diff --git a/agents/opencode.ts b/agents/opencode.ts index 292d52d..8c053ff 100644 --- a/agents/opencode.ts +++ b/agents/opencode.ts @@ -1,4 +1,4 @@ -import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { mkdirSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { log } from "../utils/cli.ts"; @@ -42,12 +42,6 @@ export const opencode = agent({ // 6. set up environment setupProcessAgentEnv({ HOME: tempHome }); - // DEBUG: log original process.env values before building env - log.startGroup("🔍 DEBUG: Environment analysis"); - log.info(`Original process.env.HOME: ${process.env.HOME}`); - log.info(`Original process.env.XDG_CONFIG_HOME: ${process.env.XDG_CONFIG_HOME || "(not set)"}`); - log.info(`Target tempHome: ${tempHome}`); - // build env vars: start with process.env (includes all API_KEY vars loaded by config()) // exclude GITHUB_TOKEN - OpenCode should use MCP server for GitHub operations, not direct token // then override with apiKeys, HOME, and XDG_CONFIG_HOME @@ -68,51 +62,13 @@ export const opencode = agent({ env[key.toUpperCase()] = value; } - // DEBUG: verify env overrides worked - log.info(`Final env.HOME: ${env.HOME}`); - log.info(`Final env.XDG_CONFIG_HOME: ${env.XDG_CONFIG_HOME}`); - - // DEBUG: verify config file exists and log its contents - const configPath = join(env.HOME!, ".config", "opencode", "opencode.json"); - const configExists = existsSync(configPath); - log.info(`Config path: ${configPath}`); - log.info(`Config file exists: ${configExists}`); - if (configExists) { - const configContents = readFileSync(configPath, "utf-8"); - log.info(`Config file contents:\n${configContents}`); - } - - // DEBUG: check for alternative config locations OpenCode might use - const altConfigPaths = [ - join(env.HOME!, ".opencode", "config.json"), - join(env.HOME!, ".opencode.json"), - join(process.cwd(), ".opencode.json"), - join(process.cwd(), ".opencode", "config.json"), - ]; - for (const altPath of altConfigPaths) { - if (existsSync(altPath)) { - log.info(`⚠️ Alternative config found at: ${altPath}`); - } - } - - // DEBUG: test MCP server connectivity - const mcpUrl = "http://127.0.0.1:3764/mcp"; - try { - const response = await fetch(mcpUrl, { method: "GET" }); - log.info(`MCP server reachable: ${response.ok} (status: ${response.status})`); - } catch (error) { - log.warning( - `MCP server NOT reachable: ${error instanceof Error ? error.message : String(error)}` - ); - } - - log.endGroup(); - // run OpenCode in the repository directory (process.cwd() is set to GITHUB_WORKSPACE or repo dir) const repoDir = process.cwd(); log.info(`🚀 Starting OpenCode CLI: ${cliPath} ${args.join(" ")}`); log.info(`📁 Working directory: ${repoDir}`); + log.debug(`🏠 HOME: ${env.HOME}`); + log.debug(`📋 XDG_CONFIG_HOME: ${env.XDG_CONFIG_HOME}`); const startTime = Date.now(); let lastActivityTime = startTime; diff --git a/entry b/entry index e7ad3cb..5f0bc04 100755 --- a/entry +++ b/entry @@ -406,7 +406,7 @@ var require_tunnel = __commonJS({ connectOptions.headers = connectOptions.headers || {}; connectOptions.headers["Proxy-Authorization"] = "Basic " + new Buffer(connectOptions.proxyAuth).toString("base64"); } - debug2("making CONNECT request"); + debug("making CONNECT request"); var connectReq = self2.request(connectOptions); connectReq.useChunkedEncodingByDefault = false; connectReq.once("response", onResponse); @@ -426,7 +426,7 @@ var require_tunnel = __commonJS({ connectReq.removeAllListeners(); socket.removeAllListeners(); if (res.statusCode !== 200) { - debug2( + debug( "tunneling socket could not be established, statusCode=%d", res.statusCode ); @@ -438,7 +438,7 @@ var require_tunnel = __commonJS({ return; } if (head.length > 0) { - debug2("got illegal response body from proxy"); + debug("got illegal response body from proxy"); socket.destroy(); var error42 = new Error("got illegal response body from proxy"); error42.code = "ECONNRESET"; @@ -446,13 +446,13 @@ var require_tunnel = __commonJS({ self2.removeSocket(placeholder); return; } - debug2("tunneling connection has established"); + debug("tunneling connection has established"); self2.sockets[self2.sockets.indexOf(placeholder)] = socket; return cb(socket); } function onError(cause) { connectReq.removeAllListeners(); - debug2( + debug( "tunneling socket could not be established, cause=%s\n", cause.message, cause.stack @@ -514,9 +514,9 @@ var require_tunnel = __commonJS({ } return target; } - var debug2; + var debug; if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) { - debug2 = function() { + debug = function() { var args3 = Array.prototype.slice.call(arguments); if (typeof args3[0] === "string") { args3[0] = "TUNNEL: " + args3[0]; @@ -526,10 +526,10 @@ var require_tunnel = __commonJS({ console.error.apply(console, args3); }; } else { - debug2 = function() { + debug = function() { }; } - exports.debug = debug2; + exports.debug = debug; } }); @@ -19740,10 +19740,10 @@ Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); return process.env["RUNNER_DEBUG"] === "1"; } exports.isDebug = isDebug; - function debug2(message) { + function debug(message) { (0, command_1.issueCommand)("debug", {}, message); } - exports.debug = debug2; + exports.debug = debug; function error42(message, properties = {}) { (0, command_1.issueCommand)("error", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message); } @@ -80422,7 +80422,7 @@ var log = { debug: (message) => { if (isDebugEnabled()) { if (isGitHubActions) { - core.debug(message); + core.info(`[DEBUG] ${message}`); } else { core.info(`[DEBUG] ${message}`); } @@ -91248,7 +91248,7 @@ function configureGeminiMcpServers({ mcpServers, cliPath }) { } // agents/opencode.ts -import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs"; +import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "node:fs"; import { join as join7 } from "node:path"; var opencode = agent({ name: "opencode", @@ -91272,10 +91272,6 @@ var opencode = agent({ log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); } setupProcessAgentEnv({ HOME: tempHome }); - log.startGroup("\u{1F50D} DEBUG: Environment analysis"); - log.info(`Original process.env.HOME: ${process.env.HOME}`); - log.info(`Original process.env.XDG_CONFIG_HOME: ${process.env.XDG_CONFIG_HOME || "(not set)"}`); - log.info(`Target tempHome: ${tempHome}`); const env3 = { ...Object.fromEntries( Object.entries(process.env).filter( @@ -91288,41 +91284,11 @@ var opencode = agent({ for (const [key, value2] of Object.entries(apiKeys || {})) { env3[key.toUpperCase()] = value2; } - log.info(`Final env.HOME: ${env3.HOME}`); - log.info(`Final env.XDG_CONFIG_HOME: ${env3.XDG_CONFIG_HOME}`); - const configPath = join7(env3.HOME, ".config", "opencode", "opencode.json"); - const configExists = existsSync3(configPath); - log.info(`Config path: ${configPath}`); - log.info(`Config file exists: ${configExists}`); - if (configExists) { - const configContents = readFileSync2(configPath, "utf-8"); - log.info(`Config file contents: -${configContents}`); - } - const altConfigPaths = [ - join7(env3.HOME, ".opencode", "config.json"), - join7(env3.HOME, ".opencode.json"), - join7(process.cwd(), ".opencode.json"), - join7(process.cwd(), ".opencode", "config.json") - ]; - for (const altPath of altConfigPaths) { - if (existsSync3(altPath)) { - log.info(`\u26A0\uFE0F Alternative config found at: ${altPath}`); - } - } - const mcpUrl = "http://127.0.0.1:3764/mcp"; - try { - const response = await fetch(mcpUrl, { method: "GET" }); - log.info(`MCP server reachable: ${response.ok} (status: ${response.status})`); - } catch (error42) { - log.warning( - `MCP server NOT reachable: ${error42 instanceof Error ? error42.message : String(error42)}` - ); - } - log.endGroup(); const repoDir = process.cwd(); log.info(`\u{1F680} Starting OpenCode CLI: ${cliPath} ${args3.join(" ")}`); log.info(`\u{1F4C1} Working directory: ${repoDir}`); + log.debug(`\u{1F3E0} HOME: ${env3.HOME}`); + log.debug(`\u{1F4CB} XDG_CONFIG_HOME: ${env3.XDG_CONFIG_HOME}`); const startTime = Date.now(); let lastActivityTime = startTime; let eventCount = 0; @@ -124082,35 +124048,33 @@ function GetCheckSuiteLogsTool(ctx) { // mcp/debug.ts var DebugShellCommand = type({}); -var DebugShellCommandTool = tool({ - name: "debug_shell_command", - description: "debug tool: runs 'git status' and returns the output. use this to test shell command execution in the MCP server.", - parameters: DebugShellCommand, - execute: async () => { - try { +function DebugShellCommandTool(_ctx) { + return tool({ + name: "debug_shell_command", + description: "debug tool: runs 'git status' and returns the output. use this to test shell command execution in the MCP server.", + parameters: DebugShellCommand, + execute: execute(_ctx, async () => { const result = $("git", ["status"]); - return handleToolSuccess({ + return { success: true, command: "git status", output: result.trim() - }); - } catch (error42) { - return handleToolError(error42); - } - } -}); + }; + }) + }); +} // mcp/files.ts import { relative, resolve } from "node:path"; var ListFiles = type({ path: type.string.describe("The path to list files from (defaults to current directory)").default(".") }); -var ListFilesTool = tool({ - name: "list_files", - description: "List files in the repository, including both git-tracked and untracked files. Useful for discovering the file structure and locating files, including newly created files that haven't been committed yet.", - parameters: ListFiles, - execute: async ({ path: path4 }) => { - try { +function ListFilesTool(_ctx) { + return tool({ + name: "list_files", + description: "List files in the repository, including both git-tracked and untracked files. Useful for discovering the file structure and locating files, including newly created files that haven't been committed yet.", + parameters: ListFiles, + execute: execute(_ctx, async ({ path: path4 }) => { const pathStr = path4 ?? "."; const cwd2 = process.cwd(); let gitFiles = []; @@ -124142,27 +124106,23 @@ var ListFilesTool = tool({ findFailed = true; } if (gitFailed && findFailed) { - return handleToolError( - new Error( - `Failed to list files: both git ls-files and find commands failed. Path: ${pathStr}, working directory: ${cwd2}` - ) + throw new Error( + `Failed to list files: both git ls-files and find commands failed. Path: ${pathStr}, working directory: ${cwd2}` ); } const gitFilesSet = new Set(gitFiles); const allFiles = [.../* @__PURE__ */ new Set([...gitFiles, ...filesystemFiles])].sort(); const untrackedFiles = filesystemFiles.filter((f) => !gitFilesSet.has(f)); const untrackedCount = untrackedFiles.length; - return handleToolSuccess({ + return { files: allFiles, method: "combined", trackedCount: gitFiles.length, untrackedCount - }); - } catch (error42) { - return handleToolError(error42); - } - } -}); + }; + }) + }); +} // utils/secrets.ts function getAllSecrets() { @@ -125048,12 +125008,12 @@ async function startMcpHttpServer(ctx) { GetReviewCommentsTool(ctx), ListPullRequestReviewsTool(ctx), GetCheckSuiteLogsTool(ctx), - DebugShellCommandTool, + DebugShellCommandTool(ctx), AddLabelsTool(ctx), CreateBranchTool(ctx), CommitFilesTool(ctx), PushBranchTool(ctx), - ListFilesTool + ListFilesTool(ctx) ]; if (!isProgressCommentDisabled(ctx)) { tools.push(ReportProgressTool(ctx)); @@ -125080,7 +125040,7 @@ async function startMcpHttpServer(ctx) { } // prep/installNodeDependencies.ts -import { existsSync as existsSync4 } from "node:fs"; +import { existsSync as existsSync3 } from "node:fs"; import { join as join9 } from "node:path"; // ../node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/commands.mjs @@ -125414,7 +125374,7 @@ var installNodeDependencies = { name: "installNodeDependencies", shouldRun: () => { const packageJsonPath = join9(process.cwd(), "package.json"); - return existsSync4(packageJsonPath); + return existsSync3(packageJsonPath); }, run: async () => { const detected = await detect({ cwd: process.cwd() }); @@ -125474,7 +125434,7 @@ var installNodeDependencies = { }; // prep/installPythonDependencies.ts -import { existsSync as existsSync5 } from "node:fs"; +import { existsSync as existsSync4 } from "node:fs"; import { join as join10 } from "node:path"; var PYTHON_CONFIGS = [ { @@ -125547,11 +125507,11 @@ var installPythonDependencies = { return false; } const cwd2 = process.cwd(); - return PYTHON_CONFIGS.some((config3) => existsSync5(join10(cwd2, config3.file))); + return PYTHON_CONFIGS.some((config3) => existsSync4(join10(cwd2, config3.file))); }, run: async () => { const cwd2 = process.cwd(); - const config3 = PYTHON_CONFIGS.find((c) => existsSync5(join10(cwd2, c.file))); + const config3 = PYTHON_CONFIGS.find((c) => existsSync4(join10(cwd2, c.file))); if (!config3) { return { language: "python", diff --git a/mcp/debug.ts b/mcp/debug.ts index 7b5a66c..18bf628 100644 --- a/mcp/debug.ts +++ b/mcp/debug.ts @@ -1,24 +1,23 @@ import { type } from "arktype"; +import type { Context } from "../main.ts"; import { $ } from "../utils/shell.ts"; -import { handleToolError, handleToolSuccess, tool, type ToolResult } from "./shared.ts"; +import { execute, tool } from "./shared.ts"; export const DebugShellCommand = type({}); -export const DebugShellCommandTool = tool({ - name: "debug_shell_command", - description: - "debug tool: runs 'git status' and returns the output. use this to test shell command execution in the MCP server.", - parameters: DebugShellCommand, - execute: async (): Promise => { - try { +export function DebugShellCommandTool(_ctx: Context) { + return tool({ + name: "debug_shell_command", + description: + "debug tool: runs 'git status' and returns the output. use this to test shell command execution in the MCP server.", + parameters: DebugShellCommand, + execute: execute(_ctx, async () => { const result = $("git", ["status"]); - return handleToolSuccess({ + return { success: true, command: "git status", output: result.trim(), - }); - } catch (error) { - return handleToolError(error); - } - }, -}); + }; + }), + }); +} diff --git a/mcp/files.ts b/mcp/files.ts index 7a187fe..c0b2e8c 100644 --- a/mcp/files.ts +++ b/mcp/files.ts @@ -1,7 +1,8 @@ import { relative, resolve } from "node:path"; import { type } from "arktype"; import { $ } from "../utils/shell.ts"; -import { handleToolError, handleToolSuccess, type ToolResult, tool } from "./shared.ts"; +import type { Context } from "../main.ts"; +import { execute, tool } from "./shared.ts"; export const ListFiles = type({ path: type.string @@ -9,14 +10,13 @@ export const ListFiles = type({ .default("."), }); -// static tool - doesn't need ctx, just runs git/find commands -export const ListFilesTool = tool({ - name: "list_files", - description: - "List files in the repository, including both git-tracked and untracked files. Useful for discovering the file structure and locating files, including newly created files that haven't been committed yet.", - parameters: ListFiles, - execute: async ({ path }: { path?: string }): Promise => { - try { +export function ListFilesTool(_ctx: Context) { + return tool({ + name: "list_files", + description: + "List files in the repository, including both git-tracked and untracked files. Useful for discovering the file structure and locating files, including newly created files that haven't been committed yet.", + parameters: ListFiles, + execute: execute(_ctx, async ({ path }: { path?: string }) => { const pathStr = path ?? "."; const cwd = process.cwd(); @@ -62,13 +62,11 @@ export const ListFilesTool = tool({ findFailed = true; } - // if both methods failed, return an error + // if both methods failed, throw an error (execute helper will handle it) if (gitFailed && findFailed) { - return handleToolError( - new Error( - `Failed to list files: both git ls-files and find commands failed. ` + - `Path: ${pathStr}, working directory: ${cwd}` - ) + throw new Error( + `Failed to list files: both git ls-files and find commands failed. ` + + `Path: ${pathStr}, working directory: ${cwd}` ); } @@ -82,14 +80,12 @@ export const ListFilesTool = tool({ const untrackedFiles = filesystemFiles.filter((f) => !gitFilesSet.has(f)); const untrackedCount = untrackedFiles.length; - return handleToolSuccess({ + return { files: allFiles, method: "combined", trackedCount: gitFiles.length, untrackedCount, - }); - } catch (error) { - return handleToolError(error); - } - }, -}); + }; + }), + }); +} diff --git a/mcp/server.ts b/mcp/server.ts index 025d2d3..b0bb47a 100644 --- a/mcp/server.ts +++ b/mcp/server.ts @@ -22,7 +22,7 @@ import { IssueInfoTool } from "./issueInfo.ts"; import { AddLabelsTool } from "./labels.ts"; import { PullRequestTool } from "./pr.ts"; import { PullRequestInfoTool } from "./prInfo.ts"; -import { AddReviewCommentTool, ReviewTool, StartReviewTool, SubmitReviewTool } from "./review.ts"; +import { AddReviewCommentTool, StartReviewTool, SubmitReviewTool } from "./review.ts"; import { GetReviewCommentsTool, ListPullRequestReviewsTool } from "./reviewComments.ts"; import { SelectModeTool } from "./selectMode.ts"; import { addTools, isProgressCommentDisabled } from "./shared.ts"; @@ -87,12 +87,12 @@ export async function startMcpHttpServer( GetReviewCommentsTool(ctx), ListPullRequestReviewsTool(ctx), GetCheckSuiteLogsTool(ctx), - DebugShellCommandTool, + DebugShellCommandTool(ctx), AddLabelsTool(ctx), CreateBranchTool(ctx), CommitFilesTool(ctx), PushBranchTool(ctx), - ListFilesTool, + ListFilesTool(ctx), ]; // only include ReportProgressTool if progress comment is not disabled diff --git a/utils/cli.ts b/utils/cli.ts index 17e22d6..adcdb98 100644 --- a/utils/cli.ts +++ b/utils/cli.ts @@ -277,7 +277,10 @@ export const log = { debug: (message: string): void => { if (isDebugEnabled()) { if (isGitHubActions) { - core.debug(message); + // using this instead of core.debug + // because core.debug only logs when ACTIONS_STEP_DEBUG is set to true + // we are using LOG_LEVEL + core.info(`[DEBUG] ${message}`); } else { core.info(`[DEBUG] ${message}`); }