Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2296060d04 | |||
| 458bfe18a0 | |||
| 4cfb9b5008 | |||
| 06542e382a | |||
| bcdf6ab5fb | |||
| 314f669f10 | |||
| a24275e21b | |||
| 872e620342 |
+26
-31
@@ -1,4 +1,3 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { access, constants } from "node:fs/promises";
|
||||
import * as core from "@actions/core";
|
||||
import { createMcpConfig } from "../mcp/config.ts";
|
||||
@@ -50,7 +49,10 @@ export class ClaudeAgent implements Agent {
|
||||
try {
|
||||
const result = await spawn({
|
||||
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 },
|
||||
timeout: 120000, // 2 minute timeout
|
||||
onStdout: () => {},
|
||||
@@ -58,7 +60,9 @@ export class ClaudeAgent implements Agent {
|
||||
});
|
||||
|
||||
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");
|
||||
@@ -81,12 +85,15 @@ export class ClaudeAgent implements Agent {
|
||||
"--output-format",
|
||||
"stream-json",
|
||||
"--verbose",
|
||||
"--debug",
|
||||
"--permission-mode",
|
||||
"bypassPermissions",
|
||||
];
|
||||
|
||||
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);
|
||||
@@ -152,7 +159,8 @@ export class ClaudeAgent implements Agent {
|
||||
try {
|
||||
core.endGroup();
|
||||
} catch {}
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : "Unknown error";
|
||||
return {
|
||||
success: false,
|
||||
error: `Failed to execute Claude Code: ${errorMessage}`,
|
||||
@@ -178,7 +186,12 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
||||
["model", parsedChunk.model],
|
||||
["cwd", parsedChunk.cwd],
|
||||
["permission_mode", parsedChunk.permissionMode],
|
||||
["tools", parsedChunk.tools?.length ? `${parsedChunk.tools.length} tools` : "none"],
|
||||
[
|
||||
"tools",
|
||||
parsedChunk.tools?.length
|
||||
? `${parsedChunk.tools.length} tools`
|
||||
: "none",
|
||||
],
|
||||
[
|
||||
"mcp_servers",
|
||||
parsedChunk.mcp_servers?.length
|
||||
@@ -193,29 +206,6 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
||||
],
|
||||
])
|
||||
);
|
||||
|
||||
// Check for failed MCP servers and show debug logs
|
||||
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(", ");
|
||||
|
||||
// Try to read MCP server debug logs
|
||||
let debugInfo = "";
|
||||
try {
|
||||
const logContent = readFileSync("/tmp/mcp-server.log", "utf-8");
|
||||
core.error("MCP Server Debug Log:");
|
||||
core.error(logContent);
|
||||
debugInfo = " (see debug log above)";
|
||||
} catch (logError) {
|
||||
debugInfo = ` (could not read debug log: ${logError instanceof Error ? logError.message : String(logError)})`;
|
||||
}
|
||||
|
||||
throw new Error(`MCP servers failed to start: ${failedNames}${debugInfo}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -228,7 +218,9 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
||||
for (const content of parsedChunk.message.content) {
|
||||
if (content.type === "text") {
|
||||
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") {
|
||||
if (agent) {
|
||||
@@ -313,7 +305,10 @@ function processJSONChunk(chunk: string, agent?: ClaudeAgent): void {
|
||||
if (parsedChunk.subtype === "success") {
|
||||
core.info(
|
||||
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],
|
||||
["Output Tokens", parsedChunk.usage?.output_tokens || 0],
|
||||
["Duration", `${parsedChunk.duration_ms}ms`],
|
||||
|
||||
@@ -25500,7 +25500,6 @@ var core4 = __toESM(require_core(), 1);
|
||||
var core2 = __toESM(require_core(), 1);
|
||||
|
||||
// agents/claude.ts
|
||||
var import_node_fs = require("node:fs");
|
||||
var import_promises = require("node:fs/promises");
|
||||
var core = __toESM(require_core(), 1);
|
||||
|
||||
@@ -25509,17 +25508,20 @@ var actionPath = process.env.GITHUB_ACTION_PATH || process.cwd();
|
||||
function createMcpConfig(githubInstallationToken) {
|
||||
const githubRepository = process.env.GITHUB_REPOSITORY;
|
||||
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(
|
||||
{
|
||||
mcpServers: {
|
||||
minimal_github_comment: {
|
||||
command: `${actionPath}/mcp/debug-server.sh`,
|
||||
command: "node",
|
||||
args: [`${actionPath}/mcp/server.ts`],
|
||||
env: {
|
||||
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
|
||||
GITHUB_REPOSITORY: githubRepository
|
||||
GITHUB_REPOSITORY: githubRepository,
|
||||
LOG_LEVEL: "debug"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25732,7 +25734,10 @@ var ClaudeAgent = class {
|
||||
try {
|
||||
const result = await spawn({
|
||||
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 },
|
||||
timeout: 12e4,
|
||||
// 2 minute timeout
|
||||
@@ -25741,7 +25746,9 @@ var ClaudeAgent = class {
|
||||
onStderr: (chunk) => process.stderr.write(chunk)
|
||||
});
|
||||
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");
|
||||
} catch (error2) {
|
||||
@@ -25761,11 +25768,14 @@ var ClaudeAgent = class {
|
||||
"--output-format",
|
||||
"stream-json",
|
||||
"--verbose",
|
||||
"--debug",
|
||||
"--permission-mode",
|
||||
"bypassPermissions"
|
||||
];
|
||||
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);
|
||||
console.log("\u{1F4CB} MCP Config:", mcpConfig);
|
||||
@@ -25848,7 +25858,10 @@ function processJSONChunk(chunk, agent) {
|
||||
["model", parsedChunk.model],
|
||||
["cwd", parsedChunk.cwd],
|
||||
["permission_mode", parsedChunk.permissionMode],
|
||||
["tools", parsedChunk.tools?.length ? `${parsedChunk.tools.length} tools` : "none"],
|
||||
[
|
||||
"tools",
|
||||
parsedChunk.tools?.length ? `${parsedChunk.tools.length} tools` : "none"
|
||||
],
|
||||
[
|
||||
"mcp_servers",
|
||||
parsedChunk.mcp_servers?.length ? `${parsedChunk.mcp_servers.length} servers` : "none"
|
||||
@@ -25859,24 +25872,6 @@ function processJSONChunk(chunk, agent) {
|
||||
]
|
||||
])
|
||||
);
|
||||
if (parsedChunk.mcp_servers?.length > 0) {
|
||||
const failedServers = parsedChunk.mcp_servers.filter(
|
||||
(server) => server.status === "failed"
|
||||
);
|
||||
if (failedServers.length > 0) {
|
||||
const failedNames = failedServers.map((server) => server.name).join(", ");
|
||||
let debugInfo = "";
|
||||
try {
|
||||
const logContent = (0, import_node_fs.readFileSync)("/tmp/mcp-server.log", "utf-8");
|
||||
core.error("MCP Server Debug Log:");
|
||||
core.error(logContent);
|
||||
debugInfo = " (see debug log above)";
|
||||
} catch (logError) {
|
||||
debugInfo = ` (could not read debug log: ${logError instanceof Error ? logError.message : String(logError)})`;
|
||||
}
|
||||
throw new Error(`MCP servers failed to start: ${failedNames}${debugInfo}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "assistant":
|
||||
@@ -25887,7 +25882,9 @@ function processJSONChunk(chunk, agent) {
|
||||
for (const content of parsedChunk.message.content) {
|
||||
if (content.type === "text") {
|
||||
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") {
|
||||
if (agent) {
|
||||
@@ -25954,7 +25951,10 @@ function processJSONChunk(chunk, agent) {
|
||||
if (parsedChunk.subtype === "success") {
|
||||
core.info(
|
||||
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],
|
||||
["Output Tokens", parsedChunk.usage?.output_tokens || 0],
|
||||
["Duration", `${parsedChunk.duration_ms}ms`],
|
||||
|
||||
+12
-2
@@ -3,21 +3,31 @@
|
||||
*/
|
||||
const actionPath = process.env.GITHUB_ACTION_PATH || process.cwd();
|
||||
|
||||
// import { dirname } from "node:path";
|
||||
// import { fileURLToPath } from "node:url";
|
||||
|
||||
// const __filename = fileURLToPath(import.meta.url);
|
||||
// const __dirname = dirname(__filename);
|
||||
// const actionPath = dirname(__dirname);
|
||||
|
||||
export function createMcpConfig(githubInstallationToken: string) {
|
||||
const githubRepository = process.env.GITHUB_REPOSITORY;
|
||||
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(
|
||||
{
|
||||
mcpServers: {
|
||||
minimal_github_comment: {
|
||||
command: `${actionPath}/mcp/debug-server.sh`,
|
||||
command: "node",
|
||||
args: [`${actionPath}/mcp/server.ts`],
|
||||
env: {
|
||||
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
|
||||
GITHUB_REPOSITORY: githubRepository,
|
||||
LOG_LEVEL: "debug",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Wrapper script to capture MCP server logs for debugging
|
||||
LOG_FILE="/tmp/mcp-server.log"
|
||||
|
||||
echo "=== MCP Server Debug Wrapper Starting ===" >> "$LOG_FILE"
|
||||
echo "Timestamp: $(date)" >> "$LOG_FILE"
|
||||
echo "Working directory: $(pwd)" >> "$LOG_FILE"
|
||||
echo "Environment variables:" >> "$LOG_FILE"
|
||||
env | grep -E "(GITHUB_|MCP_|NODE_)" >> "$LOG_FILE"
|
||||
echo "Node.js version: $(node --version)" >> "$LOG_FILE"
|
||||
echo "Arguments: $@" >> "$LOG_FILE"
|
||||
echo "=== Starting MCP Server ===" >> "$LOG_FILE"
|
||||
|
||||
# Execute the actual MCP server, capturing both stdout and stderr
|
||||
exec node "$@" 2>&1 | tee -a "$LOG_FILE"
|
||||
+6
-3
@@ -31,7 +31,9 @@ server.tool(
|
||||
|
||||
const githubInstallationToken = process.env.GITHUB_INSTALLATION_TOKEN;
|
||||
if (!githubInstallationToken) {
|
||||
throw new Error("GITHUB_INSTALLATION_TOKEN environment variable is required");
|
||||
throw new Error(
|
||||
"GITHUB_INSTALLATION_TOKEN environment variable is required"
|
||||
);
|
||||
}
|
||||
|
||||
// Resolve repository context from environment
|
||||
@@ -66,7 +68,8 @@ server.tool(
|
||||
],
|
||||
};
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
@@ -89,4 +92,4 @@ async function runServer() {
|
||||
});
|
||||
}
|
||||
|
||||
runServer().catch(console.error);
|
||||
await runServer();
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@pullfrog/action",
|
||||
"version": "0.0.19",
|
||||
"version": "0.0.25",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"index.js",
|
||||
|
||||
Reference in New Issue
Block a user