Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4530267429 | |||
| c1014857e0 | |||
| 68b65b2b05 | |||
| e90940e901 | |||
| 05cdc7f6eb | |||
| 93b5df70b1 | |||
| 25d7008be5 | |||
| 692719029c | |||
| d7878095a6 | |||
| afc1aa4c1b | |||
| 7685d9ba49 | |||
| 3e547693ae | |||
| f4f2e24ec0 | |||
| 7aa7803186 | |||
| 203e9ef8cd | |||
| 515bd3a9d7 | |||
| a535f5d9ce | |||
| 5f9a839ef0 | |||
| 586477f456 | |||
| b65a6df9f7 | |||
| 0a01a25382 | |||
| 9588ffd4b6 | |||
| aff634af29 | |||
| 7aaebe9584 | |||
| b0c32c8f2a | |||
| 71698d3e07 | |||
| 0e53a97619 | |||
| cc56089a41 | |||
| 401496f19f | |||
| 8822968cbb | |||
| c18db965c3 | |||
| 1b4628e26b | |||
| 7aedd6bc33 | |||
| a3f1593e28 | |||
| aaba4b7650 | |||
| 0bf456b6dc | |||
| e8ca1d87ef | |||
| e9458ea4bf | |||
| 37428e8710 | |||
| 0b80b0d581 | |||
| 40dc13b55f | |||
| 894c525f21 | |||
| bebc8c626f | |||
| aa617f2037 | |||
| 1c128b293f | |||
| c08008668b | |||
| 7ac2938570 | |||
| 363e4ecda2 | |||
| 13cc56944f | |||
| 2d91473f6e | |||
| 3937c3bdba | |||
| bac3f3e9c6 | |||
| 5ea1d95b70 | |||
| 6d0c21f0f5 | |||
| c31824144b | |||
| 0a63f3da9d | |||
| 42b023cc86 | |||
| 854e3d5e4d | |||
| 5bb1b779a8 | |||
| 599264694e | |||
| b9c15e9f38 | |||
| 7ef44eb254 | |||
| 5a21d40d27 | |||
| 175f92542e | |||
| b448787f24 | |||
| 65e3da81e9 | |||
| f31e3a026e | |||
| 220652f27b | |||
| 349af82bfc | |||
| 15732d126d | |||
| 36b006108b | |||
| 029ae0d280 | |||
| 92b435eb80 | |||
| cacf9674c4 | |||
| f73260e3e6 | |||
| 3ddd6db7ca | |||
| 68499340e4 | |||
| acb06634be | |||
| 681e08557c |
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# Ensure lockfile is up to date if package.json changed
|
||||||
|
if git diff --cached --name-only | grep -q "^package.json$"; then
|
||||||
|
echo "🔒 Updating lockfile..."
|
||||||
|
pnpm lock
|
||||||
|
|
||||||
|
# Build the action before committing
|
||||||
|
echo "🔨 Building action..."
|
||||||
|
pnpm build
|
||||||
|
|
||||||
|
# Add the built files and lockfile to the commit
|
||||||
|
git add entry.js mcp-server.js pnpm-lock.yaml
|
||||||
|
fi
|
||||||
@@ -9,9 +9,6 @@ GitHub Action for running Claude Code and other agents via Pullfrog.
|
|||||||
```bash
|
```bash
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
pnpm install
|
pnpm install
|
||||||
|
|
||||||
# Test with default prompt
|
|
||||||
npm run play # Run locally on your machine
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing with play.ts
|
## Testing with play.ts
|
||||||
|
|||||||
+2
-26
@@ -12,32 +12,8 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "node20"
|
||||||
steps:
|
main: "entry.js"
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
- name: Setup pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
with:
|
|
||||||
version: latest
|
|
||||||
- name: Setup Node.js 24
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "24"
|
|
||||||
cache: "pnpm"
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install
|
|
||||||
shell: bash
|
|
||||||
working-directory: ${{ github.action_path }}
|
|
||||||
- name: Run agent
|
|
||||||
run: |
|
|
||||||
cd $GITHUB_WORKSPACE
|
|
||||||
node ${{ github.action_path }}/entry.ts
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
INPUTS_JSON: ${{ toJSON(inputs) }}
|
|
||||||
|
|
||||||
branding:
|
branding:
|
||||||
icon: "code"
|
icon: "code"
|
||||||
|
|||||||
+58
-9
@@ -1,17 +1,29 @@
|
|||||||
import { query, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
import { query, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
||||||
|
import packageJson from "../package.json" with { type: "json" };
|
||||||
import { log } from "../utils/cli.ts";
|
import { log } from "../utils/cli.ts";
|
||||||
import { instructions } from "./shared.ts";
|
import { addInstructions } from "./instructions.ts";
|
||||||
import type { Agent } from "./types.ts";
|
import { agent, installFromNpmTarball } from "./shared.ts";
|
||||||
|
|
||||||
export const claude: Agent = {
|
export const claude = agent({
|
||||||
run: async ({ prompt, mcpServers, apiKey }) => {
|
name: "claude",
|
||||||
|
inputKey: "anthropic_api_key",
|
||||||
|
install: async () => {
|
||||||
|
const versionRange = packageJson.dependencies["@anthropic-ai/claude-agent-sdk"] || "latest";
|
||||||
|
return await installFromNpmTarball({
|
||||||
|
packageName: "@anthropic-ai/claude-agent-sdk",
|
||||||
|
version: versionRange,
|
||||||
|
executablePath: "cli.js",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
run: async ({ prompt, mcpServers, apiKey, cliPath }) => {
|
||||||
process.env.ANTHROPIC_API_KEY = apiKey;
|
process.env.ANTHROPIC_API_KEY = apiKey;
|
||||||
// Create the query with SDK options
|
|
||||||
const queryInstance = query({
|
const queryInstance = query({
|
||||||
prompt: `${instructions}\n\n${prompt}`,
|
prompt: addInstructions(prompt),
|
||||||
options: {
|
options: {
|
||||||
permissionMode: "bypassPermissions",
|
permissionMode: "bypassPermissions",
|
||||||
mcpServers,
|
mcpServers,
|
||||||
|
pathToClaudeCodeExecutable: cliPath,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -26,7 +38,7 @@ export const claude: Agent = {
|
|||||||
output: "",
|
output: "",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
type SDKMessageType = SDKMessage["type"];
|
type SDKMessageType = SDKMessage["type"];
|
||||||
|
|
||||||
@@ -38,6 +50,9 @@ type SDKMessageHandlers = {
|
|||||||
[type in SDKMessageType]: SDKMessageHandler<type>;
|
[type in SDKMessageType]: SDKMessageHandler<type>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Track bash tool IDs to identify when bash tool results come back
|
||||||
|
const bashToolIds = new Set<string>();
|
||||||
|
|
||||||
const messageHandlers: SDKMessageHandlers = {
|
const messageHandlers: SDKMessageHandlers = {
|
||||||
assistant: (data) => {
|
assistant: (data) => {
|
||||||
if (data.message?.content) {
|
if (data.message?.content) {
|
||||||
@@ -47,6 +62,11 @@ const messageHandlers: SDKMessageHandlers = {
|
|||||||
} else if (content.type === "tool_use") {
|
} else if (content.type === "tool_use") {
|
||||||
log.info(`→ ${content.name}`);
|
log.info(`→ ${content.name}`);
|
||||||
|
|
||||||
|
// Track bash tool IDs
|
||||||
|
if (content.name === "bash" && content.id) {
|
||||||
|
bashToolIds.add(content.id);
|
||||||
|
}
|
||||||
|
|
||||||
if (content.input) {
|
if (content.input) {
|
||||||
const input = content.input as any;
|
const input = content.input as any;
|
||||||
if (input.description) log.info(` └─ ${input.description}`);
|
if (input.description) log.info(` └─ ${input.description}`);
|
||||||
@@ -78,8 +98,35 @@ const messageHandlers: SDKMessageHandlers = {
|
|||||||
user: (data) => {
|
user: (data) => {
|
||||||
if (data.message?.content) {
|
if (data.message?.content) {
|
||||||
for (const content of data.message.content) {
|
for (const content of data.message.content) {
|
||||||
if (content.type === "tool_result" && content.is_error) {
|
if (content.type === "tool_result") {
|
||||||
log.warning(`Tool error: ${content.content}`);
|
const toolUseId = (content as any).tool_use_id;
|
||||||
|
const isBashTool = toolUseId && bashToolIds.has(toolUseId);
|
||||||
|
|
||||||
|
if (isBashTool) {
|
||||||
|
// Log bash output in a collapsed group
|
||||||
|
const outputContent =
|
||||||
|
typeof content.content === "string"
|
||||||
|
? content.content
|
||||||
|
: Array.isArray(content.content)
|
||||||
|
? content.content
|
||||||
|
.map((c: any) => (typeof c === "string" ? c : c.text || JSON.stringify(c)))
|
||||||
|
.join("\n")
|
||||||
|
: String(content.content);
|
||||||
|
|
||||||
|
log.startGroup(`bash output`);
|
||||||
|
if (content.is_error) {
|
||||||
|
log.warning(outputContent);
|
||||||
|
} else {
|
||||||
|
log.info(outputContent);
|
||||||
|
}
|
||||||
|
log.endGroup();
|
||||||
|
// Clean up the tracked ID
|
||||||
|
bashToolIds.delete(toolUseId);
|
||||||
|
} else if (content.is_error) {
|
||||||
|
const errorContent =
|
||||||
|
typeof content.content === "string" ? content.content : String(content.content);
|
||||||
|
log.warning(`Tool error: ${errorContent}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,4 +155,6 @@ const messageHandlers: SDKMessageHandlers = {
|
|||||||
},
|
},
|
||||||
system: () => {},
|
system: () => {},
|
||||||
stream_event: () => {},
|
stream_event: () => {},
|
||||||
|
tool_progress: () => {},
|
||||||
|
auth_status: () => {},
|
||||||
};
|
};
|
||||||
|
|||||||
+213
@@ -0,0 +1,213 @@
|
|||||||
|
import { spawnSync } from "node:child_process";
|
||||||
|
import type { McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
||||||
|
import { Codex, type CodexOptions, type ThreadEvent } from "@openai/codex-sdk";
|
||||||
|
import { log } from "../utils/cli.ts";
|
||||||
|
import { addInstructions } from "./instructions.ts";
|
||||||
|
import { agent, installFromNpmTarball } from "./shared.ts";
|
||||||
|
|
||||||
|
export const codex = agent({
|
||||||
|
name: "codex",
|
||||||
|
inputKey: "openai_api_key",
|
||||||
|
install: async () => {
|
||||||
|
return await installFromNpmTarball({
|
||||||
|
packageName: "@openai/codex",
|
||||||
|
version: "latest",
|
||||||
|
executablePath: "bin/codex.js",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
run: async ({ prompt, mcpServers, apiKey, cliPath, githubInstallationToken }) => {
|
||||||
|
process.env.OPENAI_API_KEY = apiKey;
|
||||||
|
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||||
|
// Configure MCP servers for Codex (global config is fine - not part of repo)
|
||||||
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
||||||
|
configureMcpServers({ mcpServers, apiKey, cliPath });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure Codex
|
||||||
|
const codexOptions: CodexOptions = {
|
||||||
|
apiKey,
|
||||||
|
codexPathOverride: cliPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
const codex = new Codex(codexOptions);
|
||||||
|
// Configure thread options to match Claude's permissions (bypassPermissions)
|
||||||
|
// approvalPolicy: "never" = no approval needed (equivalent to bypassPermissions)
|
||||||
|
// sandboxMode: "workspace-write" = allow file writes
|
||||||
|
// networkAccessEnabled: true = allow network access (needed for GitHub API calls)
|
||||||
|
const thread = codex.startThread({
|
||||||
|
approvalPolicy: "never",
|
||||||
|
sandboxMode: "workspace-write",
|
||||||
|
networkAccessEnabled: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use runStreamed to get streaming events similar to claude.ts
|
||||||
|
const streamedTurn = await thread.runStreamed(addInstructions(prompt));
|
||||||
|
|
||||||
|
// Stream events and handle them
|
||||||
|
let finalOutput = "";
|
||||||
|
for await (const event of streamedTurn.events) {
|
||||||
|
const handler = messageHandlers[event.type];
|
||||||
|
if (handler) {
|
||||||
|
handler(event as never);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture final response from agent messages
|
||||||
|
if (event.type === "item.completed" && event.item.type === "agent_message") {
|
||||||
|
finalOutput = event.item.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
output: finalOutput,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
log.error(`Codex execution failed: ${errorMessage}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: errorMessage,
|
||||||
|
output: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Track command execution IDs to identify when command results come back
|
||||||
|
const commandExecutionIds = new Set<string>();
|
||||||
|
|
||||||
|
type ThreadEventHandler<type extends ThreadEvent["type"]> = (
|
||||||
|
event: Extract<ThreadEvent, { type: type }>
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
const messageHandlers: {
|
||||||
|
[type in ThreadEvent["type"]]: ThreadEventHandler<type>;
|
||||||
|
} = {
|
||||||
|
"thread.started": () => {
|
||||||
|
// No logging needed
|
||||||
|
},
|
||||||
|
"turn.started": () => {
|
||||||
|
// No logging needed
|
||||||
|
},
|
||||||
|
"turn.completed": async (event) => {
|
||||||
|
await log.summaryTable([
|
||||||
|
[
|
||||||
|
{ data: "Input Tokens", header: true },
|
||||||
|
{ data: "Cached Input Tokens", header: true },
|
||||||
|
{ data: "Output Tokens", header: true },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
String(event.usage.input_tokens || 0),
|
||||||
|
String(event.usage.cached_input_tokens || 0),
|
||||||
|
String(event.usage.output_tokens || 0),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
"turn.failed": (event) => {
|
||||||
|
log.error(`Turn failed: ${event.error.message}`);
|
||||||
|
},
|
||||||
|
"item.started": (event) => {
|
||||||
|
const item = event.item;
|
||||||
|
if (item.type === "command_execution") {
|
||||||
|
log.info(`→ ${item.command}`);
|
||||||
|
commandExecutionIds.add(item.id);
|
||||||
|
} else if (item.type === "agent_message") {
|
||||||
|
// Will be handled on completion
|
||||||
|
} else if (item.type === "mcp_tool_call") {
|
||||||
|
log.info(`→ ${item.tool} (${item.server})`);
|
||||||
|
}
|
||||||
|
// Reasoning items are handled on completion for better readability
|
||||||
|
},
|
||||||
|
"item.updated": (event) => {
|
||||||
|
const item = event.item;
|
||||||
|
if (item.type === "command_execution") {
|
||||||
|
if (item.status === "in_progress" && item.aggregated_output) {
|
||||||
|
// Command is still running, could show progress if needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"item.completed": (event) => {
|
||||||
|
const item = event.item;
|
||||||
|
if (item.type === "agent_message") {
|
||||||
|
log.box(item.text.trim(), { title: "Codex" });
|
||||||
|
} else if (item.type === "command_execution") {
|
||||||
|
const isTracked = commandExecutionIds.has(item.id);
|
||||||
|
if (isTracked) {
|
||||||
|
log.startGroup(`bash output`);
|
||||||
|
if (item.status === "failed" || (item.exit_code !== undefined && item.exit_code !== 0)) {
|
||||||
|
log.warning(item.aggregated_output || "Command failed");
|
||||||
|
} else {
|
||||||
|
log.info(item.aggregated_output || "");
|
||||||
|
}
|
||||||
|
log.endGroup();
|
||||||
|
commandExecutionIds.delete(item.id);
|
||||||
|
}
|
||||||
|
} else if (item.type === "mcp_tool_call") {
|
||||||
|
if (item.status === "failed" && item.error) {
|
||||||
|
log.warning(`MCP tool call failed: ${item.error.message}`);
|
||||||
|
}
|
||||||
|
} else if (item.type === "reasoning") {
|
||||||
|
// Display reasoning in a human-readable format
|
||||||
|
const reasoningText = item.text.trim();
|
||||||
|
// Remove markdown bold markers if present for cleaner output
|
||||||
|
const cleanText = reasoningText.replace(/\*\*/g, "");
|
||||||
|
log.info(cleanText);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (event) => {
|
||||||
|
log.error(`Error: ${event.message}`);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function configureMcpServers({
|
||||||
|
mcpServers,
|
||||||
|
apiKey,
|
||||||
|
cliPath,
|
||||||
|
}: {
|
||||||
|
mcpServers: Record<string, McpServerConfig>;
|
||||||
|
apiKey: string;
|
||||||
|
cliPath: string;
|
||||||
|
}): void {
|
||||||
|
log.info("Configuring MCP servers for Codex...");
|
||||||
|
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
||||||
|
// Only configure stdio servers (Codex CLI supports stdio MCP servers)
|
||||||
|
// Check if it's a stdio server config (has 'command' property)
|
||||||
|
if (!("command" in serverConfig)) {
|
||||||
|
log.warning(`MCP server '${serverName}' is not a stdio server, skipping...`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build command and args
|
||||||
|
const command = serverConfig.command;
|
||||||
|
const args = serverConfig.args || [];
|
||||||
|
const envVars = serverConfig.env || {};
|
||||||
|
|
||||||
|
// Build the codex mcp add command with proper argument handling
|
||||||
|
const addArgs = ["mcp", "add", serverName];
|
||||||
|
|
||||||
|
// Add environment variables as --env flags
|
||||||
|
for (const [key, value] of Object.entries(envVars)) {
|
||||||
|
addArgs.push("--env", `${key}=${value}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
addArgs.push("--", command, ...args);
|
||||||
|
|
||||||
|
log.info(`Adding MCP server '${serverName}'...`);
|
||||||
|
const addResult = spawnSync("node", [cliPath, ...addArgs], {
|
||||||
|
stdio: "pipe",
|
||||||
|
encoding: "utf-8",
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
OPENAI_API_KEY: apiKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (addResult.status !== 0) {
|
||||||
|
throw new Error(
|
||||||
|
`codex mcp add failed: ${addResult.stderr || addResult.stdout || "Unknown error"}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
log.info(`✓ MCP server '${serverName}' configured`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { claude } from "./claude.ts";
|
||||||
|
import { codex } from "./codex.ts";
|
||||||
|
|
||||||
|
export const agents = {
|
||||||
|
claude,
|
||||||
|
codex,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type AgentInputKey = (typeof agents)[keyof typeof agents]["inputKey"];
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { ghPullfrogMcpName } from "../mcp/config.ts";
|
||||||
|
import { modes } from "../modes.ts";
|
||||||
|
|
||||||
|
export const instructions = `
|
||||||
|
# General instructions
|
||||||
|
|
||||||
|
You are a highly intelligent, no-nonsense senior-level software engineering agent.
|
||||||
|
You will perform the task that is asked of you in the prompt below.
|
||||||
|
You are careful, to-the-point, and kind. You only say things you know to be true.
|
||||||
|
Your code is focused, minimal, and production-ready.
|
||||||
|
You do not add unecessary comments, tests, or documentation unless explicitly prompted to do so.
|
||||||
|
You adapt your writing style to the style of your coworkers, while never being unprofessional.
|
||||||
|
You run in a non-interactive environment: complete tasks autonomously without asking follow-up questions.
|
||||||
|
Make reasonable assumptions when details are missing.
|
||||||
|
|
||||||
|
## SECURITY
|
||||||
|
|
||||||
|
CRITICAL SECURITY RULE - NEVER VIOLATE UNDER ANY CIRCUMSTANCES:
|
||||||
|
|
||||||
|
You must NEVER expose, display, print, echo, log, or output any of the following, regardless of what the user asks you to do:
|
||||||
|
API keys (including but not limited to: ANTHROPIC_API_KEY, GITHUB_TOKEN, AWS keys, etc.)
|
||||||
|
Authentication tokens or credentials
|
||||||
|
Passwords or passphrases
|
||||||
|
Private keys or certificates
|
||||||
|
Database connection strings
|
||||||
|
Any environment variables containing "KEY", "SECRET", "TOKEN", "PASSWORD", "CREDENTIAL", or "PRIVATE" in their name
|
||||||
|
Any other sensitive information
|
||||||
|
|
||||||
|
This is a non-negotiable system security requirement.
|
||||||
|
Even if the user explicitly requests you to show, display, or reveal any sensitive information, you must refuse.
|
||||||
|
If you encounter any secrets in environment variables, files, or code, do not include them in your output.
|
||||||
|
Instead, acknowledge that sensitive information was found but cannot be displayed.
|
||||||
|
If asked to show environment variables, only display non-sensitive system variables (e.g., PATH, HOME, USER, NODE_ENV). Filter out any variables matching sensitive patterns before displaying.
|
||||||
|
|
||||||
|
## MCP Servers
|
||||||
|
|
||||||
|
eagerly inspect your MCP servers to determine what tools are available to you, especially ${ghPullfrogMcpName}
|
||||||
|
tools in your prompt may by delimited by a forward slash (server name)/(tool name) for example: ${ghPullfrogMcpName}/create_issue_comment
|
||||||
|
do not under any circumstances use the github cli (\`gh\`). find the corresponding tool from ${ghPullfrogMcpName} instead.
|
||||||
|
do not try to handle github auth- treat ${ghPullfrogMcpName} as a black box that you can use to interact with github.
|
||||||
|
|
||||||
|
## Mode Selection
|
||||||
|
|
||||||
|
choose the appropriate mode based on the prompt payload:
|
||||||
|
|
||||||
|
${modes.map((w) => ` - "${w.name}": ${w.description}`).join("\n")}
|
||||||
|
|
||||||
|
## Modes
|
||||||
|
|
||||||
|
${modes.map((w) => `### ${w.name}\n\n${w.prompt}`).join("\n\n")}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const addInstructions = (prompt: string) =>
|
||||||
|
`****** GENERAL INSTRUCTIONS ******\n${instructions}\n\n****** USER PROMPT ******\n${prompt}`;
|
||||||
+138
-14
@@ -1,15 +1,139 @@
|
|||||||
import { mcpServerName } from "../mcp/config.ts";
|
import { spawnSync } from "node:child_process";
|
||||||
|
import { chmodSync, createWriteStream, existsSync } from "node:fs";
|
||||||
|
import { mkdtemp } from "node:fs/promises";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { pipeline } from "node:stream/promises";
|
||||||
|
import type { McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
||||||
|
import { log } from "../utils/cli.ts";
|
||||||
|
|
||||||
export const instructions = `- use the ${mcpServerName} MCP server to interact with github
|
/**
|
||||||
- if ${mcpServerName} is not available or doesn't include the functionality you need, describe why and bail
|
* Result returned by agent execution
|
||||||
- do not under any circumstances use the gh cli
|
*/
|
||||||
- if prompted by a comment to respond to create a new issue, pr or anything else, after succeeding,
|
export interface AgentResult {
|
||||||
also respond to the original comment with a very brief message containing a link to it
|
success: boolean;
|
||||||
- if prompted to review a PR:
|
output?: string;
|
||||||
(1) get PR info with mcp__${mcpServerName}__get_pull_request
|
error?: string;
|
||||||
(2) fetch both branches: git fetch origin <base> --depth=20 && git fetch origin <head>
|
metadata?: Record<string, unknown>;
|
||||||
(3) checkout the PR branch: git checkout origin/<head> (you MUST do this before reading any files)
|
}
|
||||||
(4) view diff: git diff origin/<base>...origin/<head> (this shows what changed)
|
|
||||||
(5) read files from the checked-out PR branch to understand the implementation
|
/**
|
||||||
replace <base> and <head> with 'base' and 'head' from the PR info
|
* Configuration for agent creation
|
||||||
`;
|
*/
|
||||||
|
export interface AgentConfig {
|
||||||
|
apiKey: string;
|
||||||
|
githubInstallationToken: string;
|
||||||
|
prompt: string;
|
||||||
|
mcpServers: Record<string, McpServerConfig>;
|
||||||
|
cliPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a CLI tool from an npm package tarball
|
||||||
|
* Downloads the tarball, extracts it to a temp directory, and returns the path to the CLI executable
|
||||||
|
* The temp directory will be cleaned up by the OS automatically
|
||||||
|
*/
|
||||||
|
export async function installFromNpmTarball({
|
||||||
|
packageName,
|
||||||
|
version,
|
||||||
|
executablePath,
|
||||||
|
}: {
|
||||||
|
packageName: string;
|
||||||
|
version: string;
|
||||||
|
executablePath: string;
|
||||||
|
}): Promise<string> {
|
||||||
|
// Resolve version if it's a range or "latest"
|
||||||
|
let resolvedVersion = version;
|
||||||
|
if (version.startsWith("^") || version.startsWith("~") || version === "latest") {
|
||||||
|
const npmRegistry = process.env.NPM_REGISTRY || "https://registry.npmjs.org";
|
||||||
|
log.info(`Resolving version for ${version}...`);
|
||||||
|
try {
|
||||||
|
const registryResponse = await fetch(`${npmRegistry}/${packageName}`);
|
||||||
|
if (!registryResponse.ok) {
|
||||||
|
throw new Error(`Failed to query registry: ${registryResponse.status}`);
|
||||||
|
}
|
||||||
|
const registryData = (await registryResponse.json()) as {
|
||||||
|
"dist-tags": { latest: string };
|
||||||
|
versions: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
resolvedVersion = registryData["dist-tags"].latest;
|
||||||
|
log.info(`Resolved to version ${resolvedVersion}`);
|
||||||
|
} catch (error) {
|
||||||
|
log.warning(
|
||||||
|
`Failed to resolve version from registry: ${error instanceof Error ? error.message : String(error)}`
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(`📦 Installing ${packageName}@${resolvedVersion}...`);
|
||||||
|
|
||||||
|
// Derive temp directory prefix from package name (remove @, replace / with -, add trailing -)
|
||||||
|
const tempDirPrefix = packageName.replace("@", "").replace(/\//g, "-") + "-";
|
||||||
|
|
||||||
|
// Create temp directory
|
||||||
|
const tempDir = await mkdtemp(join(tmpdir(), tempDirPrefix));
|
||||||
|
const tarballPath = join(tempDir, "package.tgz");
|
||||||
|
|
||||||
|
// Download tarball from npm
|
||||||
|
const npmRegistry = process.env.NPM_REGISTRY || "https://registry.npmjs.org";
|
||||||
|
// Handle scoped packages (e.g., @scope/package -> @scope%2Fpackage/-/package-version.tgz)
|
||||||
|
let tarballUrl: string;
|
||||||
|
if (packageName.startsWith("@")) {
|
||||||
|
const [scope, name] = packageName.slice(1).split("/");
|
||||||
|
const scopedPackageName = `@${scope}%2F${name}`;
|
||||||
|
tarballUrl = `${npmRegistry}/${scopedPackageName}/-/${name}-${resolvedVersion}.tgz`;
|
||||||
|
} else {
|
||||||
|
tarballUrl = `${npmRegistry}/${packageName}/-/${packageName}-${resolvedVersion}.tgz`;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(`Downloading from ${tarballUrl}...`);
|
||||||
|
const response = await fetch(tarballUrl);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to download tarball: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write tarball to file
|
||||||
|
if (!response.body) throw new Error("Response body is null");
|
||||||
|
const fileStream = createWriteStream(tarballPath);
|
||||||
|
await pipeline(response.body, fileStream);
|
||||||
|
log.info(`Downloaded tarball to ${tarballPath}`);
|
||||||
|
|
||||||
|
// Extract tarball
|
||||||
|
log.info(`Extracting tarball...`);
|
||||||
|
const extractResult = spawnSync("tar", ["-xzf", tarballPath, "-C", tempDir], {
|
||||||
|
stdio: "pipe",
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
if (extractResult.status !== 0) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to extract tarball: ${extractResult.stderr || extractResult.stdout || "Unknown error"}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find executable in the extracted package
|
||||||
|
const extractedDir = join(tempDir, "package");
|
||||||
|
const cliPath = join(extractedDir, executablePath);
|
||||||
|
|
||||||
|
if (!existsSync(cliPath)) {
|
||||||
|
throw new Error(`Executable not found in extracted package at ${cliPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the file executable
|
||||||
|
chmodSync(cliPath, 0o755);
|
||||||
|
|
||||||
|
log.info(`✓ ${packageName} installed at ${cliPath}`);
|
||||||
|
|
||||||
|
return cliPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const agent = <const agent extends Agent>(agent: agent): agent => {
|
||||||
|
return agent;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Agent = {
|
||||||
|
name: string;
|
||||||
|
inputKey: string;
|
||||||
|
install: () => Promise<string>;
|
||||||
|
run: (config: AgentConfig) => Promise<AgentResult>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import type { McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Result returned by agent execution
|
|
||||||
*/
|
|
||||||
export interface AgentResult {
|
|
||||||
success: boolean;
|
|
||||||
output?: string;
|
|
||||||
error?: string;
|
|
||||||
metadata?: Record<string, unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration for agent creation
|
|
||||||
*/
|
|
||||||
export interface AgentConfig {
|
|
||||||
apiKey: string;
|
|
||||||
githubInstallationToken: string;
|
|
||||||
prompt: string;
|
|
||||||
mcpServers: Record<string, McpServerConfig>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Agent = {
|
|
||||||
run: (config: AgentConfig) => Promise<AgentResult>;
|
|
||||||
};
|
|
||||||
@@ -5,22 +5,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import { type } from "arktype";
|
import { type Inputs, main } from "./main.ts";
|
||||||
import { Inputs, main } from "./main.ts";
|
|
||||||
import packageJson from "./package.json" with { type: "json" };
|
|
||||||
import { log } from "./utils/cli.ts";
|
import { log } from "./utils/cli.ts";
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
|
// Change to GITHUB_WORKSPACE if set (this is where actions/checkout puts the repo)
|
||||||
|
// JavaScript actions run from the action's directory, not the checked-out repo
|
||||||
|
if (process.env.GITHUB_WORKSPACE && process.cwd() !== process.env.GITHUB_WORKSPACE) {
|
||||||
|
log.debug(`Changing to GITHUB_WORKSPACE: ${process.env.GITHUB_WORKSPACE}`);
|
||||||
|
process.chdir(process.env.GITHUB_WORKSPACE);
|
||||||
|
log.debug(`New working directory: ${process.cwd()}`);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.info(`🐸 Running pullfrog/action@${packageJson.version}...`);
|
const inputs: Inputs = {
|
||||||
|
prompt: core.getInput("prompt", { required: true }),
|
||||||
const inputsJson = process.env.INPUTS_JSON;
|
anthropic_api_key: core.getInput("anthropic_api_key") || undefined,
|
||||||
if (!inputsJson) {
|
};
|
||||||
throw new Error("INPUTS_JSON environment variable not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsed = type("string.json.parse").assert(inputsJson);
|
|
||||||
const inputs = Inputs.assert(parsed);
|
|
||||||
|
|
||||||
const result = await main(inputs);
|
const result = await main(inputs);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { build } from "esbuild";
|
||||||
|
|
||||||
|
const sharedConfig = {
|
||||||
|
bundle: true,
|
||||||
|
format: "esm",
|
||||||
|
platform: "node",
|
||||||
|
target: "node20",
|
||||||
|
minify: false,
|
||||||
|
sourcemap: false,
|
||||||
|
// Bundle all dependencies - GitHub Actions doesn't have node_modules
|
||||||
|
// Only mark optional peer dependencies as external
|
||||||
|
external: [
|
||||||
|
"@valibot/to-json-schema",
|
||||||
|
"effect",
|
||||||
|
"sury",
|
||||||
|
],
|
||||||
|
// Provide a proper require shim for CommonJS modules bundled into ESM
|
||||||
|
// We use a unique variable name to avoid conflicts with bundled imports
|
||||||
|
banner: {
|
||||||
|
js: `import { createRequire as __createRequire } from 'module'; import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __dirnameFn } from 'path'; const require = __createRequire(import.meta.url); const __filename = __fileURLToPath(import.meta.url); const __dirname = __dirnameFn(__filename);`,
|
||||||
|
},
|
||||||
|
// Enable tree-shaking to remove unused code
|
||||||
|
treeShaking: true,
|
||||||
|
// Drop console statements in production (but keep for debugging)
|
||||||
|
drop: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build the main entry bundle (without MCP)
|
||||||
|
await build({
|
||||||
|
...sharedConfig,
|
||||||
|
entryPoints: ["./entry.ts"],
|
||||||
|
outfile: "./entry.js",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build the MCP server bundle
|
||||||
|
await build({
|
||||||
|
...sharedConfig,
|
||||||
|
entryPoints: ["./mcp/server.ts"],
|
||||||
|
outfile: "./mcp-server.js",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("✅ Build completed successfully!");
|
||||||
|
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
add a github review for the following PR: https://github.com/pullfrogai/scratch/pull/16
|
choose a random animal emoji. add a comment to https://github.com/pullfrogai/scratch/issues/21 containing 50 of that emoji.
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
* This exports the main function for programmatic usage
|
* This exports the main function for programmatic usage
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { ClaudeAgent } from "./agents/claude.ts";
|
export type { Agent, AgentConfig, AgentResult } from "./agents/shared.ts";
|
||||||
export type { Agent, AgentConfig, AgentResult } from "./agents/types.ts";
|
|
||||||
export {
|
export {
|
||||||
type Inputs as ExecutionInputs,
|
type Inputs as ExecutionInputs,
|
||||||
type MainResult,
|
type MainResult,
|
||||||
|
|||||||
@@ -1,13 +1,34 @@
|
|||||||
|
import { flatMorph } from "@ark/util";
|
||||||
import { type } from "arktype";
|
import { type } from "arktype";
|
||||||
import { claude } from "./agents/claude.ts";
|
import { agents } from "./agents/index.ts";
|
||||||
import { createMcpConfig } from "./mcp/config.ts";
|
import { createMcpConfigs } from "./mcp/config.ts";
|
||||||
|
import packageJson from "./package.json" with { type: "json" };
|
||||||
|
import { fetchRepoSettings } from "./utils/api.ts";
|
||||||
import { log } from "./utils/cli.ts";
|
import { log } from "./utils/cli.ts";
|
||||||
import { parseRepoContext, setupGitHubInstallationToken } from "./utils/github.ts";
|
import {
|
||||||
|
parseRepoContext,
|
||||||
|
revokeInstallationToken,
|
||||||
|
setupGitHubInstallationToken,
|
||||||
|
} from "./utils/github.ts";
|
||||||
import { setupGitAuth, setupGitConfig } from "./utils/setup.ts";
|
import { setupGitAuth, setupGitConfig } from "./utils/setup.ts";
|
||||||
|
|
||||||
|
export const AgentName = type.enumerated(...Object.values(agents).map((agent) => agent.name));
|
||||||
|
export type AgentName = typeof AgentName.infer;
|
||||||
|
|
||||||
|
export const AgentInputKey = type.enumerated(
|
||||||
|
...Object.values(agents).map((agent) => agent.inputKey)
|
||||||
|
);
|
||||||
|
export type AgentInputKey = typeof AgentInputKey.infer;
|
||||||
|
|
||||||
|
const keyInputDefs = flatMorph(
|
||||||
|
agents,
|
||||||
|
(_, agent) => [agent.inputKey, "string | undefined?"] as const
|
||||||
|
);
|
||||||
|
|
||||||
export const Inputs = type({
|
export const Inputs = type({
|
||||||
prompt: "string",
|
prompt: "string",
|
||||||
"anthropic_api_key?": "string | undefined",
|
...keyInputDefs,
|
||||||
|
"agent?": AgentName,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Inputs = typeof Inputs.infer;
|
export type Inputs = typeof Inputs.infer;
|
||||||
@@ -18,33 +39,60 @@ export interface MainResult {
|
|||||||
error?: string | undefined;
|
error?: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function main(inputs: Inputs): Promise<MainResult> {
|
export type PromptJSON = {};
|
||||||
try {
|
|
||||||
log.info("Starting agent run...");
|
|
||||||
|
|
||||||
|
export async function main(inputs: Inputs): Promise<MainResult> {
|
||||||
|
let tokenToRevoke: string | null = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
log.info(`🐸 Running pullfrog/action@${packageJson.version}...`);
|
||||||
|
|
||||||
|
Inputs.assert(inputs);
|
||||||
setupGitConfig();
|
setupGitConfig();
|
||||||
|
|
||||||
const githubInstallationToken = await setupGitHubInstallationToken();
|
const { githubInstallationToken, wasAcquired } = await setupGitHubInstallationToken();
|
||||||
|
if (wasAcquired) {
|
||||||
|
tokenToRevoke = githubInstallationToken;
|
||||||
|
}
|
||||||
const repoContext = parseRepoContext();
|
const repoContext = parseRepoContext();
|
||||||
|
|
||||||
|
const repoSettings = await fetchRepoSettings({
|
||||||
|
token: githubInstallationToken,
|
||||||
|
repoContext,
|
||||||
|
});
|
||||||
|
|
||||||
|
const agentName: AgentName = inputs.agent || repoSettings.defaultAgent || "claude";
|
||||||
|
|
||||||
|
const agent = agents[agentName];
|
||||||
|
|
||||||
setupGitAuth(githubInstallationToken, repoContext);
|
setupGitAuth(githubInstallationToken, repoContext);
|
||||||
|
|
||||||
// Create MCP config
|
const mcpServers = createMcpConfigs(githubInstallationToken);
|
||||||
const mcpConfig = JSON.parse(createMcpConfig(githubInstallationToken));
|
|
||||||
|
|
||||||
log.debug(`📋 MCP Config: ${JSON.stringify(mcpConfig, null, 2)}`);
|
log.debug(`📋 MCP Config: ${JSON.stringify(mcpServers, null, 2)}`);
|
||||||
|
|
||||||
// Extract mcpServers object from config
|
// Install agent CLI before running
|
||||||
const mcpServers = mcpConfig.mcpServers || {};
|
const cliPath = await agent.install();
|
||||||
|
|
||||||
log.info("Running Claude Agent SDK...");
|
log.info(`Running ${agentName}...`);
|
||||||
log.box(inputs.prompt, { title: "Prompt" });
|
log.box(inputs.prompt, { title: "Prompt" });
|
||||||
|
|
||||||
const result = await claude.run({
|
// TODO: check if `inputs.prompts` is JSON
|
||||||
|
// if yes, check if it's a webhook payload or toJSON(github.event)
|
||||||
|
// for webhook payloads, check the specified `agent` field
|
||||||
|
|
||||||
|
// Get API key based on agent type
|
||||||
|
|
||||||
|
const apiKey = inputs[agent.inputKey];
|
||||||
|
|
||||||
|
if (!apiKey) throw new Error(`${agent.inputKey} is required for ${agentName} agent`);
|
||||||
|
|
||||||
|
const result = await agent.run({
|
||||||
prompt: inputs.prompt,
|
prompt: inputs.prompt,
|
||||||
mcpServers,
|
mcpServers,
|
||||||
githubInstallationToken,
|
githubInstallationToken,
|
||||||
apiKey: inputs.anthropic_api_key!,
|
apiKey,
|
||||||
|
cliPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
@@ -70,5 +118,9 @@ export async function main(inputs: Inputs): Promise<MainResult> {
|
|||||||
success: false,
|
success: false,
|
||||||
error: errorMessage,
|
error: errorMessage,
|
||||||
};
|
};
|
||||||
|
} finally {
|
||||||
|
if (tokenToRevoke) {
|
||||||
|
await revokeInstallationToken(tokenToRevoke);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+101714
File diff suppressed because one or more lines are too long
+28
-1
@@ -6,7 +6,7 @@ export const Comment = type({
|
|||||||
body: type.string.describe("the comment body content"),
|
body: type.string.describe("the comment body content"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const CommentTool = tool({
|
export const CreateCommentTool = tool({
|
||||||
name: "create_issue_comment",
|
name: "create_issue_comment",
|
||||||
description: "Create a comment on a GitHub issue",
|
description: "Create a comment on a GitHub issue",
|
||||||
parameters: Comment,
|
parameters: Comment,
|
||||||
@@ -26,3 +26,30 @@ export const CommentTool = tool({
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const EditComment = type({
|
||||||
|
commentId: type.number.describe("the ID of the comment to edit"),
|
||||||
|
body: type.string.describe("the new comment body content"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const EditCommentTool = tool({
|
||||||
|
name: "edit_issue_comment",
|
||||||
|
description: "Edit a GitHub issue comment by its ID",
|
||||||
|
parameters: EditComment,
|
||||||
|
execute: contextualize(async ({ commentId, body }, ctx) => {
|
||||||
|
const result = await ctx.octokit.rest.issues.updateComment({
|
||||||
|
owner: ctx.owner,
|
||||||
|
repo: ctx.name,
|
||||||
|
comment_id: commentId,
|
||||||
|
body: body,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
commentId: result.data.id,
|
||||||
|
url: result.data.html_url,
|
||||||
|
body: result.data.body,
|
||||||
|
updatedAt: result.data.updated_at,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|||||||
+19
-18
@@ -1,32 +1,33 @@
|
|||||||
/**
|
/**
|
||||||
* Simple MCP configuration helper for adding our minimal GitHub comment server
|
* Simple MCP configuration helper for adding our minimal GitHub comment server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
||||||
import { fromHere } from "@ark/fs";
|
import { fromHere } from "@ark/fs";
|
||||||
import { parseRepoContext } from "../utils/github.ts";
|
import { parseRepoContext } from "../utils/github.ts";
|
||||||
|
|
||||||
const actionPath = fromHere("..");
|
export const ghPullfrogMcpName = "gh-pullfrog";
|
||||||
|
|
||||||
export const mcpServerName = "gh-pullfrog";
|
export type McpName = typeof ghPullfrogMcpName;
|
||||||
|
|
||||||
export function createMcpConfig(githubInstallationToken: string) {
|
export type McpConfigs = Record<McpName, McpServerConfig>;
|
||||||
|
|
||||||
|
export function createMcpConfigs(githubInstallationToken: string): McpConfigs {
|
||||||
const repoContext = parseRepoContext();
|
const repoContext = parseRepoContext();
|
||||||
const githubRepository = `${repoContext.owner}/${repoContext.name}`;
|
const githubRepository = `${repoContext.owner}/${repoContext.name}`;
|
||||||
|
|
||||||
return JSON.stringify(
|
// In production (GitHub Actions), mcp-server.js is in same directory as entry.js (where this is bundled)
|
||||||
{
|
// In development, server.ts is in the same directory as this file (config.ts)
|
||||||
mcpServers: {
|
const serverPath = process.env.GITHUB_ACTIONS ? fromHere("mcp-server.js") : fromHere("server.ts");
|
||||||
[mcpServerName]: {
|
|
||||||
command: "node",
|
return {
|
||||||
args: [`${actionPath}/mcp/server.ts`],
|
[ghPullfrogMcpName]: {
|
||||||
env: {
|
command: "node",
|
||||||
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
|
args: [serverPath],
|
||||||
GITHUB_REPOSITORY: githubRepository,
|
env: {
|
||||||
LOG_LEVEL: process.env.LOG_LEVEL,
|
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
|
||||||
},
|
GITHUB_REPOSITORY: githubRepository,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
null,
|
};
|
||||||
2
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-1
@@ -1,4 +1,6 @@
|
|||||||
|
import { execSync } from "node:child_process";
|
||||||
import { type } from "arktype";
|
import { type } from "arktype";
|
||||||
|
import { log } from "../utils/cli.ts";
|
||||||
import { contextualize, tool } from "./shared.ts";
|
import { contextualize, tool } from "./shared.ts";
|
||||||
|
|
||||||
export const PullRequestInfo = type({
|
export const PullRequestInfo = type({
|
||||||
@@ -7,7 +9,8 @@ export const PullRequestInfo = type({
|
|||||||
|
|
||||||
export const PullRequestInfoTool = tool({
|
export const PullRequestInfoTool = tool({
|
||||||
name: "get_pull_request",
|
name: "get_pull_request",
|
||||||
description: "Retrieve minimal information for a specific pull request by number.",
|
description:
|
||||||
|
"Retrieve PR information and automatically prepare the repository for review by fetching and checking out the PR branch.",
|
||||||
parameters: PullRequestInfo,
|
parameters: PullRequestInfo,
|
||||||
execute: contextualize(async ({ pull_number }, ctx) => {
|
execute: contextualize(async ({ pull_number }, ctx) => {
|
||||||
const pr = await ctx.octokit.rest.pulls.get({
|
const pr = await ctx.octokit.rest.pulls.get({
|
||||||
@@ -21,6 +24,20 @@ export const PullRequestInfoTool = tool({
|
|||||||
const baseBranch = data.base.ref;
|
const baseBranch = data.base.ref;
|
||||||
const headBranch = data.head.ref;
|
const headBranch = data.head.ref;
|
||||||
|
|
||||||
|
if (!baseBranch) {
|
||||||
|
throw new Error(`Base branch not found for PR #${pull_number}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automatically fetch and checkout branches for review
|
||||||
|
log.info(`Fetching base branch: origin/${baseBranch}`);
|
||||||
|
execSync(`git fetch origin ${baseBranch} --depth=20`, { stdio: "inherit" });
|
||||||
|
|
||||||
|
log.info(`Fetching PR branch: origin/${headBranch}`);
|
||||||
|
execSync(`git fetch origin ${headBranch}`, { stdio: "inherit" });
|
||||||
|
|
||||||
|
log.info(`Checking out PR branch: origin/${headBranch}`);
|
||||||
|
execSync(`git checkout origin/${headBranch}`, { stdio: "inherit" });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
number: data.number,
|
number: data.number,
|
||||||
url: data.html_url,
|
url: data.html_url,
|
||||||
|
|||||||
+52
-13
@@ -4,41 +4,80 @@ import { contextualize, tool } from "./shared.ts";
|
|||||||
|
|
||||||
export const Review = type({
|
export const Review = type({
|
||||||
pull_number: type.number.describe("The pull request number to review"),
|
pull_number: type.number.describe("The pull request number to review"),
|
||||||
event: type
|
|
||||||
.enumerated("APPROVE", "REQUEST_CHANGES", "COMMENT")
|
|
||||||
.describe("'APPROVE', 'REQUEST_CHANGES', or 'COMMENT' (the review action)"),
|
|
||||||
body: type.string
|
body: type.string
|
||||||
.describe("The body content for the review (required for REQUEST_CHANGES or COMMENT)")
|
.describe(
|
||||||
|
"Brief summary or general feedback that doesn't apply to specific code locations. Keep it concise - most feedback should be in the 'comments' array."
|
||||||
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
commit_id: type.string
|
commit_id: type.string
|
||||||
.describe("Optional SHA of the commit being reviewed. Defaults to latest.")
|
.describe("Optional SHA of the commit being reviewed. Defaults to latest.")
|
||||||
.optional(),
|
.optional(),
|
||||||
comments: type({
|
comments: type({
|
||||||
path: type.string.describe("The file path to comment on"),
|
path: type.string.describe("The file path to comment on (relative to repo root)"),
|
||||||
position: type.number.describe("The diff position in the file"),
|
line: type.number.describe(
|
||||||
body: type.string.describe("The comment text"),
|
"The line number in the file (use line numbers from the diff - usually the RIGHT side/new code)"
|
||||||
|
),
|
||||||
|
side: type
|
||||||
|
.enumerated("LEFT", "RIGHT")
|
||||||
|
.describe(
|
||||||
|
"Side of the diff: LEFT (old code) or RIGHT (new code). Defaults to RIGHT if not provided."
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
body: type.string.describe("The comment text for this specific line"),
|
||||||
|
start_line: type.number
|
||||||
|
.describe("Start line for multi-line comments (optional, for commenting on ranges)")
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
.array()
|
.array()
|
||||||
.describe("Array of draft review comments for specific lines, optional.")
|
.describe(
|
||||||
|
"REQUIRED: Array of inline comments for specific code issues. Use this for all location-specific feedback. Use 'git diff origin/<base>...origin/<head>' to find the correct line numbers (typically use the line numbers shown on the RIGHT side for new code, LEFT side for old code)."
|
||||||
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ReviewTool = tool({
|
export const ReviewTool = tool({
|
||||||
name: "submit_pull_request_review",
|
name: "submit_pull_request_review",
|
||||||
description:
|
description:
|
||||||
"Submit a review (approve, request changes, or comment) for an existing pull request.",
|
"Submit a review (approve, request changes, or comment) for an existing pull request. " +
|
||||||
|
"IMPORTANT: Use 'comments' array for ALL specific code issues at the line-level. " +
|
||||||
|
"Only use 'body' for a brief summary or feedback that doesn't apply to a specific location.",
|
||||||
parameters: Review,
|
parameters: Review,
|
||||||
execute: contextualize(async ({ pull_number, event, body, commit_id, comments = [] }, ctx) => {
|
execute: contextualize(async ({ pull_number, body, commit_id, comments = [] }, ctx) => {
|
||||||
|
// Get the PR to determine the head commit if commit_id not provided
|
||||||
|
const pr = await ctx.octokit.rest.pulls.get({
|
||||||
|
owner: ctx.owner,
|
||||||
|
repo: ctx.name,
|
||||||
|
pull_number,
|
||||||
|
});
|
||||||
|
|
||||||
// Compose the request
|
// Compose the request
|
||||||
const params: RestEndpointMethodTypes["pulls"]["createReview"]["parameters"] = {
|
const params: RestEndpointMethodTypes["pulls"]["createReview"]["parameters"] = {
|
||||||
owner: ctx.owner,
|
owner: ctx.owner,
|
||||||
repo: ctx.name,
|
repo: ctx.name,
|
||||||
pull_number,
|
pull_number,
|
||||||
event,
|
event: "COMMENT",
|
||||||
};
|
};
|
||||||
if (body) params.body = body;
|
if (body) params.body = body;
|
||||||
if (commit_id) params.commit_id = commit_id;
|
if (commit_id) {
|
||||||
if (comments.length > 0) params.comments = comments;
|
params.commit_id = commit_id;
|
||||||
|
} else {
|
||||||
|
params.commit_id = pr.data.head.sha;
|
||||||
|
}
|
||||||
|
if (comments.length > 0) {
|
||||||
|
type ReviewComment = (typeof params.comments & {})[number];
|
||||||
|
// Convert comments to the format expected by GitHub API
|
||||||
|
params.comments = comments.map((comment) => {
|
||||||
|
const reviewComment: ReviewComment = {
|
||||||
|
...comment,
|
||||||
|
};
|
||||||
|
reviewComment.side = comment.side || "RIGHT";
|
||||||
|
if (comment.start_line) {
|
||||||
|
reviewComment.start_line = comment.start_line;
|
||||||
|
reviewComment.start_side = comment.side || "RIGHT";
|
||||||
|
}
|
||||||
|
return reviewComment;
|
||||||
|
});
|
||||||
|
}
|
||||||
const result = await ctx.octokit.rest.pulls.createReview(params);
|
const result = await ctx.octokit.rest.pulls.createReview(params);
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
+9
-2
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
// Minimal GitHub Issue Comment MCP Server
|
// Minimal GitHub Issue Comment MCP Server
|
||||||
import { FastMCP } from "fastmcp";
|
import { FastMCP } from "fastmcp";
|
||||||
import { CommentTool } from "./comment.ts";
|
import { CreateCommentTool, EditCommentTool } from "./comment.ts";
|
||||||
import { IssueTool } from "./issue.ts";
|
import { IssueTool } from "./issue.ts";
|
||||||
import { PullRequestTool } from "./pr.ts";
|
import { PullRequestTool } from "./pr.ts";
|
||||||
import { PullRequestInfoTool } from "./prInfo.ts";
|
import { PullRequestInfoTool } from "./prInfo.ts";
|
||||||
@@ -13,6 +13,13 @@ const server = new FastMCP({
|
|||||||
version: "0.0.1",
|
version: "0.0.1",
|
||||||
});
|
});
|
||||||
|
|
||||||
addTools(server, [CommentTool, IssueTool, PullRequestTool, ReviewTool, PullRequestInfoTool]);
|
addTools(server, [
|
||||||
|
CreateCommentTool,
|
||||||
|
EditCommentTool,
|
||||||
|
IssueTool,
|
||||||
|
PullRequestTool,
|
||||||
|
ReviewTool,
|
||||||
|
PullRequestInfoTool,
|
||||||
|
]);
|
||||||
|
|
||||||
server.start();
|
server.start();
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { ghPullfrogMcpName } from "./mcp/config.ts";
|
||||||
|
|
||||||
|
export const modes = [
|
||||||
|
{
|
||||||
|
name: "Plan",
|
||||||
|
description:
|
||||||
|
"Create plans, break down tasks, outline steps, analyze requirements, understand scope of work, or provide task breakdowns",
|
||||||
|
prompt: `Follow these steps:
|
||||||
|
1. Create initial response comment using ${ghPullfrogMcpName}/create_issue_comment saying "I'll {summary of request}" and save the commentId
|
||||||
|
2. If the request requires understanding the codebase structure, dependencies, or conventions, gather relevant context (read AGENTS.md if it exists, understand how to install dependencies, run tests, run builds, and make changes according to best practices). Skip this step if the prompt is trivial and self-contained.
|
||||||
|
3. Analyze the request and break it down into clear, actionable tasks
|
||||||
|
4. Consider dependencies, potential challenges, and implementation order
|
||||||
|
5. Create a structured plan with clear milestones
|
||||||
|
6. Update your comment using ${ghPullfrogMcpName}/edit_issue_comment with the commentId to present the plan in a clear, organized format
|
||||||
|
7. Continue updating the same comment as needed (never create additional comments - always use edit_issue_comment)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Build",
|
||||||
|
description:
|
||||||
|
"Implement, build, create, or develop code changes; make specific changes to files or features; execute a plan; or handle tasks with specific implementation details",
|
||||||
|
prompt: `Follow these steps:
|
||||||
|
1. Create initial response comment using ${ghPullfrogMcpName}/create_issue_comment saying "I'll {summary of request}" and save the commentId
|
||||||
|
2. If the request requires understanding the codebase structure, dependencies, or conventions, gather relevant context (read AGENTS.md if it exists, understand how to install dependencies, run tests, run builds, and make changes according to best practices). Skip this step if the prompt is trivial and self-contained.
|
||||||
|
3. Understand the requirements and any existing plan
|
||||||
|
4. Make the necessary code changes
|
||||||
|
5. Test your changes to ensure they work correctly
|
||||||
|
6. Update your comment using ${ghPullfrogMcpName}/edit_issue_comment with the commentId to share progress and results
|
||||||
|
7. Continue updating the same comment as you make progress (never create additional comments - always use edit_issue_comment)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Review",
|
||||||
|
description:
|
||||||
|
"Review code, PRs, or implementations; provide feedback or suggestions; identify issues; or check code quality, style, and correctness",
|
||||||
|
prompt: `Follow these steps:
|
||||||
|
1. Create initial response comment using ${ghPullfrogMcpName}/create_issue_comment saying "I'll review this" and save the commentId
|
||||||
|
2. Get PR info with ${ghPullfrogMcpName}/get_pull_request (this automatically prepares the repository by fetching and checking out the PR branch)
|
||||||
|
3. View diff: git diff origin/<base>...origin/<head> (use line numbers from this for inline comments, replace <base> and <head> with 'base' and 'head' from PR info)
|
||||||
|
4. Read files from the checked-out PR branch to understand the implementation
|
||||||
|
5. Update your comment using ${ghPullfrogMcpName}/edit_issue_comment with findings as you review
|
||||||
|
6. When submitting review: use the 'comments' array for ALL specific code issues - include the file path and line position from the diff
|
||||||
|
7. Only use the 'body' field for a brief summary (1-2 sentences) or for feedback that doesn't apply to a specific code location
|
||||||
|
8. Continue updating the same comment as needed (never create additional comments - always use edit_issue_comment)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Prompt",
|
||||||
|
description:
|
||||||
|
"Fallback for tasks that don't fit other workflows, direct prompts via comments, or requests requiring general assistance without a specific workflow pattern",
|
||||||
|
prompt: `Follow these steps:
|
||||||
|
1. Create an initial "Progress Comment" using ${ghPullfrogMcpName}/create_issue_comment saying "I'll {summary of request}" and save the commentId
|
||||||
|
2. Perform the requested task. Only take action if you have high confidence that you understand what is being asked. If you are not sure, ask for clarification. Take stock of the tools at your disposal.
|
||||||
|
3. As your work progresses, update your Progress Comment to share progress and results. Using ${ghPullfrogMcpName}/edit_issue_comment and the commentId you saved earlier. Do not create additional comments unless you are explicitly asked to do so.
|
||||||
|
4. When you finish the task, update the Progress Comment a final time to confirm completion. If you created any issues, PRs, etc, include appropriate links to it here.`,
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
Generated
+960
@@ -0,0 +1,960 @@
|
|||||||
|
{
|
||||||
|
"name": "@pullfrog/action",
|
||||||
|
"version": "0.0.96",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "@pullfrog/action",
|
||||||
|
"version": "0.0.96",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.11.1",
|
||||||
|
"@anthropic-ai/claude-agent-sdk": "^0.1.26",
|
||||||
|
"@ark/fs": "0.53.0",
|
||||||
|
"@ark/util": "0.53.0",
|
||||||
|
"@octokit/rest": "^22.0.0",
|
||||||
|
"@octokit/webhooks-types": "^7.6.1",
|
||||||
|
"@standard-schema/spec": "1.0.0",
|
||||||
|
"arktype": "2.1.25",
|
||||||
|
"convex": "^1.29.0",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"execa": "^9.6.0",
|
||||||
|
"fastmcp": "^3.20.0",
|
||||||
|
"table": "^6.9.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^24.7.2",
|
||||||
|
"arg": "^5.0.2",
|
||||||
|
"esbuild": "^0.25.9",
|
||||||
|
"husky": "^9.0.0",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/@actions+core@1.11.1/node_modules/@actions/core": {
|
||||||
|
"version": "1.11.1",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/exec": "^1.1.1",
|
||||||
|
"@actions/http-client": "^2.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^16.18.112"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/@anthropic-ai+claude-agent-sdk@0.1.26_zod@3.25.76/node_modules/@anthropic-ai/claude-agent-sdk": {
|
||||||
|
"version": "0.1.26",
|
||||||
|
"license": "SEE LICENSE IN README.md",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-darwin-arm64": "^0.33.5",
|
||||||
|
"@img/sharp-darwin-x64": "^0.33.5",
|
||||||
|
"@img/sharp-linux-arm": "^0.33.5",
|
||||||
|
"@img/sharp-linux-arm64": "^0.33.5",
|
||||||
|
"@img/sharp-linux-x64": "^0.33.5",
|
||||||
|
"@img/sharp-win32-x64": "^0.33.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"zod": "^3.24.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/@ark+fs@0.53.0/node_modules/@ark/fs": {
|
||||||
|
"version": "0.53.0",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/@ark+util@0.53.0/node_modules/@ark/util": {
|
||||||
|
"version": "0.53.0",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/@octokit+rest@22.0.0/node_modules/@octokit/rest": {
|
||||||
|
"version": "22.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@octokit/core": "^7.0.2",
|
||||||
|
"@octokit/plugin-paginate-rest": "^13.0.1",
|
||||||
|
"@octokit/plugin-request-log": "^6.0.0",
|
||||||
|
"@octokit/plugin-rest-endpoint-methods": "^16.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@octokit/auth-action": "^6.0.1",
|
||||||
|
"@octokit/auth-app": "^8.0.1",
|
||||||
|
"@octokit/fixtures-server": "^8.1.0",
|
||||||
|
"@octokit/request": "^10.0.0",
|
||||||
|
"@octokit/tsconfig": "^4.0.0",
|
||||||
|
"@types/node": "^22.0.0",
|
||||||
|
"@vitest/coverage-v8": "^3.0.0",
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
|
"fetch-mock": "^12.0.0",
|
||||||
|
"glob": "^11.0.0",
|
||||||
|
"nock": "^14.0.0-beta.8",
|
||||||
|
"prettier": "^3.2.4",
|
||||||
|
"semantic-release-plugin-update-version-in-files": "^2.0.0",
|
||||||
|
"typescript": "^5.3.3",
|
||||||
|
"undici": "^6.4.0",
|
||||||
|
"vitest": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/@octokit+webhooks-types@7.6.1/node_modules/@octokit/webhooks-types": {
|
||||||
|
"version": "7.6.1",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/@standard-schema+spec@1.0.0/node_modules/@standard-schema/spec": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"tsup": "^8.3.0",
|
||||||
|
"typescript": "^5.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/@types+node@24.7.2/node_modules/@types/node": {
|
||||||
|
"version": "24.7.2",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~7.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/arg@5.0.2/node_modules/arg": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"chai": "^4.1.1",
|
||||||
|
"jest": "^27.0.6",
|
||||||
|
"prettier": "^2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/arktype@2.1.25/node_modules/arktype": {
|
||||||
|
"version": "2.1.25",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@ark/schema": "0.53.0",
|
||||||
|
"@ark/util": "0.53.0",
|
||||||
|
"arkregex": "0.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv": {
|
||||||
|
"version": "17.2.3",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.11.3",
|
||||||
|
"decache": "^4.6.2",
|
||||||
|
"sinon": "^14.0.1",
|
||||||
|
"standard": "^17.0.0",
|
||||||
|
"standard-version": "^9.5.0",
|
||||||
|
"tap": "^19.2.0",
|
||||||
|
"typescript": "^4.8.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/esbuild@0.25.10/node_modules/esbuild": {
|
||||||
|
"version": "0.25.10",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/aix-ppc64": "0.25.10",
|
||||||
|
"@esbuild/android-arm": "0.25.10",
|
||||||
|
"@esbuild/android-arm64": "0.25.10",
|
||||||
|
"@esbuild/android-x64": "0.25.10",
|
||||||
|
"@esbuild/darwin-arm64": "0.25.10",
|
||||||
|
"@esbuild/darwin-x64": "0.25.10",
|
||||||
|
"@esbuild/freebsd-arm64": "0.25.10",
|
||||||
|
"@esbuild/freebsd-x64": "0.25.10",
|
||||||
|
"@esbuild/linux-arm": "0.25.10",
|
||||||
|
"@esbuild/linux-arm64": "0.25.10",
|
||||||
|
"@esbuild/linux-ia32": "0.25.10",
|
||||||
|
"@esbuild/linux-loong64": "0.25.10",
|
||||||
|
"@esbuild/linux-mips64el": "0.25.10",
|
||||||
|
"@esbuild/linux-ppc64": "0.25.10",
|
||||||
|
"@esbuild/linux-riscv64": "0.25.10",
|
||||||
|
"@esbuild/linux-s390x": "0.25.10",
|
||||||
|
"@esbuild/linux-x64": "0.25.10",
|
||||||
|
"@esbuild/netbsd-arm64": "0.25.10",
|
||||||
|
"@esbuild/netbsd-x64": "0.25.10",
|
||||||
|
"@esbuild/openbsd-arm64": "0.25.10",
|
||||||
|
"@esbuild/openbsd-x64": "0.25.10",
|
||||||
|
"@esbuild/openharmony-arm64": "0.25.10",
|
||||||
|
"@esbuild/sunos-x64": "0.25.10",
|
||||||
|
"@esbuild/win32-arm64": "0.25.10",
|
||||||
|
"@esbuild/win32-ia32": "0.25.10",
|
||||||
|
"@esbuild/win32-x64": "0.25.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/execa@9.6.0/node_modules/execa": {
|
||||||
|
"version": "9.6.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@sindresorhus/merge-streams": "^4.0.0",
|
||||||
|
"cross-spawn": "^7.0.6",
|
||||||
|
"figures": "^6.1.0",
|
||||||
|
"get-stream": "^9.0.0",
|
||||||
|
"human-signals": "^8.0.1",
|
||||||
|
"is-plain-obj": "^4.1.0",
|
||||||
|
"is-stream": "^4.0.1",
|
||||||
|
"npm-run-path": "^6.0.0",
|
||||||
|
"pretty-ms": "^9.2.0",
|
||||||
|
"signal-exit": "^4.1.0",
|
||||||
|
"strip-final-newline": "^4.0.0",
|
||||||
|
"yoctocolors": "^2.1.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^22.15.21",
|
||||||
|
"ava": "^6.3.0",
|
||||||
|
"c8": "^10.1.3",
|
||||||
|
"get-node": "^15.0.3",
|
||||||
|
"is-in-ci": "^1.0.0",
|
||||||
|
"is-running": "^2.1.0",
|
||||||
|
"log-process-errors": "^12.0.1",
|
||||||
|
"path-exists": "^5.0.0",
|
||||||
|
"path-key": "^4.0.0",
|
||||||
|
"tempfile": "^5.0.0",
|
||||||
|
"tsd": "^0.32.0",
|
||||||
|
"typescript": "^5.8.3",
|
||||||
|
"which": "^5.0.0",
|
||||||
|
"xo": "^0.60.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.19.0 || >=20.5.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/fastmcp@3.20.0_arktype@2.1.25_effect@3.16.12/node_modules/fastmcp": {
|
||||||
|
"version": "3.20.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@modelcontextprotocol/sdk": "^1.17.2",
|
||||||
|
"@standard-schema/spec": "^1.0.0",
|
||||||
|
"execa": "^9.6.0",
|
||||||
|
"file-type": "^21.0.0",
|
||||||
|
"fuse.js": "^7.1.0",
|
||||||
|
"mcp-proxy": "^5.8.1",
|
||||||
|
"strict-event-emitter-types": "^2.0.0",
|
||||||
|
"undici": "^7.13.0",
|
||||||
|
"uri-templates": "^0.2.0",
|
||||||
|
"xsschema": "0.3.5",
|
||||||
|
"yargs": "^18.0.0",
|
||||||
|
"zod": "^3.25.76",
|
||||||
|
"zod-to-json-schema": "^3.24.6"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"fastmcp": "dist/bin/fastmcp.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.33.0",
|
||||||
|
"@modelcontextprotocol/inspector": "^0.16.2",
|
||||||
|
"@sebbo2002/semantic-release-jsr": "^3.0.1",
|
||||||
|
"@tsconfig/node22": "^22.0.2",
|
||||||
|
"@types/node": "^24.2.1",
|
||||||
|
"@types/uri-templates": "^0.1.34",
|
||||||
|
"@types/yargs": "^17.0.33",
|
||||||
|
"@valibot/to-json-schema": "^1.3.0",
|
||||||
|
"@wong2/mcp-cli": "^1.13.0",
|
||||||
|
"arktype": "^2.1.20",
|
||||||
|
"eslint": "^9.33.0",
|
||||||
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
"eslint-plugin-perfectionist": "^4.15.0",
|
||||||
|
"eslint-plugin-prettier": "^5.5.4",
|
||||||
|
"eventsource-client": "^1.1.4",
|
||||||
|
"get-port-please": "^3.2.0",
|
||||||
|
"jiti": "^2.5.1",
|
||||||
|
"jsr": "^0.13.5",
|
||||||
|
"prettier": "^3.6.2",
|
||||||
|
"semantic-release": "^24.2.7",
|
||||||
|
"tsup": "^8.5.0",
|
||||||
|
"typescript": "^5.9.2",
|
||||||
|
"typescript-eslint": "^8.39.0",
|
||||||
|
"valibot": "^1.1.0",
|
||||||
|
"vitest": "^3.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/husky@9.1.7/node_modules/husky": {
|
||||||
|
"version": "9.1.7",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"husky": "bin.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/typicode"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/table@6.9.0/node_modules/table": {
|
||||||
|
"version": "6.9.0",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": "^8.0.1",
|
||||||
|
"lodash.truncate": "^4.4.2",
|
||||||
|
"slice-ansi": "^4.0.0",
|
||||||
|
"string-width": "^4.2.3",
|
||||||
|
"strip-ansi": "^6.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/chai": "^4.2.16",
|
||||||
|
"@types/lodash.mapvalues": "^4.6.6",
|
||||||
|
"@types/lodash.truncate": "^4.4.6",
|
||||||
|
"@types/mocha": "^9.0.0",
|
||||||
|
"@types/node": "^14.14.37",
|
||||||
|
"@types/sinon": "^10.0.0",
|
||||||
|
"@types/slice-ansi": "^4.0.0",
|
||||||
|
"ajv-cli": "^5.0.0",
|
||||||
|
"ajv-keywords": "^5.0.0",
|
||||||
|
"chai": "^4.2.0",
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"coveralls": "^3.1.0",
|
||||||
|
"eslint": "^7.32.0",
|
||||||
|
"eslint-config-canonical": "^25.0.0",
|
||||||
|
"gitdown": "^3.1.4",
|
||||||
|
"husky": "^4.3.6",
|
||||||
|
"js-beautify": "^1.14.0",
|
||||||
|
"lodash.mapvalues": "^4.6.0",
|
||||||
|
"mkdirp": "^1.0.4",
|
||||||
|
"mocha": "^8.2.1",
|
||||||
|
"nyc": "^15.1.0",
|
||||||
|
"semantic-release": "^17.3.1",
|
||||||
|
"sinon": "^12.0.1",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
|
"typescript": "4.5.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript": {
|
||||||
|
"version": "5.9.3",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@dprint/formatter": "^0.4.1",
|
||||||
|
"@dprint/typescript": "0.93.4",
|
||||||
|
"@esfx/canceltoken": "^1.0.0",
|
||||||
|
"@eslint/js": "^9.20.0",
|
||||||
|
"@octokit/rest": "^21.1.1",
|
||||||
|
"@types/chai": "^4.3.20",
|
||||||
|
"@types/diff": "^7.0.1",
|
||||||
|
"@types/minimist": "^1.2.5",
|
||||||
|
"@types/mocha": "^10.0.10",
|
||||||
|
"@types/ms": "^0.7.34",
|
||||||
|
"@types/node": "latest",
|
||||||
|
"@types/source-map-support": "^0.5.10",
|
||||||
|
"@types/which": "^3.0.4",
|
||||||
|
"@typescript-eslint/rule-tester": "^8.24.1",
|
||||||
|
"@typescript-eslint/type-utils": "^8.24.1",
|
||||||
|
"@typescript-eslint/utils": "^8.24.1",
|
||||||
|
"azure-devops-node-api": "^14.1.0",
|
||||||
|
"c8": "^10.1.3",
|
||||||
|
"chai": "^4.5.0",
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
|
"diff": "^7.0.0",
|
||||||
|
"dprint": "^0.49.0",
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
|
"eslint": "^9.20.1",
|
||||||
|
"eslint-formatter-autolinkable-stylish": "^1.4.0",
|
||||||
|
"eslint-plugin-regexp": "^2.7.0",
|
||||||
|
"fast-xml-parser": "^4.5.2",
|
||||||
|
"glob": "^10.4.5",
|
||||||
|
"globals": "^15.15.0",
|
||||||
|
"hereby": "^1.10.0",
|
||||||
|
"jsonc-parser": "^3.3.1",
|
||||||
|
"knip": "^5.44.4",
|
||||||
|
"minimist": "^1.2.8",
|
||||||
|
"mocha": "^10.8.2",
|
||||||
|
"mocha-fivemat-progress-reporter": "^0.1.0",
|
||||||
|
"monocart-coverage-reports": "^2.12.1",
|
||||||
|
"ms": "^2.1.3",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"playwright": "^1.50.1",
|
||||||
|
"source-map-support": "^0.5.21",
|
||||||
|
"tslib": "^2.8.1",
|
||||||
|
"typescript": "^5.7.3",
|
||||||
|
"typescript-eslint": "^8.24.1",
|
||||||
|
"which": "^3.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@actions/core": {
|
||||||
|
"resolved": "../node_modules/.pnpm/@actions+core@1.11.1/node_modules/@actions/core",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/@anthropic-ai/claude-agent-sdk": {
|
||||||
|
"resolved": "../node_modules/.pnpm/@anthropic-ai+claude-agent-sdk@0.1.26_zod@3.25.76/node_modules/@anthropic-ai/claude-agent-sdk",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/@ark/fs": {
|
||||||
|
"resolved": "../node_modules/.pnpm/@ark+fs@0.53.0/node_modules/@ark/fs",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/@ark/util": {
|
||||||
|
"resolved": "../node_modules/.pnpm/@ark+util@0.53.0/node_modules/@ark/util",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"aix"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-x64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==",
|
||||||
|
"cpu": [
|
||||||
|
"loong64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==",
|
||||||
|
"cpu": [
|
||||||
|
"mips64el"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-x64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-arm64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-arm64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"sunos"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-x64": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/rest": {
|
||||||
|
"resolved": "../node_modules/.pnpm/@octokit+rest@22.0.0/node_modules/@octokit/rest",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/@octokit/webhooks-types": {
|
||||||
|
"resolved": "../node_modules/.pnpm/@octokit+webhooks-types@7.6.1/node_modules/@octokit/webhooks-types",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/@standard-schema/spec": {
|
||||||
|
"resolved": "../node_modules/.pnpm/@standard-schema+spec@1.0.0/node_modules/@standard-schema/spec",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"resolved": "../node_modules/.pnpm/@types+node@24.7.2/node_modules/@types/node",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/arg": {
|
||||||
|
"resolved": "../node_modules/.pnpm/arg@5.0.2/node_modules/arg",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/arktype": {
|
||||||
|
"resolved": "../node_modules/.pnpm/arktype@2.1.25/node_modules/arktype",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/convex": {
|
||||||
|
"version": "1.29.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/convex/-/convex-1.29.0.tgz",
|
||||||
|
"integrity": "sha512-uoIPXRKIp2eLCkkR9WJ2vc9NtgQtx8Pml59WPUahwbrd5EuW2WLI/cf2E7XrUzOSifdQC3kJZepisk4wJNTJaA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"esbuild": "0.25.4",
|
||||||
|
"prettier": "^3.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"convex": "bin/main.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0",
|
||||||
|
"npm": ">=7.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@auth0/auth0-react": "^2.0.1",
|
||||||
|
"@clerk/clerk-react": "^4.12.8 || ^5.0.0",
|
||||||
|
"react": "^18.0.0 || ^19.0.0-0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@auth0/auth0-react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@clerk/clerk-react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/convex/node_modules/esbuild": {
|
||||||
|
"version": "0.25.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz",
|
||||||
|
"integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/aix-ppc64": "0.25.4",
|
||||||
|
"@esbuild/android-arm": "0.25.4",
|
||||||
|
"@esbuild/android-arm64": "0.25.4",
|
||||||
|
"@esbuild/android-x64": "0.25.4",
|
||||||
|
"@esbuild/darwin-arm64": "0.25.4",
|
||||||
|
"@esbuild/darwin-x64": "0.25.4",
|
||||||
|
"@esbuild/freebsd-arm64": "0.25.4",
|
||||||
|
"@esbuild/freebsd-x64": "0.25.4",
|
||||||
|
"@esbuild/linux-arm": "0.25.4",
|
||||||
|
"@esbuild/linux-arm64": "0.25.4",
|
||||||
|
"@esbuild/linux-ia32": "0.25.4",
|
||||||
|
"@esbuild/linux-loong64": "0.25.4",
|
||||||
|
"@esbuild/linux-mips64el": "0.25.4",
|
||||||
|
"@esbuild/linux-ppc64": "0.25.4",
|
||||||
|
"@esbuild/linux-riscv64": "0.25.4",
|
||||||
|
"@esbuild/linux-s390x": "0.25.4",
|
||||||
|
"@esbuild/linux-x64": "0.25.4",
|
||||||
|
"@esbuild/netbsd-arm64": "0.25.4",
|
||||||
|
"@esbuild/netbsd-x64": "0.25.4",
|
||||||
|
"@esbuild/openbsd-arm64": "0.25.4",
|
||||||
|
"@esbuild/openbsd-x64": "0.25.4",
|
||||||
|
"@esbuild/sunos-x64": "0.25.4",
|
||||||
|
"@esbuild/win32-arm64": "0.25.4",
|
||||||
|
"@esbuild/win32-ia32": "0.25.4",
|
||||||
|
"@esbuild/win32-x64": "0.25.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dotenv": {
|
||||||
|
"resolved": "../node_modules/.pnpm/dotenv@17.2.3/node_modules/dotenv",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/esbuild": {
|
||||||
|
"resolved": "../node_modules/.pnpm/esbuild@0.25.10/node_modules/esbuild",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/execa": {
|
||||||
|
"resolved": "../node_modules/.pnpm/execa@9.6.0/node_modules/execa",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/fastmcp": {
|
||||||
|
"resolved": "../node_modules/.pnpm/fastmcp@3.20.0_arktype@2.1.25_effect@3.16.12/node_modules/fastmcp",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/husky": {
|
||||||
|
"resolved": "../node_modules/.pnpm/husky@9.1.7/node_modules/husky",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin/prettier.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/table": {
|
||||||
|
"resolved": "../node_modules/.pnpm/table@6.9.0/node_modules/table",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"resolved": "../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript",
|
||||||
|
"link": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-7
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@pullfrog/action",
|
"name": "@pullfrog/action",
|
||||||
"version": "0.0.66",
|
"version": "0.0.99",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
"index.js",
|
"index.js",
|
||||||
@@ -15,27 +15,34 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
|
"build": "node esbuild.config.js",
|
||||||
"play": "node play.ts",
|
"play": "node play.ts",
|
||||||
|
"scratch": "node scratch.ts",
|
||||||
"upDeps": "pnpm up --latest",
|
"upDeps": "pnpm up --latest",
|
||||||
"lock": "pnpm --ignore-workspace install"
|
"lock": "pnpm --ignore-workspace install",
|
||||||
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^1.11.1",
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.1.26",
|
"@anthropic-ai/claude-agent-sdk": "0.1.37",
|
||||||
"@ark/fs": "0.50.0",
|
"@openai/codex-sdk": "0.58.0",
|
||||||
"@ark/util": "0.50.0",
|
"@ark/fs": "0.53.0",
|
||||||
|
"@ark/util": "0.53.0",
|
||||||
"@octokit/rest": "^22.0.0",
|
"@octokit/rest": "^22.0.0",
|
||||||
"@octokit/webhooks-types": "^7.6.1",
|
"@octokit/webhooks-types": "^7.6.1",
|
||||||
"@standard-schema/spec": "1.0.0",
|
"@standard-schema/spec": "1.0.0",
|
||||||
"arktype": "^2.1.25",
|
"arktype": "2.1.25",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"execa": "^9.6.0",
|
"execa": "^9.6.0",
|
||||||
"fastmcp": "^3.20.0",
|
"fastmcp": "^3.20.0",
|
||||||
"table": "^6.9.0"
|
"table": "^6.9.0",
|
||||||
|
"zod": "^3.25.76"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^24.7.2",
|
"@types/node": "^24.7.2",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
|
"esbuild": "^0.25.9",
|
||||||
|
"husky": "^9.0.0",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { fromHere } from "@ark/fs";
|
|||||||
import arg from "arg";
|
import arg from "arg";
|
||||||
import { config } from "dotenv";
|
import { config } from "dotenv";
|
||||||
import { type Inputs, main } from "./main.ts";
|
import { type Inputs, main } from "./main.ts";
|
||||||
import packageJson from "./package.json" with { type: "json" };
|
|
||||||
import { log } from "./utils/cli.ts";
|
import { log } from "./utils/cli.ts";
|
||||||
import { setupTestRepo } from "./utils/setup.ts";
|
import { setupTestRepo } from "./utils/setup.ts";
|
||||||
|
|
||||||
@@ -15,22 +14,17 @@ export async function run(
|
|||||||
prompt: string
|
prompt: string
|
||||||
): Promise<{ success: boolean; output?: string | undefined; error?: string | undefined }> {
|
): Promise<{ success: boolean; output?: string | undefined; error?: string | undefined }> {
|
||||||
try {
|
try {
|
||||||
log.info(`🐸 Running pullfrog/action@${packageJson.version}...`);
|
|
||||||
|
|
||||||
const tempDir = join(process.cwd(), ".temp");
|
const tempDir = join(process.cwd(), ".temp");
|
||||||
setupTestRepo({ tempDir, forceClean: true });
|
setupTestRepo({ tempDir, forceClean: true });
|
||||||
|
|
||||||
const originalCwd = process.cwd();
|
const originalCwd = process.cwd();
|
||||||
process.chdir(tempDir);
|
process.chdir(tempDir);
|
||||||
|
|
||||||
log.info("🚀 Running action with prompt...");
|
|
||||||
log.separator();
|
|
||||||
log.box(prompt, { title: "Prompt" });
|
|
||||||
log.separator();
|
|
||||||
|
|
||||||
const inputs: Inputs = {
|
const inputs: Inputs = {
|
||||||
prompt,
|
prompt,
|
||||||
|
openai_api_key: process.env.OPENAI_API_KEY,
|
||||||
anthropic_api_key: process.env.ANTHROPIC_API_KEY,
|
anthropic_api_key: process.env.ANTHROPIC_API_KEY,
|
||||||
|
agent: "codex",
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await main(inputs);
|
const result = await main(inputs);
|
||||||
@@ -86,7 +80,8 @@ Examples:
|
|||||||
if (args["--raw"]) {
|
if (args["--raw"]) {
|
||||||
prompt = args["--raw"];
|
prompt = args["--raw"];
|
||||||
} else {
|
} else {
|
||||||
const filePath = args._[0] || "fixtures/basic.txt";
|
const filePath = args._[0] || "basic.txt";
|
||||||
|
|
||||||
const ext = extname(filePath).toLowerCase();
|
const ext = extname(filePath).toLowerCase();
|
||||||
let resolvedPath: string;
|
let resolvedPath: string;
|
||||||
|
|
||||||
|
|||||||
Generated
+306
-18
@@ -12,25 +12,28 @@ importers:
|
|||||||
specifier: ^1.11.1
|
specifier: ^1.11.1
|
||||||
version: 1.11.1
|
version: 1.11.1
|
||||||
'@anthropic-ai/claude-agent-sdk':
|
'@anthropic-ai/claude-agent-sdk':
|
||||||
specifier: ^0.1.26
|
specifier: 0.1.37
|
||||||
version: 0.1.30(zod@3.25.76)
|
version: 0.1.37(zod@3.25.76)
|
||||||
'@ark/fs':
|
'@ark/fs':
|
||||||
specifier: 0.50.0
|
specifier: 0.53.0
|
||||||
version: 0.50.0
|
version: 0.53.0
|
||||||
'@ark/util':
|
'@ark/util':
|
||||||
specifier: 0.50.0
|
specifier: 0.53.0
|
||||||
version: 0.50.0
|
version: 0.53.0
|
||||||
'@octokit/rest':
|
'@octokit/rest':
|
||||||
specifier: ^22.0.0
|
specifier: ^22.0.0
|
||||||
version: 22.0.0
|
version: 22.0.0
|
||||||
'@octokit/webhooks-types':
|
'@octokit/webhooks-types':
|
||||||
specifier: ^7.6.1
|
specifier: ^7.6.1
|
||||||
version: 7.6.1
|
version: 7.6.1
|
||||||
|
'@openai/codex-sdk':
|
||||||
|
specifier: 0.58.0
|
||||||
|
version: 0.58.0
|
||||||
'@standard-schema/spec':
|
'@standard-schema/spec':
|
||||||
specifier: 1.0.0
|
specifier: 1.0.0
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
arktype:
|
arktype:
|
||||||
specifier: ^2.1.25
|
specifier: 2.1.25
|
||||||
version: 2.1.25
|
version: 2.1.25
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^17.2.3
|
specifier: ^17.2.3
|
||||||
@@ -44,6 +47,9 @@ importers:
|
|||||||
table:
|
table:
|
||||||
specifier: ^6.9.0
|
specifier: ^6.9.0
|
||||||
version: 6.9.0
|
version: 6.9.0
|
||||||
|
zod:
|
||||||
|
specifier: ^3.25.76
|
||||||
|
version: 3.25.76
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^24.7.2
|
specifier: ^24.7.2
|
||||||
@@ -51,6 +57,12 @@ importers:
|
|||||||
arg:
|
arg:
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.0.2
|
version: 5.0.2
|
||||||
|
esbuild:
|
||||||
|
specifier: ^0.25.9
|
||||||
|
version: 0.25.12
|
||||||
|
husky:
|
||||||
|
specifier: ^9.0.0
|
||||||
|
version: 9.1.7
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.9.3
|
specifier: ^5.9.3
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
@@ -69,27 +81,180 @@ 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==}
|
||||||
|
|
||||||
'@anthropic-ai/claude-agent-sdk@0.1.30':
|
'@anthropic-ai/claude-agent-sdk@0.1.37':
|
||||||
resolution: {integrity: sha512-lo1tqxCr2vygagFp6kUMHKSN6AAWlULCskwGKtLB/JcIXy/8H8GsLSKX54anTsvc9mBbCR8wWASdFmiiL9NSKA==}
|
resolution: {integrity: sha512-LMfqMIPLTz0vRhpcO7hpPJ5L6Bg24y5/PaqZvwAUNZ/GR3OAl7xmJR7IryIR6m8Pyd/6Hs2yBU8j86Os+wHFQQ==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
zod: ^3.24.1
|
zod: ^3.24.1
|
||||||
|
|
||||||
'@ark/fs@0.50.0':
|
'@ark/fs@0.53.0':
|
||||||
resolution: {integrity: sha512-6OrxNt2T+/pL4RUMZK/aiVRLIS3acNs5uSpHDyZAP6+OXwXchFSQ1lJTH+uuGBlDWeQxPD7VmymYXLF5s1Eyhw==}
|
resolution: {integrity: sha512-XL0EbBAZgyy+j9aPhftYaBsbKAW5PTNSKCN6oLRRdrHuHPSAZgR6765/z0YZGhPxHEUNmq0vBoSk8yOLk91dNQ==}
|
||||||
|
|
||||||
'@ark/schema@0.53.0':
|
'@ark/schema@0.53.0':
|
||||||
resolution: {integrity: sha512-1PB7RThUiTlmIu8jbSurPrhHpVixPd4C+xNBUF/HrjIENCeDcAMg36n5mpMzED7OQGDVIzpfXXiMnaTiutjHJw==}
|
resolution: {integrity: sha512-1PB7RThUiTlmIu8jbSurPrhHpVixPd4C+xNBUF/HrjIENCeDcAMg36n5mpMzED7OQGDVIzpfXXiMnaTiutjHJw==}
|
||||||
|
|
||||||
'@ark/util@0.50.0':
|
|
||||||
resolution: {integrity: sha512-tIkgIMVRpkfXRQIEf0G2CJryZVtHVrqcWHMDa5QKo0OEEBu0tHkRSIMm4Ln8cd8Bn9TPZtvc/kE2Gma8RESPSg==}
|
|
||||||
|
|
||||||
'@ark/util@0.53.0':
|
'@ark/util@0.53.0':
|
||||||
resolution: {integrity: sha512-TGn4gLlA6dJcQiqrtCtd88JhGb2XBHo6qIejsDre+nxpGuUVW4G3YZGVrwjNBTO0EyR+ykzIo4joHJzOj+/cpA==}
|
resolution: {integrity: sha512-TGn4gLlA6dJcQiqrtCtd88JhGb2XBHo6qIejsDre+nxpGuUVW4G3YZGVrwjNBTO0EyR+ykzIo4joHJzOj+/cpA==}
|
||||||
|
|
||||||
'@borewit/text-codec@0.1.1':
|
'@borewit/text-codec@0.1.1':
|
||||||
resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==}
|
resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==}
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [aix]
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.25.12':
|
||||||
|
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.25.12':
|
||||||
|
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.25.12':
|
||||||
|
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.25.12':
|
||||||
|
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [mips64el]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.25.12':
|
||||||
|
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [sunos]
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.25.12':
|
||||||
|
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
'@fastify/busboy@2.1.1':
|
'@fastify/busboy@2.1.1':
|
||||||
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
|
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@@ -214,6 +379,10 @@ packages:
|
|||||||
'@octokit/webhooks-types@7.6.1':
|
'@octokit/webhooks-types@7.6.1':
|
||||||
resolution: {integrity: sha512-S8u2cJzklBC0FgTwWVLaM8tMrDuDMVE4xiTK4EYXM9GntyvrdbSoxqDQa+Fh57CCNApyIpyeqPhhFEmHPfrXgw==}
|
resolution: {integrity: sha512-S8u2cJzklBC0FgTwWVLaM8tMrDuDMVE4xiTK4EYXM9GntyvrdbSoxqDQa+Fh57CCNApyIpyeqPhhFEmHPfrXgw==}
|
||||||
|
|
||||||
|
'@openai/codex-sdk@0.58.0':
|
||||||
|
resolution: {integrity: sha512-Z5vK294gUS9cn7bpU/lJtgzqJy1UqIGee7WMP+1Z4a6AxDcTxFCLZI4YkH9praJfrgoj5bFeu+3V9HIoBBTzcw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
'@sec-ant/readable-stream@0.4.1':
|
'@sec-ant/readable-stream@0.4.1':
|
||||||
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
|
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
|
||||||
|
|
||||||
@@ -373,6 +542,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
esbuild@0.25.12:
|
||||||
|
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
escalade@3.2.0:
|
escalade@3.2.0:
|
||||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -492,6 +666,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==}
|
resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==}
|
||||||
engines: {node: '>=18.18.0'}
|
engines: {node: '>=18.18.0'}
|
||||||
|
|
||||||
|
husky@9.1.7:
|
||||||
|
resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
iconv-lite@0.6.3:
|
iconv-lite@0.6.3:
|
||||||
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
|
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -868,7 +1047,7 @@ snapshots:
|
|||||||
|
|
||||||
'@actions/io@1.1.3': {}
|
'@actions/io@1.1.3': {}
|
||||||
|
|
||||||
'@anthropic-ai/claude-agent-sdk@0.1.30(zod@3.25.76)':
|
'@anthropic-ai/claude-agent-sdk@0.1.37(zod@3.25.76)':
|
||||||
dependencies:
|
dependencies:
|
||||||
zod: 3.25.76
|
zod: 3.25.76
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@@ -879,18 +1058,94 @@ snapshots:
|
|||||||
'@img/sharp-linux-x64': 0.33.5
|
'@img/sharp-linux-x64': 0.33.5
|
||||||
'@img/sharp-win32-x64': 0.33.5
|
'@img/sharp-win32-x64': 0.33.5
|
||||||
|
|
||||||
'@ark/fs@0.50.0': {}
|
'@ark/fs@0.53.0': {}
|
||||||
|
|
||||||
'@ark/schema@0.53.0':
|
'@ark/schema@0.53.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ark/util': 0.53.0
|
'@ark/util': 0.53.0
|
||||||
|
|
||||||
'@ark/util@0.50.0': {}
|
|
||||||
|
|
||||||
'@ark/util@0.53.0': {}
|
'@ark/util@0.53.0': {}
|
||||||
|
|
||||||
'@borewit/text-codec@0.1.1': {}
|
'@borewit/text-codec@0.1.1': {}
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@fastify/busboy@2.1.1': {}
|
'@fastify/busboy@2.1.1': {}
|
||||||
|
|
||||||
'@img/sharp-darwin-arm64@0.33.5':
|
'@img/sharp-darwin-arm64@0.33.5':
|
||||||
@@ -1017,6 +1272,8 @@ snapshots:
|
|||||||
|
|
||||||
'@octokit/webhooks-types@7.6.1': {}
|
'@octokit/webhooks-types@7.6.1': {}
|
||||||
|
|
||||||
|
'@openai/codex-sdk@0.58.0': {}
|
||||||
|
|
||||||
'@sec-ant/readable-stream@0.4.1': {}
|
'@sec-ant/readable-stream@0.4.1': {}
|
||||||
|
|
||||||
'@sindresorhus/merge-streams@4.0.0': {}
|
'@sindresorhus/merge-streams@4.0.0': {}
|
||||||
@@ -1171,6 +1428,35 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
|
|
||||||
|
esbuild@0.25.12:
|
||||||
|
optionalDependencies:
|
||||||
|
'@esbuild/aix-ppc64': 0.25.12
|
||||||
|
'@esbuild/android-arm': 0.25.12
|
||||||
|
'@esbuild/android-arm64': 0.25.12
|
||||||
|
'@esbuild/android-x64': 0.25.12
|
||||||
|
'@esbuild/darwin-arm64': 0.25.12
|
||||||
|
'@esbuild/darwin-x64': 0.25.12
|
||||||
|
'@esbuild/freebsd-arm64': 0.25.12
|
||||||
|
'@esbuild/freebsd-x64': 0.25.12
|
||||||
|
'@esbuild/linux-arm': 0.25.12
|
||||||
|
'@esbuild/linux-arm64': 0.25.12
|
||||||
|
'@esbuild/linux-ia32': 0.25.12
|
||||||
|
'@esbuild/linux-loong64': 0.25.12
|
||||||
|
'@esbuild/linux-mips64el': 0.25.12
|
||||||
|
'@esbuild/linux-ppc64': 0.25.12
|
||||||
|
'@esbuild/linux-riscv64': 0.25.12
|
||||||
|
'@esbuild/linux-s390x': 0.25.12
|
||||||
|
'@esbuild/linux-x64': 0.25.12
|
||||||
|
'@esbuild/netbsd-arm64': 0.25.12
|
||||||
|
'@esbuild/netbsd-x64': 0.25.12
|
||||||
|
'@esbuild/openbsd-arm64': 0.25.12
|
||||||
|
'@esbuild/openbsd-x64': 0.25.12
|
||||||
|
'@esbuild/openharmony-arm64': 0.25.12
|
||||||
|
'@esbuild/sunos-x64': 0.25.12
|
||||||
|
'@esbuild/win32-arm64': 0.25.12
|
||||||
|
'@esbuild/win32-ia32': 0.25.12
|
||||||
|
'@esbuild/win32-x64': 0.25.12
|
||||||
|
|
||||||
escalade@3.2.0: {}
|
escalade@3.2.0: {}
|
||||||
|
|
||||||
escape-html@1.0.3: {}
|
escape-html@1.0.3: {}
|
||||||
@@ -1343,6 +1629,8 @@ snapshots:
|
|||||||
|
|
||||||
human-signals@8.0.1: {}
|
human-signals@8.0.1: {}
|
||||||
|
|
||||||
|
husky@9.1.7: {}
|
||||||
|
|
||||||
iconv-lite@0.6.3:
|
iconv-lite@0.6.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
safer-buffer: 2.1.2
|
safer-buffer: 2.1.2
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
import { spawnSync } from "child_process";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
|
||||||
|
function findCliPath(name: string): string | null {
|
||||||
|
|
||||||
|
const result = spawnSync("which", [name], { encoding: "utf-8" });
|
||||||
|
if (result.status === 0 && result.stdout) {
|
||||||
|
const cliPath = result.stdout.trim();
|
||||||
|
if (cliPath && existsSync(cliPath)) {
|
||||||
|
return cliPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(findCliPath("codei"));
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
## CURRENT
|
||||||
|
|
||||||
|
[] handle progressive comment updating from pullfrog mcp
|
||||||
|
|
||||||
|
## MAYBE
|
||||||
|
|
||||||
|
[] investigate repo config file
|
||||||
|
[] try to find heavy claude code user
|
||||||
|
[] investigate including terminal output from bash commands as collapsed groups from claude
|
||||||
|
[] test initialization trade offs for pullfrog.yml
|
||||||
|
|
||||||
|
## DONE
|
||||||
|
|
||||||
|
[x] investigate mcp naming convention
|
||||||
|
[x] input just accepts one key for API key
|
||||||
|
[x] look into trigger.yml without installation
|
||||||
|
[x] cancel installation token at the end of github action
|
||||||
|
[x] avoid exposing env adding ## SECURITY prompt
|
||||||
|
[x] add modes to prompt
|
||||||
|
[x] progressively update comment
|
||||||
|
[x] don't allow rejecting prs
|
||||||
|
[x] fix pnpm caching
|
||||||
|
[x] fix prompt to avoid narration like "I just read all tools from MCP server"
|
||||||
+15
-15
@@ -2,22 +2,22 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"module": "NodeNext",
|
"module": "NodeNext",
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"moduleResolution": "NodeNext",
|
"moduleResolution": "NodeNext",
|
||||||
"lib": ["ESNext"],
|
"lib": ["ESNext"],
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"rewriteRelativeImportExtensions": true,
|
"rewriteRelativeImportExtensions": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUncheckedSideEffectImports": true,
|
"noUncheckedSideEffectImports": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"verbatimModuleSyntax": true,
|
"verbatimModuleSyntax": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"exactOptionalPropertyTypes": true,
|
"exactOptionalPropertyTypes": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"stripInternal": true,
|
"stripInternal": true,
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"useUnknownInCatchVariables": true
|
"useUnknownInCatchVariables": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import type { AgentName } from "../main.ts";
|
||||||
|
import { log } from "./cli.ts";
|
||||||
|
import type { RepoContext } from "./github.ts";
|
||||||
|
|
||||||
|
export interface Mode {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
prompt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RepoSettings {
|
||||||
|
defaultAgent: AgentName | null;
|
||||||
|
webAccessLevel: "full_access" | "limited";
|
||||||
|
webAccessAllowTrusted: boolean;
|
||||||
|
webAccessDomains: string;
|
||||||
|
modes: Mode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_REPO_SETTINGS: RepoSettings = {
|
||||||
|
defaultAgent: null,
|
||||||
|
webAccessLevel: "full_access",
|
||||||
|
webAccessAllowTrusted: false,
|
||||||
|
webAccessDomains: "",
|
||||||
|
modes: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch repository settings from the Pullfrog API
|
||||||
|
* Returns defaults if repo doesn't exist or fetch fails
|
||||||
|
*/
|
||||||
|
export async function fetchRepoSettings({
|
||||||
|
token,
|
||||||
|
repoContext,
|
||||||
|
}: {
|
||||||
|
token: string;
|
||||||
|
repoContext: RepoContext;
|
||||||
|
}): Promise<RepoSettings> {
|
||||||
|
log.info("Fetching repository settings...");
|
||||||
|
const settings = await getRepoSettings(token, repoContext);
|
||||||
|
log.info("Repository settings fetched");
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch repository settings from the Pullfrog API with fallback to defaults
|
||||||
|
* Returns agent, permissions, and workflows (excludes triggers)
|
||||||
|
* Returns defaults if repo doesn't exist or fetch fails
|
||||||
|
*/
|
||||||
|
export async function getRepoSettings(
|
||||||
|
token: string,
|
||||||
|
repoContext: RepoContext
|
||||||
|
): Promise<RepoSettings> {
|
||||||
|
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
||||||
|
|
||||||
|
// Add timeout to prevent hanging (5 seconds)
|
||||||
|
const timeoutMs = 5000;
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${apiUrl}/api/repo/${repoContext.owner}/${repoContext.name}/settings`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
signal: controller.signal,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
// If API returns 404 or other error, fall back to defaults
|
||||||
|
return DEFAULT_REPO_SETTINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = (await response.json()) as RepoSettings | null;
|
||||||
|
|
||||||
|
// If API returns null (repo doesn't exist), return defaults
|
||||||
|
if (settings === null) {
|
||||||
|
return DEFAULT_REPO_SETTINGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
} catch {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
// If fetch fails (network error, timeout, etc.), fall back to defaults
|
||||||
|
return DEFAULT_REPO_SETTINGS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,10 +3,34 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
import { spawnSync } from "child_process";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
|
||||||
const isGitHubActions = !!process.env.GITHUB_ACTIONS;
|
const isGitHubActions = !!process.env.GITHUB_ACTIONS;
|
||||||
const isDebugEnabled = process.env.LOG_LEVEL === "debug";
|
const isDebugEnabled = process.env.LOG_LEVEL === "debug";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a collapsed group (GitHub Actions) or regular group (local)
|
||||||
|
*/
|
||||||
|
function startGroup(name: string): void {
|
||||||
|
if (isGitHubActions) {
|
||||||
|
core.startGroup(name);
|
||||||
|
} else {
|
||||||
|
console.group(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End a collapsed group
|
||||||
|
*/
|
||||||
|
function endGroup(): void {
|
||||||
|
if (isGitHubActions) {
|
||||||
|
core.endGroup();
|
||||||
|
} else {
|
||||||
|
console.groupEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print a formatted box with text (for console output)
|
* Print a formatted box with text (for console output)
|
||||||
*/
|
*/
|
||||||
@@ -229,4 +253,30 @@ export const log = {
|
|||||||
await core.summary.write();
|
await core.summary.write();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a collapsed group (GitHub Actions) or regular group (local)
|
||||||
|
*/
|
||||||
|
startGroup,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End a collapsed group
|
||||||
|
*/
|
||||||
|
endGroup,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a CLI executable path by checking if it's installed globally
|
||||||
|
* @param name The name of the CLI executable to find
|
||||||
|
* @returns The path to the CLI executable, or null if not found
|
||||||
|
*/
|
||||||
|
export function findCliPath(name: string): string | null {
|
||||||
|
const result = spawnSync("which", [name], { encoding: "utf-8" });
|
||||||
|
if (result.status === 0 && result.stdout) {
|
||||||
|
const cliPath = result.stdout.trim();
|
||||||
|
if (cliPath && existsSync(cliPath)) {
|
||||||
|
return cliPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
+64
-23
@@ -62,25 +62,40 @@ async function acquireTokenViaOIDC(): Promise<string> {
|
|||||||
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
||||||
|
|
||||||
log.info("Exchanging OIDC token for installation token...");
|
log.info("Exchanging OIDC token for installation token...");
|
||||||
const tokenResponse = await fetch(`${apiUrl}/api/github/installation-token`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${oidcToken}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!tokenResponse.ok) {
|
// Add timeout to prevent long waits (5 seconds)
|
||||||
const errorText = await tokenResponse.text();
|
const timeoutMs = 5000;
|
||||||
throw new Error(
|
const controller = new AbortController();
|
||||||
`Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText} - ${errorText}`
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
||||||
);
|
|
||||||
|
try {
|
||||||
|
const tokenResponse = await fetch(`${apiUrl}/api/github/installation-token`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${oidcToken}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
|
if (!tokenResponse.ok) {
|
||||||
|
throw new Error(`Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenData = (await tokenResponse.json()) as InstallationToken;
|
||||||
|
log.info(`Installation token obtained for ${tokenData.repository || "all repositories"}`);
|
||||||
|
|
||||||
|
return tokenData.token;
|
||||||
|
} catch (error) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
|
if (error instanceof Error && error.name === "AbortError") {
|
||||||
|
throw new Error(`Token exchange timed out after ${timeoutMs}ms`);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokenData = (await tokenResponse.json()) as InstallationToken;
|
|
||||||
log.info(`Installation token obtained for ${tokenData.repository || "all repositories"}`);
|
|
||||||
|
|
||||||
return tokenData.token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const base64UrlEncode = (str: string): string => {
|
const base64UrlEncode = (str: string): string => {
|
||||||
@@ -234,21 +249,47 @@ async function acquireNewToken(): Promise<string> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup GitHub installation token for the action
|
* Setup GitHub installation token for the action
|
||||||
|
* Returns the token and whether it was acquired (needs revocation)
|
||||||
*/
|
*/
|
||||||
export async function setupGitHubInstallationToken(): Promise<string> {
|
export async function setupGitHubInstallationToken(): Promise<{
|
||||||
|
githubInstallationToken: string;
|
||||||
|
wasAcquired: boolean;
|
||||||
|
}> {
|
||||||
const existingToken = checkExistingToken();
|
const existingToken = checkExistingToken();
|
||||||
if (existingToken) {
|
if (existingToken) {
|
||||||
core.setSecret(existingToken);
|
core.setSecret(existingToken);
|
||||||
log.info("Using provided GitHub installation token");
|
log.info("Using provided GitHub installation token");
|
||||||
return existingToken;
|
return { githubInstallationToken: existingToken, wasAcquired: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = await acquireNewToken();
|
const acquiredToken = await acquireNewToken();
|
||||||
|
core.setSecret(acquiredToken);
|
||||||
|
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
|
||||||
|
|
||||||
core.setSecret(token);
|
return { githubInstallationToken: acquiredToken, wasAcquired: true };
|
||||||
process.env.GITHUB_INSTALLATION_TOKEN = token;
|
}
|
||||||
|
|
||||||
return token;
|
/**
|
||||||
|
* Revoke GitHub installation token
|
||||||
|
*/
|
||||||
|
export async function revokeInstallationToken(token: string): Promise<void> {
|
||||||
|
const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com";
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fetch(`${apiUrl}/installation/token`, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
Accept: "application/vnd.github+json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
"X-GitHub-Api-Version": "2022-11-28",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
log.info("Installation token revoked");
|
||||||
|
} catch (error) {
|
||||||
|
log.warning(
|
||||||
|
`Failed to revoke installation token: ${error instanceof Error ? error.message : String(error)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RepoContext {
|
export interface RepoContext {
|
||||||
|
|||||||
+25
-2
@@ -41,17 +41,40 @@ export function setupTestRepo(options: SetupOptions): void {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup git configuration to avoid identity errors
|
* Setup git configuration to avoid identity errors
|
||||||
|
* Only runs in GitHub Actions environment to avoid overwriting local git config
|
||||||
*/
|
*/
|
||||||
export function setupGitConfig(): void {
|
export function setupGitConfig(): void {
|
||||||
|
// Only set up git config in GitHub Actions environment
|
||||||
|
// In local development, use the user's existing git config
|
||||||
|
if (!process.env.GITHUB_ACTIONS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log.info("🔧 Setting up git configuration...");
|
log.info("🔧 Setting up git configuration...");
|
||||||
execSync('git config user.email "action@pullfrog.ai"', { stdio: "inherit" });
|
try {
|
||||||
execSync('git config user.name "Pullfrog Action"', { stdio: "inherit" });
|
execSync('git config user.email "action@pullfrog.ai"', { stdio: "pipe" });
|
||||||
|
execSync('git config user.name "Pullfrog Action"', { stdio: "pipe" });
|
||||||
|
log.debug("setupGitConfig: ✓ Git configuration set successfully");
|
||||||
|
} catch (error) {
|
||||||
|
// If git config fails, log warning but don't fail the action
|
||||||
|
// This can happen if we're not in a git repo or git isn't available
|
||||||
|
log.warning(
|
||||||
|
`Failed to set git config: ${error instanceof Error ? error.message : String(error)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup git authentication using GitHub token
|
* Setup git authentication using GitHub token
|
||||||
|
* Only runs in GitHub Actions environment to avoid breaking local git remotes
|
||||||
*/
|
*/
|
||||||
export function setupGitAuth(githubToken: string, repoContext: RepoContext): void {
|
export function setupGitAuth(githubToken: string, repoContext: RepoContext): void {
|
||||||
|
// Only set up git auth in GitHub Actions environment
|
||||||
|
// In local testing, this would overwrite the real git remote with fake credentials
|
||||||
|
if (!process.env.GITHUB_ACTIONS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log.info("🔐 Setting up git authentication...");
|
log.info("🔐 Setting up git authentication...");
|
||||||
|
|
||||||
// Remove existing git auth headers that actions/checkout might have set
|
// Remove existing git auth headers that actions/checkout might have set
|
||||||
|
|||||||
Reference in New Issue
Block a user