Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1abbd7ff41 |
+10
-7
@@ -1,17 +1,20 @@
|
|||||||
name: 'Simple Message Action'
|
name: 'Pullfrog Claude Code Action'
|
||||||
description: 'A simple GitHub Action that prints a message to the console'
|
description: 'Execute Claude Code with a prompt using Anthropic API'
|
||||||
author: 'Pullfrog'
|
author: 'Pullfrog'
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
message:
|
prompt:
|
||||||
description: 'Message to print to console'
|
description: 'Prompt to send to Claude Code'
|
||||||
required: true
|
required: true
|
||||||
default: 'Hello from Pullfrog Action!'
|
default: 'Hello from Claude Code!'
|
||||||
|
anthropic_api_key:
|
||||||
|
description: 'Anthropic API key for Claude Code authentication'
|
||||||
|
required: false
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node20'
|
using: 'node20'
|
||||||
main: 'index.cjs'
|
main: 'index.cjs'
|
||||||
|
|
||||||
branding:
|
branding:
|
||||||
icon: 'message-circle'
|
icon: 'code'
|
||||||
color: 'blue'
|
color: 'orange'
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
import { executeCommand } from "../utils/exec";
|
||||||
|
import { createTempFile } from "../utils/files";
|
||||||
|
import type { Agent, AgentConfig, AgentResult } from "./types";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Claude Code agent implementation
|
||||||
|
*/
|
||||||
|
export class ClaudeAgent implements Agent {
|
||||||
|
private apiKey: string;
|
||||||
|
|
||||||
|
constructor(config: AgentConfig) {
|
||||||
|
if (!config.apiKey) {
|
||||||
|
throw new Error("Claude agent requires an API key");
|
||||||
|
}
|
||||||
|
this.apiKey = config.apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install Claude Code CLI
|
||||||
|
*/
|
||||||
|
async install(): Promise<void> {
|
||||||
|
core.info("Installing Claude Code...");
|
||||||
|
try {
|
||||||
|
await executeCommand("curl -fsSL https://claude.ai/install.sh | bash -s 1.0.93");
|
||||||
|
core.info("Claude Code installed successfully");
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Failed to install Claude Code: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute Claude Code with the given prompt
|
||||||
|
*/
|
||||||
|
async execute(prompt: string): Promise<AgentResult> {
|
||||||
|
core.info("Executing Claude Code...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create a temporary file for the prompt
|
||||||
|
const promptFile = createTempFile(prompt, "prompt.txt");
|
||||||
|
|
||||||
|
// Execute Claude Code with the prompt
|
||||||
|
const command = `$HOME/.local/bin/claude --dangerously-skip-permissions "${promptFile}"`;
|
||||||
|
core.info(`Executing: ${command}`);
|
||||||
|
|
||||||
|
const { stdout, stderr } = await executeCommand(command, {
|
||||||
|
ANTHROPIC_API_KEY: this.apiKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (stderr) {
|
||||||
|
core.warning(`Claude Code stderr: ${stderr}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stdout) {
|
||||||
|
core.info("Claude Code output:");
|
||||||
|
console.log(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info("Claude Code executed successfully");
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
output: stdout,
|
||||||
|
error: stderr || undefined,
|
||||||
|
metadata: {
|
||||||
|
promptFile,
|
||||||
|
command,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `Failed to execute Claude Code: ${errorMessage}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { ClaudeAgent } from "./claude";
|
||||||
|
import type { Agent, AgentConfig } from "./types";
|
||||||
|
|
||||||
|
export type AgentType = "claude";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory for creating agent instances
|
||||||
|
*/
|
||||||
|
export function createAgent(type: AgentType, config: AgentConfig): Agent {
|
||||||
|
switch (type) {
|
||||||
|
case "claude":
|
||||||
|
return new ClaudeAgent(config);
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported agent type: ${type}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./claude";
|
||||||
|
export * from "./factory";
|
||||||
|
export * from "./types";
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Standard interface for all Pullfrog agents
|
||||||
|
*/
|
||||||
|
export interface Agent {
|
||||||
|
/**
|
||||||
|
* Install the agent and any required dependencies
|
||||||
|
*/
|
||||||
|
install(): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the agent with the given prompt
|
||||||
|
* @param prompt The prompt to send to the agent
|
||||||
|
* @param options Additional options specific to the agent
|
||||||
|
*/
|
||||||
|
execute(prompt: string, options?: Record<string, any>): Promise<AgentResult>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result returned by agent execution
|
||||||
|
*/
|
||||||
|
export interface AgentResult {
|
||||||
|
success: boolean;
|
||||||
|
output?: string;
|
||||||
|
error?: string;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for agent creation
|
||||||
|
*/
|
||||||
|
export interface AgentConfig {
|
||||||
|
apiKey?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
@@ -10746,7 +10746,7 @@ var require_mock_interceptor = __commonJS({
|
|||||||
var require_mock_client = __commonJS({
|
var require_mock_client = __commonJS({
|
||||||
"node_modules/.pnpm/undici@5.29.0/node_modules/undici/lib/mock/mock-client.js"(exports2, module2) {
|
"node_modules/.pnpm/undici@5.29.0/node_modules/undici/lib/mock/mock-client.js"(exports2, module2) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var { promisify } = require("util");
|
var { promisify: promisify2 } = require("util");
|
||||||
var Client = require_client();
|
var Client = require_client();
|
||||||
var { buildMockDispatch } = require_mock_utils();
|
var { buildMockDispatch } = require_mock_utils();
|
||||||
var {
|
var {
|
||||||
@@ -10786,7 +10786,7 @@ var require_mock_client = __commonJS({
|
|||||||
return new MockInterceptor(opts, this[kDispatches]);
|
return new MockInterceptor(opts, this[kDispatches]);
|
||||||
}
|
}
|
||||||
async [kClose]() {
|
async [kClose]() {
|
||||||
await promisify(this[kOriginalClose])();
|
await promisify2(this[kOriginalClose])();
|
||||||
this[kConnected] = 0;
|
this[kConnected] = 0;
|
||||||
this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
|
this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
|
||||||
}
|
}
|
||||||
@@ -10799,7 +10799,7 @@ var require_mock_client = __commonJS({
|
|||||||
var require_mock_pool = __commonJS({
|
var require_mock_pool = __commonJS({
|
||||||
"node_modules/.pnpm/undici@5.29.0/node_modules/undici/lib/mock/mock-pool.js"(exports2, module2) {
|
"node_modules/.pnpm/undici@5.29.0/node_modules/undici/lib/mock/mock-pool.js"(exports2, module2) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var { promisify } = require("util");
|
var { promisify: promisify2 } = require("util");
|
||||||
var Pool = require_pool();
|
var Pool = require_pool();
|
||||||
var { buildMockDispatch } = require_mock_utils();
|
var { buildMockDispatch } = require_mock_utils();
|
||||||
var {
|
var {
|
||||||
@@ -10839,7 +10839,7 @@ var require_mock_pool = __commonJS({
|
|||||||
return new MockInterceptor(opts, this[kDispatches]);
|
return new MockInterceptor(opts, this[kDispatches]);
|
||||||
}
|
}
|
||||||
async [kClose]() {
|
async [kClose]() {
|
||||||
await promisify(this[kOriginalClose])();
|
await promisify2(this[kOriginalClose])();
|
||||||
this[kConnected] = 0;
|
this[kConnected] = 0;
|
||||||
this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
|
this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
|
||||||
}
|
}
|
||||||
@@ -17581,12 +17581,12 @@ var require_lib = __commonJS({
|
|||||||
throw new Error("Client has already been disposed.");
|
throw new Error("Client has already been disposed.");
|
||||||
}
|
}
|
||||||
const parsedUrl = new URL(requestUrl);
|
const parsedUrl = new URL(requestUrl);
|
||||||
let info2 = this._prepareRequest(verb, parsedUrl, headers);
|
let info3 = this._prepareRequest(verb, parsedUrl, headers);
|
||||||
const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) ? this._maxRetries + 1 : 1;
|
const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) ? this._maxRetries + 1 : 1;
|
||||||
let numTries = 0;
|
let numTries = 0;
|
||||||
let response;
|
let response;
|
||||||
do {
|
do {
|
||||||
response = yield this.requestRaw(info2, data);
|
response = yield this.requestRaw(info3, data);
|
||||||
if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) {
|
if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) {
|
||||||
let authenticationHandler;
|
let authenticationHandler;
|
||||||
for (const handler of this.handlers) {
|
for (const handler of this.handlers) {
|
||||||
@@ -17596,7 +17596,7 @@ var require_lib = __commonJS({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (authenticationHandler) {
|
if (authenticationHandler) {
|
||||||
return authenticationHandler.handleAuthentication(this, info2, data);
|
return authenticationHandler.handleAuthentication(this, info3, data);
|
||||||
} else {
|
} else {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@@ -17619,8 +17619,8 @@ var require_lib = __commonJS({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info2 = this._prepareRequest(verb, parsedRedirectUrl, headers);
|
info3 = this._prepareRequest(verb, parsedRedirectUrl, headers);
|
||||||
response = yield this.requestRaw(info2, data);
|
response = yield this.requestRaw(info3, data);
|
||||||
redirectsRemaining--;
|
redirectsRemaining--;
|
||||||
}
|
}
|
||||||
if (!response.message.statusCode || !HttpResponseRetryCodes.includes(response.message.statusCode)) {
|
if (!response.message.statusCode || !HttpResponseRetryCodes.includes(response.message.statusCode)) {
|
||||||
@@ -17649,7 +17649,7 @@ var require_lib = __commonJS({
|
|||||||
* @param info
|
* @param info
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
requestRaw(info2, data) {
|
requestRaw(info3, data) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
function callbackForResult(err, res) {
|
function callbackForResult(err, res) {
|
||||||
@@ -17661,7 +17661,7 @@ var require_lib = __commonJS({
|
|||||||
resolve(res);
|
resolve(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.requestRawWithCallback(info2, data, callbackForResult);
|
this.requestRawWithCallback(info3, data, callbackForResult);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -17671,12 +17671,12 @@ var require_lib = __commonJS({
|
|||||||
* @param data
|
* @param data
|
||||||
* @param onResult
|
* @param onResult
|
||||||
*/
|
*/
|
||||||
requestRawWithCallback(info2, data, onResult) {
|
requestRawWithCallback(info3, data, onResult) {
|
||||||
if (typeof data === "string") {
|
if (typeof data === "string") {
|
||||||
if (!info2.options.headers) {
|
if (!info3.options.headers) {
|
||||||
info2.options.headers = {};
|
info3.options.headers = {};
|
||||||
}
|
}
|
||||||
info2.options.headers["Content-Length"] = Buffer.byteLength(data, "utf8");
|
info3.options.headers["Content-Length"] = Buffer.byteLength(data, "utf8");
|
||||||
}
|
}
|
||||||
let callbackCalled = false;
|
let callbackCalled = false;
|
||||||
function handleResult(err, res) {
|
function handleResult(err, res) {
|
||||||
@@ -17685,7 +17685,7 @@ var require_lib = __commonJS({
|
|||||||
onResult(err, res);
|
onResult(err, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const req = info2.httpModule.request(info2.options, (msg) => {
|
const req = info3.httpModule.request(info3.options, (msg) => {
|
||||||
const res = new HttpClientResponse(msg);
|
const res = new HttpClientResponse(msg);
|
||||||
handleResult(void 0, res);
|
handleResult(void 0, res);
|
||||||
});
|
});
|
||||||
@@ -17697,7 +17697,7 @@ var require_lib = __commonJS({
|
|||||||
if (socket) {
|
if (socket) {
|
||||||
socket.end();
|
socket.end();
|
||||||
}
|
}
|
||||||
handleResult(new Error(`Request timeout: ${info2.options.path}`));
|
handleResult(new Error(`Request timeout: ${info3.options.path}`));
|
||||||
});
|
});
|
||||||
req.on("error", function(err) {
|
req.on("error", function(err) {
|
||||||
handleResult(err);
|
handleResult(err);
|
||||||
@@ -17733,27 +17733,27 @@ var require_lib = __commonJS({
|
|||||||
return this._getProxyAgentDispatcher(parsedUrl, proxyUrl);
|
return this._getProxyAgentDispatcher(parsedUrl, proxyUrl);
|
||||||
}
|
}
|
||||||
_prepareRequest(method, requestUrl, headers) {
|
_prepareRequest(method, requestUrl, headers) {
|
||||||
const info2 = {};
|
const info3 = {};
|
||||||
info2.parsedUrl = requestUrl;
|
info3.parsedUrl = requestUrl;
|
||||||
const usingSsl = info2.parsedUrl.protocol === "https:";
|
const usingSsl = info3.parsedUrl.protocol === "https:";
|
||||||
info2.httpModule = usingSsl ? https : http;
|
info3.httpModule = usingSsl ? https : http;
|
||||||
const defaultPort = usingSsl ? 443 : 80;
|
const defaultPort = usingSsl ? 443 : 80;
|
||||||
info2.options = {};
|
info3.options = {};
|
||||||
info2.options.host = info2.parsedUrl.hostname;
|
info3.options.host = info3.parsedUrl.hostname;
|
||||||
info2.options.port = info2.parsedUrl.port ? parseInt(info2.parsedUrl.port) : defaultPort;
|
info3.options.port = info3.parsedUrl.port ? parseInt(info3.parsedUrl.port) : defaultPort;
|
||||||
info2.options.path = (info2.parsedUrl.pathname || "") + (info2.parsedUrl.search || "");
|
info3.options.path = (info3.parsedUrl.pathname || "") + (info3.parsedUrl.search || "");
|
||||||
info2.options.method = method;
|
info3.options.method = method;
|
||||||
info2.options.headers = this._mergeHeaders(headers);
|
info3.options.headers = this._mergeHeaders(headers);
|
||||||
if (this.userAgent != null) {
|
if (this.userAgent != null) {
|
||||||
info2.options.headers["user-agent"] = this.userAgent;
|
info3.options.headers["user-agent"] = this.userAgent;
|
||||||
}
|
}
|
||||||
info2.options.agent = this._getAgent(info2.parsedUrl);
|
info3.options.agent = this._getAgent(info3.parsedUrl);
|
||||||
if (this.handlers) {
|
if (this.handlers) {
|
||||||
for (const handler of this.handlers) {
|
for (const handler of this.handlers) {
|
||||||
handler.prepareRequest(info2.options);
|
handler.prepareRequest(info3.options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return info2;
|
return info3;
|
||||||
}
|
}
|
||||||
_mergeHeaders(headers) {
|
_mergeHeaders(headers) {
|
||||||
if (this.requestOptions && this.requestOptions.headers) {
|
if (this.requestOptions && this.requestOptions.headers) {
|
||||||
@@ -19411,7 +19411,7 @@ var require_exec = __commonJS({
|
|||||||
exports2.getExecOutput = exports2.exec = void 0;
|
exports2.getExecOutput = exports2.exec = void 0;
|
||||||
var string_decoder_1 = require("string_decoder");
|
var string_decoder_1 = require("string_decoder");
|
||||||
var tr = __importStar(require_toolrunner());
|
var tr = __importStar(require_toolrunner());
|
||||||
function exec(commandLine, args, options) {
|
function exec2(commandLine, args, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const commandArgs = tr.argStringToArray(commandLine);
|
const commandArgs = tr.argStringToArray(commandLine);
|
||||||
if (commandArgs.length === 0) {
|
if (commandArgs.length === 0) {
|
||||||
@@ -19423,7 +19423,7 @@ var require_exec = __commonJS({
|
|||||||
return runner.exec();
|
return runner.exec();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports2.exec = exec;
|
exports2.exec = exec2;
|
||||||
function getExecOutput(commandLine, args, options) {
|
function getExecOutput(commandLine, args, options) {
|
||||||
var _a, _b;
|
var _a, _b;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@@ -19446,7 +19446,7 @@ var require_exec = __commonJS({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const listeners = Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.listeners), { stdout: stdOutListener, stderr: stdErrListener });
|
const listeners = Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.listeners), { stdout: stdOutListener, stderr: stdErrListener });
|
||||||
const exitCode = yield exec(commandLine, args, Object.assign(Object.assign({}, options), { listeners }));
|
const exitCode = yield exec2(commandLine, args, Object.assign(Object.assign({}, options), { listeners }));
|
||||||
stdout += stdoutDecoder.end();
|
stdout += stdoutDecoder.end();
|
||||||
stderr += stderrDecoder.end();
|
stderr += stderrDecoder.end();
|
||||||
return {
|
return {
|
||||||
@@ -19524,12 +19524,12 @@ var require_platform = __commonJS({
|
|||||||
Object.defineProperty(exports2, "__esModule", { value: true });
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
||||||
exports2.getDetails = exports2.isLinux = exports2.isMacOS = exports2.isWindows = exports2.arch = exports2.platform = void 0;
|
exports2.getDetails = exports2.isLinux = exports2.isMacOS = exports2.isWindows = exports2.arch = exports2.platform = void 0;
|
||||||
var os_1 = __importDefault(require("os"));
|
var os_1 = __importDefault(require("os"));
|
||||||
var exec = __importStar(require_exec());
|
var exec2 = __importStar(require_exec());
|
||||||
var getWindowsInfo = () => __awaiter(void 0, void 0, void 0, function* () {
|
var getWindowsInfo = () => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const { stdout: version } = yield exec.getExecOutput('powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Version"', void 0, {
|
const { stdout: version } = yield exec2.getExecOutput('powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Version"', void 0, {
|
||||||
silent: true
|
silent: true
|
||||||
});
|
});
|
||||||
const { stdout: name } = yield exec.getExecOutput('powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Caption"', void 0, {
|
const { stdout: name } = yield exec2.getExecOutput('powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Caption"', void 0, {
|
||||||
silent: true
|
silent: true
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
@@ -19539,7 +19539,7 @@ var require_platform = __commonJS({
|
|||||||
});
|
});
|
||||||
var getMacOsInfo = () => __awaiter(void 0, void 0, void 0, function* () {
|
var getMacOsInfo = () => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
var _a, _b, _c, _d;
|
var _a, _b, _c, _d;
|
||||||
const { stdout } = yield exec.getExecOutput("sw_vers", void 0, {
|
const { stdout } = yield exec2.getExecOutput("sw_vers", void 0, {
|
||||||
silent: true
|
silent: true
|
||||||
});
|
});
|
||||||
const version = (_b = (_a = stdout.match(/ProductVersion:\s*(.+)/)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : "";
|
const version = (_b = (_a = stdout.match(/ProductVersion:\s*(.+)/)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : "";
|
||||||
@@ -19550,7 +19550,7 @@ var require_platform = __commonJS({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
var getLinuxInfo = () => __awaiter(void 0, void 0, void 0, function* () {
|
var getLinuxInfo = () => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const { stdout } = yield exec.getExecOutput("lsb_release", ["-i", "-r", "-s"], {
|
const { stdout } = yield exec2.getExecOutput("lsb_release", ["-i", "-r", "-s"], {
|
||||||
silent: true
|
silent: true
|
||||||
});
|
});
|
||||||
const [name, version] = stdout.trim().split("\n");
|
const [name, version] = stdout.trim().split("\n");
|
||||||
@@ -19735,18 +19735,18 @@ Support boolean input list: \`true | True | TRUE | false | False | FALSE\``);
|
|||||||
(0, command_1.issueCommand)("error", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message);
|
(0, command_1.issueCommand)("error", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message);
|
||||||
}
|
}
|
||||||
exports2.error = error;
|
exports2.error = error;
|
||||||
function warning(message, properties = {}) {
|
function warning2(message, properties = {}) {
|
||||||
(0, command_1.issueCommand)("warning", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message);
|
(0, command_1.issueCommand)("warning", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message);
|
||||||
}
|
}
|
||||||
exports2.warning = warning;
|
exports2.warning = warning2;
|
||||||
function notice(message, properties = {}) {
|
function notice(message, properties = {}) {
|
||||||
(0, command_1.issueCommand)("notice", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message);
|
(0, command_1.issueCommand)("notice", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message);
|
||||||
}
|
}
|
||||||
exports2.notice = notice;
|
exports2.notice = notice;
|
||||||
function info2(message) {
|
function info3(message) {
|
||||||
process.stdout.write(message + os.EOL);
|
process.stdout.write(message + os.EOL);
|
||||||
}
|
}
|
||||||
exports2.info = info2;
|
exports2.info = info3;
|
||||||
function startGroup(name) {
|
function startGroup(name) {
|
||||||
(0, command_1.issue)("group", name);
|
(0, command_1.issue)("group", name);
|
||||||
}
|
}
|
||||||
@@ -19809,16 +19809,125 @@ Support boolean input list: \`true | True | TRUE | false | False | FALSE\``);
|
|||||||
});
|
});
|
||||||
|
|
||||||
// index.ts
|
// index.ts
|
||||||
|
var core2 = __toESM(require_core(), 1);
|
||||||
|
|
||||||
|
// agents/claude.ts
|
||||||
var core = __toESM(require_core(), 1);
|
var core = __toESM(require_core(), 1);
|
||||||
try {
|
|
||||||
const message = core.getInput("message") || "Hello from Pullfrog Action!";
|
// utils/exec.ts
|
||||||
console.log(`\u{1F438} Pullfrog says: ${message}`);
|
var import_node_child_process = require("node:child_process");
|
||||||
core.info(`Action executed successfully with message: ${message}`);
|
var import_node_util = require("node:util");
|
||||||
core.setOutput("message", message);
|
var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
|
||||||
} catch (error) {
|
async function executeCommand(command, env) {
|
||||||
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
const execEnv = env ? { ...process.env, ...env } : process.env;
|
||||||
core.setFailed(`Action failed: ${errorMessage}`);
|
return execAsync(command, { env: execEnv });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// utils/files.ts
|
||||||
|
var import_node_fs = require("node:fs");
|
||||||
|
var import_node_os = require("node:os");
|
||||||
|
var import_node_path = require("node:path");
|
||||||
|
function createTempFile(content, filename = "temp.txt") {
|
||||||
|
const tempDir = (0, import_node_fs.mkdtempSync)((0, import_node_path.join)((0, import_node_os.tmpdir)(), "pullfrog-"));
|
||||||
|
const filePath = (0, import_node_path.join)(tempDir, filename);
|
||||||
|
(0, import_node_fs.writeFileSync)(filePath, content);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// agents/claude.ts
|
||||||
|
var ClaudeAgent = class {
|
||||||
|
constructor(config) {
|
||||||
|
if (!config.apiKey) {
|
||||||
|
throw new Error("Claude agent requires an API key");
|
||||||
|
}
|
||||||
|
this.apiKey = config.apiKey;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Install Claude Code CLI
|
||||||
|
*/
|
||||||
|
async install() {
|
||||||
|
core.info("Installing Claude Code...");
|
||||||
|
try {
|
||||||
|
await executeCommand("curl -fsSL https://claude.ai/install.sh | bash -s 1.0.93");
|
||||||
|
core.info("Claude Code installed successfully");
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Failed to install Claude Code: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Execute Claude Code with the given prompt
|
||||||
|
*/
|
||||||
|
async execute(prompt) {
|
||||||
|
core.info("Executing Claude Code...");
|
||||||
|
try {
|
||||||
|
const promptFile = createTempFile(prompt, "prompt.txt");
|
||||||
|
const command = `$HOME/.local/bin/claude --dangerously-skip-permissions "${promptFile}"`;
|
||||||
|
core.info(`Executing: ${command}`);
|
||||||
|
const { stdout, stderr } = await executeCommand(command, {
|
||||||
|
ANTHROPIC_API_KEY: this.apiKey
|
||||||
|
});
|
||||||
|
if (stderr) {
|
||||||
|
core.warning(`Claude Code stderr: ${stderr}`);
|
||||||
|
}
|
||||||
|
if (stdout) {
|
||||||
|
core.info("Claude Code output:");
|
||||||
|
console.log(stdout);
|
||||||
|
}
|
||||||
|
core.info("Claude Code executed successfully");
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
output: stdout,
|
||||||
|
error: stderr || void 0,
|
||||||
|
metadata: {
|
||||||
|
promptFile,
|
||||||
|
command
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `Failed to execute Claude Code: ${errorMessage}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// agents/factory.ts
|
||||||
|
function createAgent(type, config) {
|
||||||
|
switch (type) {
|
||||||
|
case "claude":
|
||||||
|
return new ClaudeAgent(config);
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported agent type: ${type}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// index.ts
|
||||||
|
async function main() {
|
||||||
|
try {
|
||||||
|
const prompt = core2.getInput("prompt", { required: true });
|
||||||
|
const anthropicApiKey = core2.getInput("anthropic_api_key", { required: true });
|
||||||
|
if (!anthropicApiKey) {
|
||||||
|
throw new Error("anthropic_api_key is required");
|
||||||
|
}
|
||||||
|
core2.info(`\u{1F438} Pullfrog Claude Code Action starting...`);
|
||||||
|
core2.info(`Prompt: ${prompt}`);
|
||||||
|
const agent = createAgent("claude", { apiKey: anthropicApiKey });
|
||||||
|
await agent.install();
|
||||||
|
const result = await agent.execute(prompt);
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.error || "Agent execution failed");
|
||||||
|
}
|
||||||
|
core2.setOutput("status", "success");
|
||||||
|
core2.setOutput("prompt", prompt);
|
||||||
|
core2.setOutput("output", result.output || "");
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
||||||
|
core2.setFailed(`Action failed: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
main();
|
||||||
/*! Bundled license information:
|
/*! Bundled license information:
|
||||||
|
|
||||||
undici/lib/fetch/body.js:
|
undici/lib/fetch/body.js:
|
||||||
|
|||||||
@@ -1,17 +1,39 @@
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
import { createAgent } from "./agents/factory";
|
||||||
|
|
||||||
try {
|
async function main(): Promise<void> {
|
||||||
// Get the message input parameter, with a default fallback
|
try {
|
||||||
const message = core.getInput("message") || "Hello from Pullfrog Action!";
|
// Get inputs
|
||||||
|
const prompt = core.getInput("prompt", { required: true });
|
||||||
|
const anthropicApiKey = core.getInput("anthropic_api_key", { required: true });
|
||||||
|
|
||||||
// Print the message to console and GitHub Actions logs
|
if (!anthropicApiKey) {
|
||||||
console.log(`🐸 Pullfrog says: ${message}`);
|
throw new Error("anthropic_api_key is required");
|
||||||
core.info(`Action executed successfully with message: ${message}`);
|
}
|
||||||
|
|
||||||
// Set an output for potential use by other actions
|
core.info(`🐸 Pullfrog Claude Code Action starting...`);
|
||||||
core.setOutput("message", message);
|
core.info(`Prompt: ${prompt}`);
|
||||||
} catch (error) {
|
|
||||||
// Handle any errors and fail the action
|
// Create and install the Claude agent
|
||||||
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
const agent = createAgent("claude", { apiKey: anthropicApiKey });
|
||||||
core.setFailed(`Action failed: ${errorMessage}`);
|
await agent.install();
|
||||||
|
|
||||||
|
// Execute the agent with the prompt
|
||||||
|
const result = await agent.execute(prompt);
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.error || "Agent execution failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set outputs
|
||||||
|
core.setOutput("status", "success");
|
||||||
|
core.setOutput("prompt", prompt);
|
||||||
|
core.setOutput("output", result.output || "");
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
||||||
|
core.setFailed(`Action failed: ${errorMessage}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute main function
|
||||||
|
main();
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "action",
|
"name": "action",
|
||||||
"version": "0.0.4",
|
"version": "0.0.5",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
"example": "examples"
|
"example": "examples"
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { exec } from "node:child_process";
|
||||||
|
import { promisify } from "node:util";
|
||||||
|
|
||||||
|
export const execAsync = promisify(exec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a shell command with optional environment variables
|
||||||
|
*/
|
||||||
|
export async function executeCommand(
|
||||||
|
command: string,
|
||||||
|
env?: Record<string, string>
|
||||||
|
): Promise<{ stdout: string; stderr: string }> {
|
||||||
|
const execEnv = env ? { ...process.env, ...env } : process.env;
|
||||||
|
return execAsync(command, { env: execEnv });
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { mkdtempSync, writeFileSync } from "node:fs";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { join } from "node:path";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a temporary file with the given content
|
||||||
|
*/
|
||||||
|
export function createTempFile(content: string, filename = "temp.txt"): string {
|
||||||
|
const tempDir = mkdtempSync(join(tmpdir(), "pullfrog-"));
|
||||||
|
const filePath = join(tempDir, filename);
|
||||||
|
writeFileSync(filePath, content);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user