Compare commits

...

5 Commits

Author SHA1 Message Date
David Blass 94e2b5f6e0 add terrible debugging 2025-10-13 14:19:47 -04:00
David Blass 03810d574e bump version 2025-10-13 14:14:52 -04:00
David Blass f52e94c612 27 2025-10-13 14:08:54 -04:00
David Blass 9444a0e208 iter 2025-10-13 14:04:46 -04:00
David Blass 2296060d04 await top-level runServer 2025-10-13 13:44:29 -04:00
9 changed files with 1132 additions and 833 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
registry-url: "https://registry.npmjs.org"
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Get package version
id: version
+6 -2
View File
@@ -1,6 +1,10 @@
# Ensure lockfile is up to date
echo "🔒 Updating lockfile..."
pnpm install --lockfile-only
# Build the action before committing
echo "🔨 Building action..."
npm run build
# Add the built files to the commit
git add entry.cjs
# Add the built files and lockfile to the commit
git add entry.cjs pnpm-lock.yaml
+965 -736
View File
File diff suppressed because one or more lines are too long
+2 -1
View File
@@ -7,10 +7,12 @@
import * as core from "@actions/core";
import { type ExecutionInputs, type MainParams, main } from "./main.ts";
import packageJson from "./package.json" with { type: "json" };
import { setupGitHubInstallationToken } from "./utils/github.ts";
async function run(): Promise<void> {
try {
console.log(`🐸 Running pullfrog/action@${packageJson.version}...`);
const prompt = core.getInput("prompt", { required: true });
const anthropic_api_key = core.getInput("anthropic_api_key");
@@ -44,7 +46,6 @@ async function run(): Promise<void> {
const result = await main(params);
if (!result.success) {
throw new Error(result.error || "Agent execution failed");
}
+5 -2
View File
@@ -1,7 +1,11 @@
/**
* 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) {
const githubRepository = process.env.GITHUB_REPOSITORY;
@@ -20,7 +24,6 @@ export function createMcpConfig(githubInstallationToken: string) {
env: {
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
GITHUB_REPOSITORY: githubRepository,
LOG_LEVEL: "debug",
},
},
},
+131 -78
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env node
import { writeFileSync } from "node:fs";
// Minimal GitHub Issue Comment MCP Server
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -6,12 +7,35 @@ import { Octokit } from "@octokit/rest";
import { type } from "arktype";
import { z } from "zod";
import { resolveRepoContext } from "../utils/repo-context.ts";
import { writeFileSync } from "fs";
const server = new McpServer({
name: "Minimal GitHub Issue Comment Server",
version: "0.0.1",
});
// Simple error logging to file
function logError(message: string, error?: any) {
const timestamp = new Date().toISOString();
const errorText = error ? `\nError: ${error.message}\nStack: ${error.stack}` : "";
const logEntry = `[${timestamp}] ${message}${errorText}\n`;
try {
writeFileSync("/tmp/mcp-error.log", logEntry, { flag: "a" });
console.error(logEntry);
} catch (writeError) {
console.error(`Failed to write error log: ${writeError}`);
console.error(logEntry);
}
}
let server: McpServer;
try {
logError("Creating MCP server...");
server = new McpServer({
name: "Minimal GitHub Issue Comment Server",
version: "0.0.1",
});
logError("MCP server created successfully");
} catch (error) {
logError("Failed to create MCP server", error);
process.exit(1);
}
// Define the schema for creating issue comments
const Comment = type({
@@ -19,85 +43,114 @@ const Comment = type({
body: type.string.describe("the comment body content"),
});
server.tool(
"create_issue_comment",
"Create a comment on a GitHub issue",
{
issueNumber: z.number().describe("the issue number to comment on"),
body: z.string().describe("the comment body content"),
},
async ({ issueNumber, body }) => {
try {
Comment.assert({ issueNumber, body });
try {
logError("Registering create_issue_comment tool...");
const githubInstallationToken = process.env.GITHUB_INSTALLATION_TOKEN;
if (!githubInstallationToken) {
throw new Error(
"GITHUB_INSTALLATION_TOKEN environment variable is required"
);
server.tool(
"create_issue_comment",
"Create a comment on a GitHub issue",
{
issueNumber: z.number().describe("the issue number to comment on"),
body: z.string().describe("the comment body content"),
},
async ({ issueNumber, body }) => {
try {
Comment.assert({ issueNumber, body });
const githubInstallationToken = process.env.GITHUB_INSTALLATION_TOKEN;
if (!githubInstallationToken) {
throw new Error("GITHUB_INSTALLATION_TOKEN environment variable is required");
}
// Resolve repository context from environment
const repoContext = resolveRepoContext();
const octokit = new Octokit({
auth: githubInstallationToken,
});
const result = await octokit.rest.issues.createComment({
owner: repoContext.owner,
repo: repoContext.name,
issue_number: issueNumber,
body: body,
});
return {
content: [
{
type: "text",
text: JSON.stringify(
{
success: true,
commentId: result.data.id,
url: result.data.html_url,
body: result.data.body,
},
null,
2
),
},
],
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logError("Tool execution failed", error);
return {
content: [
{
type: "text",
text: `Error creating comment: ${errorMessage}`,
},
],
error: errorMessage,
isError: true,
};
}
// Resolve repository context from environment
const repoContext = resolveRepoContext();
const octokit = new Octokit({
auth: githubInstallationToken,
});
const result = await octokit.rest.issues.createComment({
owner: repoContext.owner,
repo: repoContext.name,
issue_number: issueNumber,
body: body,
});
return {
content: [
{
type: "text",
text: JSON.stringify(
{
success: true,
commentId: result.data.id,
url: result.data.html_url,
body: result.data.body,
},
null,
2
),
},
],
};
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : String(error);
return {
content: [
{
type: "text",
text: `Error creating comment: ${errorMessage}`,
},
],
error: errorMessage,
isError: true,
};
}
}
);
);
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
process.on("exit", () => {
server.close();
});
logError("Tool registered successfully");
} catch (error) {
logError("Failed to register tool", error);
process.exit(1);
}
runServer().catch((error) => {
// Write error to file for GitHub Actions visibility
async function runServer() {
try {
writeFileSync('/tmp/mcp-error.log', `${new Date().toISOString()} MCP Server Error: ${error.message}\nStack: ${error.stack}\n`, { flag: 'a' });
} catch {}
console.error('MCP Server Error:', error);
logError("Starting MCP server...");
const transport = new StdioServerTransport();
logError("Transport created, attempting connection...");
await server.connect(transport);
logError("MCP server connected successfully");
process.on("exit", () => {
logError("Process exiting, closing server...");
server.close();
});
process.on("SIGTERM", () => {
logError("SIGTERM received, closing server...");
server.close();
process.exit(0);
});
process.on("SIGINT", () => {
logError("SIGINT received, closing server...");
server.close();
process.exit(0);
});
} catch (error) {
logError("Server startup failed", error);
process.exit(1);
}
}
logError("Initializing MCP server process...");
runServer().catch((error) => {
logError("Unhandled server error", error);
process.exit(1);
});
+5 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@pullfrog/action",
"version": "0.0.24",
"version": "0.0.29",
"type": "module",
"files": [
"index.js",
@@ -27,6 +27,7 @@
"createLockfile": "pnpm --ignore-workspace install"
},
"dependencies": {
"@ark/fs": "0.49.0",
"@actions/core": "^1.11.1",
"@modelcontextprotocol/sdk": "^1.17.5",
"@octokit/rest": "^22.0.0",
@@ -34,7 +35,8 @@
"arktype": "^2.1.22",
"dotenv": "^17.2.2",
"execa": "^9.6.0",
"table": "^6.9.0"
"table": "^6.9.0",
"zod": "^3.24.4"
},
"devDependencies": {
"@types/node": "^20.10.0",
@@ -42,8 +44,7 @@
"esbuild": "^0.25.9",
"husky": "^9.0.0",
"typescript": "^5.3.0",
"zshy": "^0.4.1",
"zod": "^3.24.4"
"zshy": "^0.4.1"
},
"repository": {
"type": "git",
+6 -6
View File
@@ -1,23 +1,23 @@
import { existsSync, readFileSync } from "node:fs";
import { dirname, extname, join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { extname, join, resolve } from "node:path";
import { pathToFileURL } from "node:url";
import { fromHere } from "@ark/fs";
import arg from "arg";
import { config } from "dotenv";
import { main } from "./main.ts";
import packageJson from "./package.json" with { type: "json" };
import { runAct } from "./utils/act.ts";
import { setupGitHubInstallationToken } from "./utils/github.ts";
import { setupTestRepo } from "./utils/setup.ts";
config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export async function run(
prompt: string,
options: { act?: boolean } = {}
): Promise<{ success: boolean; output?: string | undefined; error?: string | undefined }> {
try {
console.log(`🐸 Running pullfrog/action@${packageJson.version}...`);
if (options.act) {
console.log("🐳 Running with Docker/act...");
runAct(prompt);
@@ -129,7 +129,7 @@ Examples:
const ext = extname(filePath).toLowerCase();
let resolvedPath: string;
const fixturesPath = join(__dirname, "fixtures", filePath);
const fixturesPath = fromHere("fixtures", filePath);
if (existsSync(fixturesPath)) {
resolvedPath = fixturesPath;
} else if (existsSync(filePath)) {
+11 -3
View File
@@ -11,6 +11,9 @@ importers:
'@actions/core':
specifier: ^1.11.1
version: 1.11.1
'@ark/fs':
specifier: 0.49.0
version: 0.49.0
'@modelcontextprotocol/sdk':
specifier: ^1.17.5
version: 1.19.1
@@ -32,6 +35,9 @@ importers:
table:
specifier: ^6.9.0
version: 6.9.0
zod:
specifier: ^3.24.4
version: 3.25.76
devDependencies:
'@types/node':
specifier: ^20.10.0
@@ -48,9 +54,6 @@ importers:
typescript:
specifier: ^5.3.0
version: 5.9.3
zod:
specifier: ^3.24.4
version: 3.25.76
zshy:
specifier: ^0.4.1
version: 0.4.3(typescript@5.9.3)
@@ -69,6 +72,9 @@ packages:
'@actions/io@1.1.3':
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':
resolution: {integrity: sha512-GphZBLpW72iS0v4YkeUtV3YIno35Gimd7+ezbPO9GwEi9kzdUrPVjvf6aXSBAfHikaFc/9pqZOpv3pOXnC71tw==}
@@ -902,6 +908,8 @@ snapshots:
'@actions/io@1.1.3': {}
'@ark/fs@0.49.0': {}
'@ark/schema@0.49.0':
dependencies:
'@ark/util': 0.49.0