Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9567d84442 | |||
| d79564db5e | |||
| a7a0e87fd8 | |||
| 7050b8de75 | |||
| 2fc3ddee16 | |||
| 284d9733dd | |||
| 94e2b5f6e0 | |||
| 03810d574e | |||
| f52e94c612 | |||
| 9444a0e208 | |||
| 2296060d04 | |||
| 458bfe18a0 | |||
| 4cfb9b5008 | |||
| 06542e382a | |||
| bcdf6ab5fb | |||
| 314f669f10 | |||
| a24275e21b | |||
| 872e620342 | |||
| 6d9c6fd2b1 | |||
| 008021df1c |
@@ -34,7 +34,7 @@ jobs:
|
|||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: "https://registry.npmjs.org"
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install --no-frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Get package version
|
- name: Get package version
|
||||||
id: version
|
id: version
|
||||||
|
|||||||
+6
-2
@@ -1,6 +1,10 @@
|
|||||||
|
# Ensure lockfile is up to date
|
||||||
|
echo "🔒 Updating lockfile..."
|
||||||
|
pnpm install --lockfile-only
|
||||||
|
|
||||||
# Build the action before committing
|
# Build the action before committing
|
||||||
echo "🔨 Building action..."
|
echo "🔨 Building action..."
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
# Add the built files to the commit
|
# Add the built files and lockfile to the commit
|
||||||
git add entry.cjs
|
git add entry.cjs pnpm-lock.yaml
|
||||||
|
|||||||
+18
-2
@@ -18,8 +18,24 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "node20"
|
using: "composite"
|
||||||
main: "entry.cjs"
|
steps:
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
- name: Setup Node.js 24
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "24"
|
||||||
|
cache: "pnpm"
|
||||||
|
cache-dependency-path: ${{ github.action_path }}/pnpm-lock.yaml
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ github.action_path }}
|
||||||
|
- name: Run agent
|
||||||
|
run: node entry.ts
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ github.action_path }}
|
||||||
|
|
||||||
branding:
|
branding:
|
||||||
icon: "code"
|
icon: "code"
|
||||||
|
|||||||
+27
-22
@@ -16,7 +16,6 @@ export class ClaudeAgent implements Agent {
|
|||||||
startTime: 0,
|
startTime: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
constructor(config: AgentConfig) {
|
constructor(config: AgentConfig) {
|
||||||
if (!config.apiKey) {
|
if (!config.apiKey) {
|
||||||
throw new Error("Claude agent requires an API key");
|
throw new Error("Claude agent requires an API key");
|
||||||
@@ -50,7 +49,10 @@ export class ClaudeAgent implements Agent {
|
|||||||
try {
|
try {
|
||||||
const result = await spawn({
|
const result = await spawn({
|
||||||
cmd: "bash",
|
cmd: "bash",
|
||||||
args: ["-c", "curl -fsSL https://claude.ai/install.sh | bash -s 1.0.93"],
|
args: [
|
||||||
|
"-c",
|
||||||
|
"curl -fsSL https://claude.ai/install.sh | bash -s 1.0.93",
|
||||||
|
],
|
||||||
env: { ANTHROPIC_API_KEY: this.apiKey },
|
env: { ANTHROPIC_API_KEY: this.apiKey },
|
||||||
timeout: 120000, // 2 minute timeout
|
timeout: 120000, // 2 minute timeout
|
||||||
onStdout: () => {},
|
onStdout: () => {},
|
||||||
@@ -58,7 +60,9 @@ export class ClaudeAgent implements Agent {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result.exitCode !== 0) {
|
if (result.exitCode !== 0) {
|
||||||
throw new Error(`Installation failed with exit code ${result.exitCode}: ${result.stderr}`);
|
throw new Error(
|
||||||
|
`Installation failed with exit code ${result.exitCode}: ${result.stderr}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info("Claude Code installed successfully");
|
core.info("Claude Code installed successfully");
|
||||||
@@ -74,7 +78,6 @@ export class ClaudeAgent implements Agent {
|
|||||||
core.info("Running Claude Code...");
|
core.info("Running Claude Code...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const claudePath = `${process.env.HOME}/.local/bin/claude`;
|
const claudePath = `${process.env.HOME}/.local/bin/claude`;
|
||||||
console.log(boxString(prompt, { title: "Prompt" }));
|
console.log(boxString(prompt, { title: "Prompt" }));
|
||||||
const args = [
|
const args = [
|
||||||
@@ -82,12 +85,15 @@ export class ClaudeAgent implements Agent {
|
|||||||
"--output-format",
|
"--output-format",
|
||||||
"stream-json",
|
"stream-json",
|
||||||
"--verbose",
|
"--verbose",
|
||||||
|
"--debug",
|
||||||
"--permission-mode",
|
"--permission-mode",
|
||||||
"bypassPermissions",
|
"bypassPermissions",
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!process.env.GITHUB_INSTALLATION_TOKEN) {
|
if (!process.env.GITHUB_INSTALLATION_TOKEN) {
|
||||||
throw new Error("GITHUB_INSTALLATION_TOKEN is required for GitHub integration");
|
throw new Error(
|
||||||
|
"GITHUB_INSTALLATION_TOKEN is required for GitHub integration"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mcpConfig = createMcpConfig(process.env.GITHUB_INSTALLATION_TOKEN);
|
const mcpConfig = createMcpConfig(process.env.GITHUB_INSTALLATION_TOKEN);
|
||||||
@@ -152,9 +158,9 @@ export class ClaudeAgent implements Agent {
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
try {
|
try {
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
} catch {
|
} catch {}
|
||||||
}
|
const errorMessage =
|
||||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
error instanceof Error ? error.message : "Unknown error";
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `Failed to execute Claude Code: ${errorMessage}`,
|
error: `Failed to execute Claude Code: ${errorMessage}`,
|
||||||
@@ -180,7 +186,12 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
|||||||
["model", parsedChunk.model],
|
["model", parsedChunk.model],
|
||||||
["cwd", parsedChunk.cwd],
|
["cwd", parsedChunk.cwd],
|
||||||
["permission_mode", parsedChunk.permissionMode],
|
["permission_mode", parsedChunk.permissionMode],
|
||||||
["tools", parsedChunk.tools?.length ? `${parsedChunk.tools.length} tools` : "none"],
|
[
|
||||||
|
"tools",
|
||||||
|
parsedChunk.tools?.length
|
||||||
|
? `${parsedChunk.tools.length} tools`
|
||||||
|
: "none",
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"mcp_servers",
|
"mcp_servers",
|
||||||
parsedChunk.mcp_servers?.length
|
parsedChunk.mcp_servers?.length
|
||||||
@@ -195,15 +206,6 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
|||||||
],
|
],
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check if MCP servers are expected but failed
|
|
||||||
if (parsedChunk.mcp_servers?.length > 0) {
|
|
||||||
const failedServers = parsedChunk.mcp_servers.filter((server: any) => server.status === "failed");
|
|
||||||
if (failedServers.length > 0) {
|
|
||||||
const failedNames = failedServers.map((server: any) => server.name).join(", ");
|
|
||||||
throw new Error(`MCP servers failed to start: ${failedNames}. This indicates a configuration or environment issue that prevents GitHub integration from working.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -216,7 +218,9 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
|||||||
for (const content of parsedChunk.message.content) {
|
for (const content of parsedChunk.message.content) {
|
||||||
if (content.type === "text") {
|
if (content.type === "text") {
|
||||||
if (content.text.trim()) {
|
if (content.text.trim()) {
|
||||||
core.info(boxString(content.text.trim(), { title: "Claude Code" }));
|
core.info(
|
||||||
|
boxString(content.text.trim(), { title: "Claude Code" })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (content.type === "tool_use") {
|
} else if (content.type === "tool_use") {
|
||||||
if (agent) {
|
if (agent) {
|
||||||
@@ -279,7 +283,6 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
|||||||
core.info(` └─ bash_command: ${input.bash_command}`);
|
core.info(` └─ bash_command: ${input.bash_command}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,10 +303,12 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
|||||||
|
|
||||||
case "result":
|
case "result":
|
||||||
if (parsedChunk.subtype === "success") {
|
if (parsedChunk.subtype === "success") {
|
||||||
|
|
||||||
core.info(
|
core.info(
|
||||||
tableString([
|
tableString([
|
||||||
["Cost", `$${parsedChunk.total_cost_usd?.toFixed(4) || "0.0000"}`],
|
[
|
||||||
|
"Cost",
|
||||||
|
`$${parsedChunk.total_cost_usd?.toFixed(4) || "0.0000"}`,
|
||||||
|
],
|
||||||
["Input Tokens", parsedChunk.usage?.input_tokens || 0],
|
["Input Tokens", parsedChunk.usage?.input_tokens || 0],
|
||||||
["Output Tokens", parsedChunk.usage?.output_tokens || 0],
|
["Output Tokens", parsedChunk.usage?.output_tokens || 0],
|
||||||
["Duration", `${parsedChunk.duration_ms}ms`],
|
["Duration", `${parsedChunk.duration_ms}ms`],
|
||||||
|
|||||||
@@ -7,10 +7,12 @@
|
|||||||
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import { type ExecutionInputs, type MainParams, main } from "./main.ts";
|
import { type ExecutionInputs, type MainParams, main } from "./main.ts";
|
||||||
|
import packageJson from "./package.json" with { type: "json" };
|
||||||
import { setupGitHubInstallationToken } from "./utils/github.ts";
|
import { setupGitHubInstallationToken } from "./utils/github.ts";
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
console.log(`🐸 Running pullfrog/action@${packageJson.version}...`);
|
||||||
const prompt = core.getInput("prompt", { required: true });
|
const prompt = core.getInput("prompt", { required: true });
|
||||||
const anthropic_api_key = core.getInput("anthropic_api_key");
|
const anthropic_api_key = core.getInput("anthropic_api_key");
|
||||||
|
|
||||||
@@ -44,7 +46,6 @@ async function run(): Promise<void> {
|
|||||||
|
|
||||||
const result = await main(params);
|
const result = await main(params);
|
||||||
|
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error(result.error || "Agent execution failed");
|
throw new Error(result.error || "Agent execution failed");
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -1,12 +1,18 @@
|
|||||||
/**
|
/**
|
||||||
* Simple MCP configuration helper for adding our minimal GitHub comment server
|
* Simple MCP configuration helper for adding our minimal GitHub comment server
|
||||||
*/
|
*/
|
||||||
const actionPath = process.env.GITHUB_ACTION_PATH || process.cwd();
|
// const actionPath = process.env.GITHUB_ACTION_PATH || process.cwd();
|
||||||
|
|
||||||
|
import { fromHere } from "@ark/fs";
|
||||||
|
|
||||||
|
const actionPath = fromHere("..");
|
||||||
|
|
||||||
export function createMcpConfig(githubInstallationToken: string) {
|
export function createMcpConfig(githubInstallationToken: string) {
|
||||||
const githubRepository = process.env.GITHUB_REPOSITORY;
|
const githubRepository = process.env.GITHUB_REPOSITORY;
|
||||||
if (!githubRepository) {
|
if (!githubRepository) {
|
||||||
throw new Error('GITHUB_REPOSITORY environment variable is required for MCP GitHub integration');
|
throw new Error(
|
||||||
|
"GITHUB_REPOSITORY environment variable is required for MCP GitHub integration"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSON.stringify(
|
return JSON.stringify(
|
||||||
@@ -18,6 +24,7 @@ export function createMcpConfig(githubInstallationToken: string) {
|
|||||||
env: {
|
env: {
|
||||||
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
|
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
|
||||||
GITHUB_REPOSITORY: githubRepository,
|
GITHUB_REPOSITORY: githubRepository,
|
||||||
|
LOG_LEVEL: "debug",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-1
@@ -89,4 +89,4 @@ async function runServer() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
runServer().catch(console.error);
|
await runServer();
|
||||||
|
|||||||
+5
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@pullfrog/action",
|
"name": "@pullfrog/action",
|
||||||
"version": "0.0.17",
|
"version": "0.0.35",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
"index.js",
|
"index.js",
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
"createLockfile": "pnpm --ignore-workspace install"
|
"createLockfile": "pnpm --ignore-workspace install"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ark/fs": "0.49.0",
|
||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^1.11.1",
|
||||||
"@modelcontextprotocol/sdk": "^1.17.5",
|
"@modelcontextprotocol/sdk": "^1.17.5",
|
||||||
"@octokit/rest": "^22.0.0",
|
"@octokit/rest": "^22.0.0",
|
||||||
@@ -34,7 +35,8 @@
|
|||||||
"arktype": "^2.1.22",
|
"arktype": "^2.1.22",
|
||||||
"dotenv": "^17.2.2",
|
"dotenv": "^17.2.2",
|
||||||
"execa": "^9.6.0",
|
"execa": "^9.6.0",
|
||||||
"table": "^6.9.0"
|
"table": "^6.9.0",
|
||||||
|
"zod": "^3.24.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.10.0",
|
"@types/node": "^20.10.0",
|
||||||
@@ -42,8 +44,7 @@
|
|||||||
"esbuild": "^0.25.9",
|
"esbuild": "^0.25.9",
|
||||||
"husky": "^9.0.0",
|
"husky": "^9.0.0",
|
||||||
"typescript": "^5.3.0",
|
"typescript": "^5.3.0",
|
||||||
"zshy": "^0.4.1",
|
"zshy": "^0.4.1"
|
||||||
"zod": "^3.24.4"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
import { existsSync, readFileSync } from "node:fs";
|
import { existsSync, readFileSync } from "node:fs";
|
||||||
import { dirname, extname, join, resolve } from "node:path";
|
import { extname, join, resolve } from "node:path";
|
||||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
import { pathToFileURL } from "node:url";
|
||||||
|
import { fromHere } from "@ark/fs";
|
||||||
import arg from "arg";
|
import arg from "arg";
|
||||||
import { config } from "dotenv";
|
import { config } from "dotenv";
|
||||||
import { main } from "./main.ts";
|
import { main } from "./main.ts";
|
||||||
|
import packageJson from "./package.json" with { type: "json" };
|
||||||
import { runAct } from "./utils/act.ts";
|
import { runAct } from "./utils/act.ts";
|
||||||
import { setupGitHubInstallationToken } from "./utils/github.ts";
|
import { setupGitHubInstallationToken } from "./utils/github.ts";
|
||||||
import { setupTestRepo } from "./utils/setup.ts";
|
import { setupTestRepo } from "./utils/setup.ts";
|
||||||
|
|
||||||
config();
|
config();
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = dirname(__filename);
|
|
||||||
|
|
||||||
export async function run(
|
export async function run(
|
||||||
prompt: string,
|
prompt: string,
|
||||||
options: { act?: boolean } = {}
|
options: { act?: boolean } = {}
|
||||||
): Promise<{ success: boolean; output?: string | undefined; error?: string | undefined }> {
|
): Promise<{ success: boolean; output?: string | undefined; error?: string | undefined }> {
|
||||||
try {
|
try {
|
||||||
|
console.log(`🐸 Running pullfrog/action@${packageJson.version}...`);
|
||||||
if (options.act) {
|
if (options.act) {
|
||||||
console.log("🐳 Running with Docker/act...");
|
console.log("🐳 Running with Docker/act...");
|
||||||
runAct(prompt);
|
runAct(prompt);
|
||||||
@@ -129,7 +129,7 @@ Examples:
|
|||||||
const ext = extname(filePath).toLowerCase();
|
const ext = extname(filePath).toLowerCase();
|
||||||
let resolvedPath: string;
|
let resolvedPath: string;
|
||||||
|
|
||||||
const fixturesPath = join(__dirname, "fixtures", filePath);
|
const fixturesPath = fromHere("fixtures", filePath);
|
||||||
if (existsSync(fixturesPath)) {
|
if (existsSync(fixturesPath)) {
|
||||||
resolvedPath = fixturesPath;
|
resolvedPath = fixturesPath;
|
||||||
} else if (existsSync(filePath)) {
|
} else if (existsSync(filePath)) {
|
||||||
|
|||||||
Generated
+11
-3
@@ -11,6 +11,9 @@ importers:
|
|||||||
'@actions/core':
|
'@actions/core':
|
||||||
specifier: ^1.11.1
|
specifier: ^1.11.1
|
||||||
version: 1.11.1
|
version: 1.11.1
|
||||||
|
'@ark/fs':
|
||||||
|
specifier: 0.49.0
|
||||||
|
version: 0.49.0
|
||||||
'@modelcontextprotocol/sdk':
|
'@modelcontextprotocol/sdk':
|
||||||
specifier: ^1.17.5
|
specifier: ^1.17.5
|
||||||
version: 1.19.1
|
version: 1.19.1
|
||||||
@@ -32,6 +35,9 @@ importers:
|
|||||||
table:
|
table:
|
||||||
specifier: ^6.9.0
|
specifier: ^6.9.0
|
||||||
version: 6.9.0
|
version: 6.9.0
|
||||||
|
zod:
|
||||||
|
specifier: ^3.24.4
|
||||||
|
version: 3.25.76
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.10.0
|
specifier: ^20.10.0
|
||||||
@@ -48,9 +54,6 @@ importers:
|
|||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.3.0
|
specifier: ^5.3.0
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
zod:
|
|
||||||
specifier: ^3.24.4
|
|
||||||
version: 3.25.76
|
|
||||||
zshy:
|
zshy:
|
||||||
specifier: ^0.4.1
|
specifier: ^0.4.1
|
||||||
version: 0.4.3(typescript@5.9.3)
|
version: 0.4.3(typescript@5.9.3)
|
||||||
@@ -69,6 +72,9 @@ packages:
|
|||||||
'@actions/io@1.1.3':
|
'@actions/io@1.1.3':
|
||||||
resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==}
|
resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==}
|
||||||
|
|
||||||
|
'@ark/fs@0.49.0':
|
||||||
|
resolution: {integrity: sha512-AEjAQS/bu1CGIRiKK/XLaQ73cSJHixfexq28wNt+kBpQ0h1RwVIVzaGsn/+5IWw6DEbR7LB+3hil5gzrzEeyZQ==}
|
||||||
|
|
||||||
'@ark/schema@0.49.0':
|
'@ark/schema@0.49.0':
|
||||||
resolution: {integrity: sha512-GphZBLpW72iS0v4YkeUtV3YIno35Gimd7+ezbPO9GwEi9kzdUrPVjvf6aXSBAfHikaFc/9pqZOpv3pOXnC71tw==}
|
resolution: {integrity: sha512-GphZBLpW72iS0v4YkeUtV3YIno35Gimd7+ezbPO9GwEi9kzdUrPVjvf6aXSBAfHikaFc/9pqZOpv3pOXnC71tw==}
|
||||||
|
|
||||||
@@ -902,6 +908,8 @@ snapshots:
|
|||||||
|
|
||||||
'@actions/io@1.1.3': {}
|
'@actions/io@1.1.3': {}
|
||||||
|
|
||||||
|
'@ark/fs@0.49.0': {}
|
||||||
|
|
||||||
'@ark/schema@0.49.0':
|
'@ark/schema@0.49.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ark/util': 0.49.0
|
'@ark/util': 0.49.0
|
||||||
|
|||||||
Reference in New Issue
Block a user