merge
This commit is contained in:
+1
-2
@@ -1,3 +1,2 @@
|
|||||||
# Mark generated files as linguist-generated to exclude from language statistics
|
# Mark generated files as linguist-generated to exclude from language statistics
|
||||||
entry.js linguist-generated
|
entry.js linguist-detectable=false
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ export const claude = agent({
|
|||||||
executablePath: "cli.js",
|
executablePath: "cli.js",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
addMcpServer: () => {
|
||||||
|
// Claude accepts mcpServers directly in the query options, no configuration needed
|
||||||
|
},
|
||||||
run: async ({ prompt, mcpServers, apiKey, cliPath }) => {
|
run: async ({ prompt, mcpServers, apiKey, cliPath }) => {
|
||||||
process.env.ANTHROPIC_API_KEY = apiKey;
|
process.env.ANTHROPIC_API_KEY = apiKey;
|
||||||
|
|
||||||
|
|||||||
+28
-56
@@ -15,13 +15,37 @@ export const codex = agent({
|
|||||||
executablePath: "bin/codex.js",
|
executablePath: "bin/codex.js",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
addMcpServer: ({ serverName, serverConfig, cliPath }) => {
|
||||||
|
// Codex CLI syntax: codex mcp add <name> --env KEY=value -- <command> [args...]
|
||||||
|
const command = serverConfig.command;
|
||||||
|
const args = serverConfig.args || [];
|
||||||
|
const envVars = serverConfig.env || {};
|
||||||
|
|
||||||
|
const addArgs = ["mcp", "add", serverName];
|
||||||
|
|
||||||
|
// Add environment variables as --env flags first
|
||||||
|
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",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (addResult.status !== 0) {
|
||||||
|
throw new Error(
|
||||||
|
`codex mcp add failed: ${addResult.stderr || addResult.stdout || "Unknown error"}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
log.info(`✓ MCP server '${serverName}' configured`);
|
||||||
|
},
|
||||||
run: async ({ prompt, mcpServers, apiKey, cliPath, githubInstallationToken }) => {
|
run: async ({ prompt, mcpServers, apiKey, cliPath, githubInstallationToken }) => {
|
||||||
process.env.OPENAI_API_KEY = apiKey;
|
process.env.OPENAI_API_KEY = apiKey;
|
||||||
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
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
|
// Configure Codex
|
||||||
const codexOptions: CodexOptions = {
|
const codexOptions: CodexOptions = {
|
||||||
@@ -159,55 +183,3 @@ const messageHandlers: {
|
|||||||
log.error(`Error: ${event.message}`);
|
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,110 @@
|
|||||||
|
import { spawnSync } from "node:child_process";
|
||||||
|
import type { McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
||||||
|
import { log } from "../utils/cli.ts";
|
||||||
|
import { spawn } from "../utils/subprocess.ts";
|
||||||
|
import { addInstructions } from "./instructions.ts";
|
||||||
|
import { agent, installFromNpmTarball } from "./shared.ts";
|
||||||
|
|
||||||
|
export const gemini = agent({
|
||||||
|
name: "gemini",
|
||||||
|
inputKeys: ["google_api_key", "gemini_api_key"],
|
||||||
|
install: async () => {
|
||||||
|
return await installFromNpmTarball({
|
||||||
|
packageName: "@google/gemini-cli",
|
||||||
|
version: "latest",
|
||||||
|
executablePath: "dist/index.js",
|
||||||
|
installDependencies: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addMcpServer: ({ serverName, serverConfig, cliPath }) => {
|
||||||
|
// Gemini CLI syntax: gemini mcp add <name> <commandOrUrl> [args...] --env KEY=value
|
||||||
|
const command = serverConfig.command;
|
||||||
|
const args = serverConfig.args || [];
|
||||||
|
const envVars = serverConfig.env || {};
|
||||||
|
|
||||||
|
const addArgs = ["mcp", "add", serverName, command, ...args];
|
||||||
|
|
||||||
|
// Add environment variables as --env flags
|
||||||
|
for (const [key, value] of Object.entries(envVars)) {
|
||||||
|
addArgs.push("--env", `${key}=${value}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(`Adding MCP server '${serverName}'...`);
|
||||||
|
const addResult = spawnSync("node", [cliPath, ...addArgs], {
|
||||||
|
stdio: "pipe",
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (addResult.status !== 0) {
|
||||||
|
throw new Error(
|
||||||
|
`gemini mcp add failed: ${addResult.stderr || addResult.stdout || "Unknown error"}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
log.info(`✓ MCP server '${serverName}' configured`);
|
||||||
|
},
|
||||||
|
run: async ({ prompt, apiKey, mcpServers, githubInstallationToken, cliPath }) => {
|
||||||
|
if (!apiKey) {
|
||||||
|
throw new Error("google_api_key or gemini_api_key is required for gemini agent");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set environment variables for Gemini CLI and MCP servers
|
||||||
|
process.env.GEMINI_API_KEY = apiKey;
|
||||||
|
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||||
|
|
||||||
|
const sessionPrompt = addInstructions(prompt);
|
||||||
|
log.info(`Starting Gemini CLI with prompt: ${prompt.substring(0, 100)}...`);
|
||||||
|
|
||||||
|
let finalOutput = "";
|
||||||
|
try {
|
||||||
|
const result = await spawn({
|
||||||
|
cmd: "node",
|
||||||
|
args: [cliPath, "--yolo", "--output-format", "text", sessionPrompt],
|
||||||
|
env: {
|
||||||
|
GEMINI_API_KEY: apiKey,
|
||||||
|
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
|
||||||
|
},
|
||||||
|
onStdout: (chunk) => {
|
||||||
|
const trimmed = chunk.trim();
|
||||||
|
if (trimmed) {
|
||||||
|
log.info(trimmed);
|
||||||
|
finalOutput += trimmed + "\n";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onStderr: (chunk) => {
|
||||||
|
const trimmed = chunk.trim();
|
||||||
|
if (trimmed) {
|
||||||
|
log.warning(trimmed);
|
||||||
|
finalOutput += trimmed + "\n";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.exitCode !== 0) {
|
||||||
|
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
||||||
|
log.error(`Gemini CLI exited with code ${result.exitCode}: ${errorMessage}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: errorMessage,
|
||||||
|
output: finalOutput || result.stdout || "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
finalOutput = finalOutput || result.stdout || "Gemini CLI completed successfully.";
|
||||||
|
log.info("✓ Gemini CLI completed successfully");
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
output: finalOutput,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
log.error(`Failed to run Gemini CLI: ${errorMessage}`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: errorMessage,
|
||||||
|
output: finalOutput || "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
+2
-2
@@ -1,13 +1,13 @@
|
|||||||
import { claude } from "./claude.ts";
|
import { claude } from "./claude.ts";
|
||||||
import { codex } from "./codex.ts";
|
import { codex } from "./codex.ts";
|
||||||
import { cursor } from "./cursor.ts";
|
import { cursor } from "./cursor.ts";
|
||||||
import { jules } from "./jules.ts";
|
import { gemini } from "./gemini.ts";
|
||||||
|
|
||||||
export const agents = {
|
export const agents = {
|
||||||
claude,
|
claude,
|
||||||
codex,
|
codex,
|
||||||
cursor,
|
cursor,
|
||||||
jules,
|
gemini,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type AgentInputKey = (typeof agents)[keyof typeof agents]["inputKeys"][number];
|
export type AgentInputKey = (typeof agents)[keyof typeof agents]["inputKeys"][number];
|
||||||
|
|||||||
-175
@@ -1,175 +0,0 @@
|
|||||||
import { log } from "../utils/cli.ts";
|
|
||||||
import { parseRepoContext } from "../utils/github.ts";
|
|
||||||
import { spawn } from "../utils/subprocess.ts";
|
|
||||||
import { addInstructions } from "./instructions.ts";
|
|
||||||
import { agent, installFromNpmTarball } from "./shared.ts";
|
|
||||||
|
|
||||||
export const jules = agent({
|
|
||||||
name: "jules",
|
|
||||||
inputKeys: ["google_api_key", "gemini_api_key"],
|
|
||||||
install: async () => {
|
|
||||||
return await installFromNpmTarball({
|
|
||||||
packageName: "@google/jules",
|
|
||||||
version: "latest",
|
|
||||||
executablePath: "run.cjs",
|
|
||||||
installDependencies: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
run: async ({
|
|
||||||
prompt,
|
|
||||||
apiKey,
|
|
||||||
mcpServers: _mcpServers,
|
|
||||||
githubInstallationToken: _githubInstallationToken,
|
|
||||||
cliPath,
|
|
||||||
}) => {
|
|
||||||
if (!apiKey) {
|
|
||||||
throw new Error("google_api_key is required for jules agent");
|
|
||||||
}
|
|
||||||
process.env.GOOGLE_API_KEY = apiKey;
|
|
||||||
|
|
||||||
const repoContext = parseRepoContext();
|
|
||||||
const repoName = `${repoContext.owner}/${repoContext.name}`;
|
|
||||||
|
|
||||||
log.info(`Creating Jules session for ${repoName}...`);
|
|
||||||
|
|
||||||
// Create a new remote session
|
|
||||||
const sessionPrompt = addInstructions(prompt);
|
|
||||||
log.info(`Starting session with prompt: ${prompt.substring(0, 100)}...`);
|
|
||||||
|
|
||||||
let sessionId: string | undefined;
|
|
||||||
try {
|
|
||||||
const createResult = await spawn({
|
|
||||||
cmd: "node",
|
|
||||||
args: [cliPath, "remote", "new", "--repo", repoName, "--session", sessionPrompt],
|
|
||||||
onStdout: (chunk) => {
|
|
||||||
log.info(chunk.trim());
|
|
||||||
// Try to extract session ID from output
|
|
||||||
const match = chunk.match(/session[:\s]+(\d+)/i) || chunk.match(/id[:\s]+(\d+)/i);
|
|
||||||
if (match && !sessionId) {
|
|
||||||
sessionId = match[1];
|
|
||||||
log.info(`✓ Session ID: ${sessionId}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onStderr: (chunk) => {
|
|
||||||
log.warning(chunk.trim());
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (createResult.exitCode !== 0) {
|
|
||||||
throw new Error(
|
|
||||||
`Failed to create Jules session: ${createResult.stderr || createResult.stdout || "Unknown error"}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If session ID wasn't extracted from stdout, try to parse it
|
|
||||||
if (!sessionId) {
|
|
||||||
const output = createResult.stdout + createResult.stderr;
|
|
||||||
const match = output.match(/session[:\s]+(\d+)/i) || output.match(/id[:\s]+(\d+)/i);
|
|
||||||
if (match) {
|
|
||||||
sessionId = match[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sessionId) {
|
|
||||||
log.warning("Could not extract session ID from output. Session may have been created.");
|
|
||||||
log.info(`Output: ${createResult.stdout}`);
|
|
||||||
} else {
|
|
||||||
log.info(`✓ Session created: ${sessionId}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
||||||
log.error(`Failed to create Jules session: ${errorMessage}`);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: errorMessage,
|
|
||||||
output: "",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Monitor session progress by polling session list
|
|
||||||
log.info("Monitoring session progress...");
|
|
||||||
let finalOutput = "";
|
|
||||||
const maxPollAttempts = 300; // ~50 minutes max (10 second intervals)
|
|
||||||
let pollAttempts = 0;
|
|
||||||
|
|
||||||
while (pollAttempts < maxPollAttempts) {
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 10000)); // Wait 10 seconds between polls
|
|
||||||
pollAttempts++;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// List sessions to check status
|
|
||||||
const listResult = await spawn({
|
|
||||||
cmd: "node",
|
|
||||||
args: [cliPath, "remote", "list", "--session"],
|
|
||||||
onStdout: (chunk) => {
|
|
||||||
// Log session updates
|
|
||||||
const trimmed = chunk.trim();
|
|
||||||
if (trimmed) {
|
|
||||||
log.info(trimmed);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (listResult.exitCode === 0) {
|
|
||||||
const output = listResult.stdout;
|
|
||||||
// Check if our session is complete
|
|
||||||
// The CLI output format may vary, so we look for completion indicators
|
|
||||||
if (sessionId && output.includes(sessionId)) {
|
|
||||||
// Try to determine if session is complete
|
|
||||||
// This is a heuristic - the actual output format may differ
|
|
||||||
if (
|
|
||||||
output.includes("completed") ||
|
|
||||||
output.includes("done") ||
|
|
||||||
output.includes("finished")
|
|
||||||
) {
|
|
||||||
log.info("Session appears to be completed");
|
|
||||||
finalOutput = "Session completed. Pulling results...";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
||||||
log.warning(`Error checking session status: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pull results if session ID is available
|
|
||||||
if (sessionId) {
|
|
||||||
try {
|
|
||||||
log.info(`Pulling results for session ${sessionId}...`);
|
|
||||||
const pullResult = await spawn({
|
|
||||||
cmd: "node",
|
|
||||||
args: [cliPath, "remote", "pull", "--session", sessionId],
|
|
||||||
onStdout: (chunk) => {
|
|
||||||
log.info(chunk.trim());
|
|
||||||
},
|
|
||||||
onStderr: (chunk) => {
|
|
||||||
log.warning(chunk.trim());
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (pullResult.exitCode === 0) {
|
|
||||||
finalOutput = pullResult.stdout || "Results pulled successfully.";
|
|
||||||
} else {
|
|
||||||
log.warning(`Failed to pull results: ${pullResult.stderr || pullResult.stdout}`);
|
|
||||||
finalOutput = finalOutput || "Session completed. Check Jules dashboard for results.";
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
||||||
log.warning(`Error pulling results: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pollAttempts >= maxPollAttempts) {
|
|
||||||
log.warning("Session monitoring timeout reached. Session may still be in progress.");
|
|
||||||
finalOutput =
|
|
||||||
finalOutput || "Session monitoring timeout. Check Jules dashboard for session status.";
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
output: finalOutput || "Jules session completed. Check the Jules dashboard for results.",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -223,9 +223,19 @@ export const agent = <const agent extends Agent>(agent: agent): agent => {
|
|||||||
return agent;
|
return agent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for adding an MCP server to an agent
|
||||||
|
*/
|
||||||
|
export interface AddMcpServerParams {
|
||||||
|
serverName: string;
|
||||||
|
serverConfig: Extract<McpServerConfig, { command: string }>;
|
||||||
|
cliPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type Agent = {
|
export type Agent = {
|
||||||
name: string;
|
name: string;
|
||||||
inputKeys: string[];
|
inputKeys: string[];
|
||||||
install: () => Promise<string>;
|
install: () => Promise<string>;
|
||||||
|
addMcpServer: (params: AddMcpServerParams) => void;
|
||||||
run: (config: AgentConfig) => Promise<AgentResult>;
|
run: (config: AgentConfig) => Promise<AgentResult>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { flatMorph } from "@ark/util";
|
import { flatMorph } from "@ark/util";
|
||||||
import { type } from "arktype";
|
import { type } from "arktype";
|
||||||
import { agents } from "./agents/index.ts";
|
import { agents } from "./agents/index.ts";
|
||||||
import { createMcpConfigs } from "./mcp/config.ts";
|
import { createMcpConfigs, forEachStdioMcpServer } from "./mcp/config.ts";
|
||||||
import packageJson from "./package.json" with { type: "json" };
|
import packageJson from "./package.json" with { type: "json" };
|
||||||
import { fetchRepoSettings } from "./utils/api.ts";
|
import { fetchRepoSettings } from "./utils/api.ts";
|
||||||
import { log } from "./utils/cli.ts";
|
import { log } from "./utils/cli.ts";
|
||||||
@@ -141,6 +141,18 @@ export async function main(inputs: Inputs): Promise<MainResult> {
|
|||||||
|
|
||||||
const apiKey = inputs[matchingInputKey]!;
|
const apiKey = inputs[matchingInputKey]!;
|
||||||
|
|
||||||
|
// Configure MCP servers if provided (global config is fine - not part of repo)
|
||||||
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
||||||
|
log.info(`Configuring MCP servers for ${agentName}...`);
|
||||||
|
forEachStdioMcpServer(mcpServers, (serverName, serverConfig) => {
|
||||||
|
agent.addMcpServer({
|
||||||
|
serverName,
|
||||||
|
serverConfig,
|
||||||
|
cliPath,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const result = await agent.run({
|
const result = await agent.run({
|
||||||
prompt: inputs.prompt,
|
prompt: inputs.prompt,
|
||||||
mcpServers,
|
mcpServers,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import type { McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
import type { McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
||||||
import { fromHere } from "@ark/fs";
|
import { fromHere } from "@ark/fs";
|
||||||
|
import { log } from "../utils/cli.ts";
|
||||||
import { parseRepoContext } from "../utils/github.ts";
|
import { parseRepoContext } from "../utils/github.ts";
|
||||||
import { ghPullfrogMcpName } from "./index.ts";
|
import { ghPullfrogMcpName } from "./index.ts";
|
||||||
|
|
||||||
@@ -30,3 +31,22 @@ export function createMcpConfigs(githubInstallationToken: string): McpConfigs {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate through MCP servers and call the provided handler for each stdio server
|
||||||
|
* Shared logic to avoid duplication across agents
|
||||||
|
*/
|
||||||
|
export function forEachStdioMcpServer(
|
||||||
|
mcpServers: Record<string, McpServerConfig>,
|
||||||
|
handler: (serverName: string, serverConfig: Extract<McpServerConfig, { command: string }>) => void
|
||||||
|
): void {
|
||||||
|
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
||||||
|
// Only configure stdio servers (CLIs support stdio MCP servers)
|
||||||
|
if (!("command" in serverConfig)) {
|
||||||
|
log.warning(`MCP server '${serverName}' is not a stdio server, skipping...`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
handler(serverName, serverConfig as Extract<McpServerConfig, { command: string }>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
## CURRENT
|
## CURRENT
|
||||||
|
|
||||||
[] handle progressive comment updating from pullfrog mcp
|
[] jules/gemini support
|
||||||
|
[] gemini installation speed
|
||||||
|
[] standardize mcp server
|
||||||
|
|
||||||
## MAYBE
|
## MAYBE
|
||||||
|
|
||||||
@@ -21,3 +23,4 @@
|
|||||||
[x] don't allow rejecting prs
|
[x] don't allow rejecting prs
|
||||||
[x] fix pnpm caching
|
[x] fix pnpm caching
|
||||||
[x] fix prompt to avoid narration like "I just read all tools from MCP server"
|
[x] fix prompt to avoid narration like "I just read all tools from MCP server"
|
||||||
|
[x] handle progressive comment updating from pullfrog mcp
|
||||||
|
|||||||
Reference in New Issue
Block a user