diff --git a/agents/claude.ts b/agents/claude.ts index bace135..36570fd 100644 --- a/agents/claude.ts +++ b/agents/claude.ts @@ -14,11 +14,11 @@ export const claude = agent({ executablePath: "cli.js", }); }, - run: async ({ payload, mcpServers, apiKey, cliPath }) => { + run: async ({ payload, mcpServers, apiKey, cliPath, prepResults }) => { // Ensure API key is NOT in process.env - only pass via SDK's env option delete process.env.ANTHROPIC_API_KEY; - const prompt = addInstructions(payload); + const prompt = addInstructions({ payload, prepResults }); console.log(prompt); // configure sandbox mode if enabled diff --git a/agents/codex.ts b/agents/codex.ts index 0627e42..c7007df 100644 --- a/agents/codex.ts +++ b/agents/codex.ts @@ -20,7 +20,7 @@ export const codex = agent({ executablePath: "bin/codex.js", }); }, - run: async ({ payload, mcpServers, apiKey, cliPath }) => { + run: async ({ payload, mcpServers, apiKey, cliPath, prepResults }) => { // create config directory for codex before setting HOME const tempHome = process.env.PULLFROG_TEMP_DIR!; const configDir = join(tempHome, ".config", "codex"); @@ -61,7 +61,7 @@ export const codex = agent({ ); try { - const streamedTurn = await thread.runStreamed(addInstructions(payload)); + const streamedTurn = await thread.runStreamed(addInstructions({ payload, prepResults })); let finalOutput = ""; for await (const event of streamedTurn.events) { diff --git a/agents/cursor.ts b/agents/cursor.ts index 0b5f39c..38ac9a5 100644 --- a/agents/cursor.ts +++ b/agents/cursor.ts @@ -91,7 +91,7 @@ export const cursor = agent({ executableName: "cursor-agent", }); }, - run: async ({ payload, apiKey, cliPath, mcpServers }) => { + run: async ({ payload, apiKey, cliPath, mcpServers, prepResults }) => { configureCursorMcpServers({ mcpServers, cliPath }); configureCursorSandbox({ sandbox: payload.sandbox ?? false }); @@ -166,7 +166,7 @@ export const cursor = agent({ }; try { - const fullPrompt = addInstructions(payload); + const fullPrompt = addInstructions({ payload, prepResults }); // configure sandbox mode if enabled // in sandbox mode: remove --force flag and rely on cli-config.json sandbox settings diff --git a/agents/gemini.ts b/agents/gemini.ts index d16d700..c1819e8 100644 --- a/agents/gemini.ts +++ b/agents/gemini.ts @@ -154,14 +154,14 @@ export const gemini = agent({ ...(githubInstallationToken && { githubInstallationToken }), }); }, - run: async ({ payload, apiKey, mcpServers, cliPath }) => { + run: async ({ payload, apiKey, mcpServers, cliPath, prepResults }) => { configureGeminiMcpServers({ mcpServers, cliPath }); if (!apiKey) { throw new Error("google_api_key or gemini_api_key is required for gemini agent"); } - const sessionPrompt = addInstructions(payload); + const sessionPrompt = addInstructions({ payload, prepResults }); log.info(`Starting Gemini CLI with prompt: ${payload.prompt.substring(0, 100)}...`); // configure sandbox mode if enabled diff --git a/agents/instructions.ts b/agents/instructions.ts index 69fd391..15730de 100644 --- a/agents/instructions.ts +++ b/agents/instructions.ts @@ -2,92 +2,79 @@ import { encode as toonEncode } from "@toon-format/toon"; import type { Payload } from "../external.ts"; import { ghPullfrogMcpName } from "../external.ts"; import { getModes } from "../modes.ts"; +import type { PrepResult } from "../prep/index.ts"; /** - * Extract only essential fields from event data to reduce token usage. - * Removes verbose GitHub API metadata (user objects, repository metadata, etc.) - * and keeps only the fields agents actually need. + * Format prep results into a human-readable string for the agent prompt */ -// function extractEssentialEventData(event: Payload["event"]): Record { -// const trigger = event.trigger; -// const essential: Record = { trigger }; +function formatPrepResults(results: PrepResult[]): string { + if (results.length === 0) { + return ""; + } -// // common fields -// if ("issue_number" in event) { -// essential.issue_number = event.issue_number; -// } -// if ("branch" in event && event.branch) { -// essential.branch = event.branch; -// } + const lines: string[] = []; -// // trigger-specific fields -// switch (trigger) { -// case "issue_comment_created": -// if ("comment_id" in event) essential.comment_id = event.comment_id; -// if ("comment_body" in event) essential.comment_body = event.comment_body; -// // include issue title/body if available in context (but not the entire context object) -// if ("context" in event && event.context && typeof event.context === "object") { -// const ctx = event.context as Record; -// if (ctx.issue && typeof ctx.issue === "object") { -// const issue = ctx.issue as Record; -// if (issue.title) essential.issue_title = issue.title; -// if (issue.body) essential.issue_body = issue.body; -// } -// } -// break; + for (const result of results) { + if (result.language === "unknown") { + continue; + } -// case "issues_opened": -// case "issues_assigned": -// case "issues_labeled": -// if ("issue_title" in event) essential.issue_title = event.issue_title; -// if ("issue_body" in event) essential.issue_body = event.issue_body; -// break; + const langDisplay = result.language === "node" ? "Node.js" : "Python"; -// case "pull_request_opened": -// case "pull_request_review_requested": -// if ("pr_title" in event) essential.pr_title = event.pr_title; -// if ("pr_body" in event) essential.pr_body = event.pr_body; -// if ("branch" in event) essential.branch = event.branch; -// break; + if (result.language === "node") { + if (result.dependenciesInstalled) { + lines.push( + `✅ ${langDisplay} dependencies installed successfully via \`${result.packageManager}\`.` + ); + } else { + lines.push( + `⚠️ ${langDisplay} dependency installation FAILED (using \`${result.packageManager}\`).` + ); + for (const issue of result.issues) { + lines.push(` - ${issue}`); + } + lines.push( + ` You may need to run \`${result.packageManager} install\` or address this issue before proceeding.` + ); + } + } -// case "pull_request_review_submitted": -// if ("review_id" in event) essential.review_id = event.review_id; -// if ("review_body" in event) essential.review_body = event.review_body; -// if ("review_state" in event) essential.review_state = event.review_state; -// if ("branch" in event) essential.branch = event.branch; -// break; + if (result.language === "python") { + if (result.dependenciesInstalled) { + lines.push( + `✅ ${langDisplay} dependencies installed successfully via \`${result.packageManager}\` (from ${result.configFile}).` + ); + } else { + lines.push( + `⚠️ ${langDisplay} dependency installation FAILED (using \`${result.packageManager}\` from ${result.configFile}).` + ); + for (const issue of result.issues) { + lines.push(` - ${issue}`); + } + lines.push( + ` You may need to run the appropriate install command or address this issue before proceeding.` + ); + } + } + } -// case "pull_request_review_comment_created": -// if ("comment_id" in event) essential.comment_id = event.comment_id; -// if ("comment_body" in event) essential.comment_body = event.comment_body; -// if ("pr_title" in event) essential.pr_title = event.pr_title; -// if ("branch" in event) essential.branch = event.branch; -// break; + if (lines.length === 0) { + return ""; + } -// case "check_suite_completed": -// if ("pr_title" in event) essential.pr_title = event.pr_title; -// if ("pr_body" in event) essential.pr_body = event.pr_body; -// if ("branch" in event) essential.branch = event.branch; -// if ("check_suite" in event) { -// essential.check_suite = { -// id: event.check_suite.id, -// head_sha: event.check_suite.head_sha, -// head_branch: event.check_suite.head_branch, -// status: event.check_suite.status, -// conclusion: event.check_suite.conclusion, -// }; -// } -// break; + return `************* ENVIRONMENT SETUP ************* -// case "workflow_dispatch": -// if ("inputs" in event) essential.inputs = event.inputs; -// break; -// } +${lines.join("\n")} -// return essential; -// } +`; +} -export const addInstructions = (payload: Payload) => { +interface AddInstructionsParams { + payload: Payload; + prepResults: PrepResult[]; +} + +export const addInstructions = ({ payload, prepResults }: AddInstructionsParams) => { let encodedEvent = ""; const eventKeys = Object.keys(payload.event); @@ -99,6 +86,9 @@ export const addInstructions = (payload: Payload) => { encodedEvent = toonEncode(payload.event); } + const envSetup = formatPrepResults(prepResults); + const dependenciesPreinstalled = prepResults.every((r) => r.dependenciesInstalled) || undefined; + return ` *********************************************** ************* SYSTEM INSTRUCTIONS ************* @@ -195,7 +185,7 @@ Before starting any work, you must first determine which mode to use by examinin Available modes: -${[...getModes({ disableProgressComment: payload.disableProgressComment }), ...payload.modes].map((w) => ` - "${w.name}": ${w.description}`).join("\n")} +${[...getModes({ disableProgressComment: payload.disableProgressComment, dependenciesPreinstalled }), ...payload.modes].map((w) => ` - "${w.name}": ${w.description}`).join("\n")} **Required first step**: 1. Examine the user's request/prompt carefully @@ -229,5 +219,6 @@ ${encodedEvent}` ************* RUNTIME CONTEXT ************* working_directory: ${process.cwd()} -`; + +${envSetup}`; }; diff --git a/agents/opencode.ts b/agents/opencode.ts index 4358f18..4803900 100644 --- a/agents/opencode.ts +++ b/agents/opencode.ts @@ -304,7 +304,7 @@ export const opencode = agent({ installDependencies: true, }); }, - run: async ({ payload, apiKey: _apiKey, apiKeys, mcpServers, cliPath }) => { + run: async ({ payload, apiKey: _apiKey, apiKeys, mcpServers, cliPath, prepResults }) => { // 1. configure home/config directory const tempHome = process.env.PULLFROG_TEMP_DIR!; const configDir = join(tempHome, ".config", "opencode"); @@ -313,7 +313,7 @@ export const opencode = agent({ configureOpenCodeMcpServers({ mcpServers }); configureOpenCodeSandbox({ sandbox: payload.sandbox ?? false }); - const prompt = addInstructions(payload); + const prompt = addInstructions({ payload, prepResults }); const args = ["run", "--format", "json", prompt]; if (payload.sandbox) { diff --git a/agents/shared.ts b/agents/shared.ts index 03de7c0..ae3b895 100644 --- a/agents/shared.ts +++ b/agents/shared.ts @@ -7,6 +7,7 @@ import { pipeline } from "node:stream/promises"; import type { McpHttpServerConfig } from "@anthropic-ai/claude-agent-sdk"; import type { show } from "@ark/util"; import { type AgentManifest, type AgentName, agentsManifest, type Payload } from "../external.ts"; +import type { PrepResult } from "../prep/index.ts"; import { log } from "../utils/cli.ts"; import { getGitHubInstallationToken } from "../utils/github.ts"; @@ -29,6 +30,7 @@ export interface AgentConfig { payload: Payload; mcpServers: Record; cliPath: string; + prepResults: PrepResult[]; } /** diff --git a/entry b/entry index c69e4db..30db37c 100755 --- a/entry +++ b/entry @@ -190,7 +190,7 @@ var require_file_command = __commonJS({ Object.defineProperty(exports, "__esModule", { value: true }); exports.prepareKeyValueMessage = exports.issueFileCommand = void 0; var crypto2 = __importStar(__require("crypto")); - var fs3 = __importStar(__require("fs")); + var fs4 = __importStar(__require("fs")); var os2 = __importStar(__require("os")); var utils_1 = require_utils(); function issueFileCommand(command, message) { @@ -198,10 +198,10 @@ var require_file_command = __commonJS({ if (!filePath) { throw new Error(`Unable to find environment variable for file command ${command}`); } - if (!fs3.existsSync(filePath)) { + if (!fs4.existsSync(filePath)) { throw new Error(`Missing file at path: ${filePath}`); } - fs3.appendFileSync(filePath, `${(0, utils_1.toCommandValue)(message)}${os2.EOL}`, { + fs4.appendFileSync(filePath, `${(0, utils_1.toCommandValue)(message)}${os2.EOL}`, { encoding: "utf8" }); } @@ -1004,14 +1004,14 @@ var require_util = __commonJS({ } const port = url2.port != null ? url2.port : url2.protocol === "https:" ? 443 : 80; let origin = url2.origin != null ? url2.origin : `${url2.protocol}//${url2.hostname}:${port}`; - let path3 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`; + let path4 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`; if (origin.endsWith("/")) { origin = origin.substring(0, origin.length - 1); } - if (path3 && !path3.startsWith("/")) { - path3 = `/${path3}`; + if (path4 && !path4.startsWith("/")) { + path4 = `/${path4}`; } - url2 = new URL(origin + path3); + url2 = new URL(origin + path4); } return url2; } @@ -2625,20 +2625,20 @@ var require_parseParams = __commonJS({ var require_basename = __commonJS({ "node_modules/.pnpm/@fastify+busboy@2.1.1/node_modules/@fastify/busboy/lib/utils/basename.js"(exports, module) { "use strict"; - module.exports = function basename(path3) { - if (typeof path3 !== "string") { + module.exports = function basename(path4) { + if (typeof path4 !== "string") { return ""; } - for (var i = path3.length - 1; i >= 0; --i) { - switch (path3.charCodeAt(i)) { + for (var i = path4.length - 1; i >= 0; --i) { + switch (path4.charCodeAt(i)) { case 47: // '/' case 92: - path3 = path3.slice(i + 1); - return path3 === ".." || path3 === "." ? "" : path3; + path4 = path4.slice(i + 1); + return path4 === ".." || path4 === "." ? "" : path4; } } - return path3 === ".." || path3 === "." ? "" : path3; + return path4 === ".." || path4 === "." ? "" : path4; }; } }); @@ -5668,7 +5668,7 @@ var require_request = __commonJS({ } var Request2 = class _Request { constructor(origin, { - path: path3, + path: path4, method, body, headers, @@ -5682,11 +5682,11 @@ var require_request = __commonJS({ throwOnError, expectContinue }, handler2) { - if (typeof path3 !== "string") { + if (typeof path4 !== "string") { throw new InvalidArgumentError("path must be a string"); - } else if (path3[0] !== "/" && !(path3.startsWith("http://") || path3.startsWith("https://")) && method !== "CONNECT") { + } else if (path4[0] !== "/" && !(path4.startsWith("http://") || path4.startsWith("https://")) && method !== "CONNECT") { throw new InvalidArgumentError("path must be an absolute URL or start with a slash"); - } else if (invalidPathRegex.exec(path3) !== null) { + } else if (invalidPathRegex.exec(path4) !== null) { throw new InvalidArgumentError("invalid request path"); } if (typeof method !== "string") { @@ -5749,7 +5749,7 @@ var require_request = __commonJS({ this.completed = false; this.aborted = false; this.upgrade = upgrade || null; - this.path = query2 ? util3.buildURL(path3, query2) : path3; + this.path = query2 ? util3.buildURL(path4, query2) : path4; this.origin = origin; this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent; this.blocking = blocking == null ? false : blocking; @@ -6757,9 +6757,9 @@ var require_RedirectHandler = __commonJS({ return this.handler.onHeaders(statusCode, headers, resume, statusText); } const { origin, pathname, search: search2 } = util3.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))); - const path3 = search2 ? `${pathname}${search2}` : pathname; + const path4 = search2 ? `${pathname}${search2}` : pathname; this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin); - this.opts.path = path3; + this.opts.path = path4; this.opts.origin = origin; this.opts.maxRedirections = 0; this.opts.query = null; @@ -7999,7 +7999,7 @@ var require_client = __commonJS({ writeH2(client, client[kHTTP2Session], request2); return; } - const { body, method, path: path3, host, upgrade, headers, blocking, reset } = request2; + const { body, method, path: path4, host, upgrade, headers, blocking, reset } = request2; const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH"; if (body && typeof body.read === "function") { body.read(0); @@ -8049,7 +8049,7 @@ var require_client = __commonJS({ if (blocking) { socket[kBlocking] = true; } - let header = `${method} ${path3} HTTP/1.1\r + let header = `${method} ${path4} HTTP/1.1\r `; if (typeof host === "string") { header += `host: ${host}\r @@ -8112,7 +8112,7 @@ upgrade: ${upgrade}\r return true; } function writeH2(client, session, request2) { - const { body, method, path: path3, host, upgrade, expectContinue, signal, headers: reqHeaders } = request2; + const { body, method, path: path4, host, upgrade, expectContinue, signal, headers: reqHeaders } = request2; let headers; if (typeof reqHeaders === "string") headers = Request2[kHTTP2CopyHeaders](reqHeaders.trim()); else headers = reqHeaders; @@ -8155,7 +8155,7 @@ upgrade: ${upgrade}\r }); return true; } - headers[HTTP2_HEADER_PATH] = path3; + headers[HTTP2_HEADER_PATH] = path4; headers[HTTP2_HEADER_SCHEME] = "https"; const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH"; if (body && typeof body.read === "function") { @@ -10395,20 +10395,20 @@ var require_mock_utils = __commonJS({ } return true; } - function safeUrl(path3) { - if (typeof path3 !== "string") { - return path3; + function safeUrl(path4) { + if (typeof path4 !== "string") { + return path4; } - const pathSegments = path3.split("?"); + const pathSegments = path4.split("?"); if (pathSegments.length !== 2) { - return path3; + return path4; } const qp = new URLSearchParams(pathSegments.pop()); qp.sort(); return [...pathSegments, qp.toString()].join("?"); } - function matchKey(mockDispatch2, { path: path3, method, body, headers }) { - const pathMatch = matchValue(mockDispatch2.path, path3); + function matchKey(mockDispatch2, { path: path4, method, body, headers }) { + const pathMatch = matchValue(mockDispatch2.path, path4); const methodMatch = matchValue(mockDispatch2.method, method); const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true; const headersMatch = matchHeaders(mockDispatch2, headers); @@ -10426,7 +10426,7 @@ var require_mock_utils = __commonJS({ function getMockDispatch(mockDispatches, key) { const basePath = key.query ? buildURL(key.path, key.query) : key.path; const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath; - let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path3 }) => matchValue(safeUrl(path3), resolvedPath)); + let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path4 }) => matchValue(safeUrl(path4), resolvedPath)); if (matchedMockDispatches.length === 0) { throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`); } @@ -10463,9 +10463,9 @@ var require_mock_utils = __commonJS({ } } function buildKey(opts) { - const { path: path3, method, body, headers, query: query2 } = opts; + const { path: path4, method, body, headers, query: query2 } = opts; return { - path: path3, + path: path4, method, body, headers, @@ -10914,10 +10914,10 @@ var require_pending_interceptors_formatter = __commonJS({ } format(pendingInterceptors) { const withPrettyHeaders = pendingInterceptors.map( - ({ method, path: path3, data: { statusCode }, persist, times, timesInvoked, origin }) => ({ + ({ method, path: path4, data: { statusCode }, persist, times, timesInvoked, origin }) => ({ Method: method, Origin: origin, - Path: path3, + Path: path4, "Status code": statusCode, Persistent: persist ? "\u2705" : "\u274C", Invocations: timesInvoked, @@ -15537,8 +15537,8 @@ var require_util6 = __commonJS({ } } } - function validateCookiePath(path3) { - for (const char of path3) { + function validateCookiePath(path4) { + for (const char of path4) { const code = char.charCodeAt(0); if (code < 33 || char === ";") { throw new Error("Invalid cookie path"); @@ -17218,11 +17218,11 @@ var require_undici = __commonJS({ if (typeof opts.path !== "string") { throw new InvalidArgumentError("invalid opts.path"); } - let path3 = opts.path; + let path4 = opts.path; if (!opts.path.startsWith("/")) { - path3 = `/${path3}`; + path4 = `/${path4}`; } - url2 = new URL(util3.parseOrigin(url2).origin + path3); + url2 = new URL(util3.parseOrigin(url2).origin + path4); } else { if (!opts) { opts = typeof url2 === "object" ? url2 : {}; @@ -18445,7 +18445,7 @@ var require_path_utils = __commonJS({ }; Object.defineProperty(exports, "__esModule", { value: true }); exports.toPlatformPath = exports.toWin32Path = exports.toPosixPath = void 0; - var path3 = __importStar(__require("path")); + var path4 = __importStar(__require("path")); function toPosixPath(pth) { return pth.replace(/[\\]/g, "/"); } @@ -18455,7 +18455,7 @@ var require_path_utils = __commonJS({ } exports.toWin32Path = toWin32Path; function toPlatformPath(pth) { - return pth.replace(/[/\\]/g, path3.sep); + return pth.replace(/[/\\]/g, path4.sep); } exports.toPlatformPath = toPlatformPath; } @@ -18518,12 +18518,12 @@ var require_io_util = __commonJS({ var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.READONLY = exports.UV_FS_O_EXLOCK = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.rename = exports.readlink = exports.readdir = exports.open = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0; - var fs3 = __importStar(__require("fs")); - var path3 = __importStar(__require("path")); - _a = fs3.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink; + var fs4 = __importStar(__require("fs")); + var path4 = __importStar(__require("path")); + _a = fs4.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink; exports.IS_WINDOWS = process.platform === "win32"; exports.UV_FS_O_EXLOCK = 268435456; - exports.READONLY = fs3.constants.O_RDONLY; + exports.READONLY = fs4.constants.O_RDONLY; function exists(fsPath) { return __awaiter(this, void 0, void 0, function* () { try { @@ -18568,7 +18568,7 @@ var require_io_util = __commonJS({ } if (stats && stats.isFile()) { if (exports.IS_WINDOWS) { - const upperExt = path3.extname(filePath).toUpperCase(); + const upperExt = path4.extname(filePath).toUpperCase(); if (extensions.some((validExt) => validExt.toUpperCase() === upperExt)) { return filePath; } @@ -18592,11 +18592,11 @@ var require_io_util = __commonJS({ if (stats && stats.isFile()) { if (exports.IS_WINDOWS) { try { - const directory = path3.dirname(filePath); - const upperName = path3.basename(filePath).toUpperCase(); + const directory = path4.dirname(filePath); + const upperName = path4.basename(filePath).toUpperCase(); for (const actualName of yield exports.readdir(directory)) { if (upperName === actualName.toUpperCase()) { - filePath = path3.join(directory, actualName); + filePath = path4.join(directory, actualName); break; } } @@ -18691,7 +18691,7 @@ var require_io = __commonJS({ Object.defineProperty(exports, "__esModule", { value: true }); exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0; var assert_1 = __require("assert"); - var path3 = __importStar(__require("path")); + var path4 = __importStar(__require("path")); var ioUtil = __importStar(require_io_util()); function cp(source, dest, options = {}) { return __awaiter(this, void 0, void 0, function* () { @@ -18700,7 +18700,7 @@ var require_io = __commonJS({ if (destStat && destStat.isFile() && !force) { return; } - const newDest = destStat && destStat.isDirectory() && copySourceDirectory ? path3.join(dest, path3.basename(source)) : dest; + const newDest = destStat && destStat.isDirectory() && copySourceDirectory ? path4.join(dest, path4.basename(source)) : dest; if (!(yield ioUtil.exists(source))) { throw new Error(`no such file or directory: ${source}`); } @@ -18712,7 +18712,7 @@ var require_io = __commonJS({ yield cpDirRecursive(source, newDest, 0, force); } } else { - if (path3.relative(source, newDest) === "") { + if (path4.relative(source, newDest) === "") { throw new Error(`'${newDest}' and '${source}' are the same file`); } yield copyFile(source, newDest, force); @@ -18725,7 +18725,7 @@ var require_io = __commonJS({ if (yield ioUtil.exists(dest)) { let destExists = true; if (yield ioUtil.isDirectory(dest)) { - dest = path3.join(dest, path3.basename(source)); + dest = path4.join(dest, path4.basename(source)); destExists = yield ioUtil.exists(dest); } if (destExists) { @@ -18736,7 +18736,7 @@ var require_io = __commonJS({ } } } - yield mkdirP(path3.dirname(dest)); + yield mkdirP(path4.dirname(dest)); yield ioUtil.rename(source, dest); }); } @@ -18799,7 +18799,7 @@ var require_io = __commonJS({ } const extensions = []; if (ioUtil.IS_WINDOWS && process.env["PATHEXT"]) { - for (const extension of process.env["PATHEXT"].split(path3.delimiter)) { + for (const extension of process.env["PATHEXT"].split(path4.delimiter)) { if (extension) { extensions.push(extension); } @@ -18812,12 +18812,12 @@ var require_io = __commonJS({ } return []; } - if (tool2.includes(path3.sep)) { + if (tool2.includes(path4.sep)) { return []; } const directories = []; if (process.env.PATH) { - for (const p of process.env.PATH.split(path3.delimiter)) { + for (const p of process.env.PATH.split(path4.delimiter)) { if (p) { directories.push(p); } @@ -18825,7 +18825,7 @@ var require_io = __commonJS({ } const matches = []; for (const directory of directories) { - const filePath = yield ioUtil.tryGetExecutablePath(path3.join(directory, tool2), extensions); + const filePath = yield ioUtil.tryGetExecutablePath(path4.join(directory, tool2), extensions); if (filePath) { matches.push(filePath); } @@ -18941,7 +18941,7 @@ var require_toolrunner = __commonJS({ var os2 = __importStar(__require("os")); var events = __importStar(__require("events")); var child = __importStar(__require("child_process")); - var path3 = __importStar(__require("path")); + var path4 = __importStar(__require("path")); var io = __importStar(require_io()); var ioUtil = __importStar(require_io_util()); var timers_1 = __require("timers"); @@ -19156,7 +19156,7 @@ var require_toolrunner = __commonJS({ exec() { return __awaiter(this, void 0, void 0, function* () { if (!ioUtil.isRooted(this.toolPath) && (this.toolPath.includes("/") || IS_WINDOWS && this.toolPath.includes("\\"))) { - this.toolPath = path3.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath); + this.toolPath = path4.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath); } this.toolPath = yield io.which(this.toolPath, true); return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { @@ -19656,7 +19656,7 @@ var require_core = __commonJS({ var file_command_1 = require_file_command(); var utils_1 = require_utils(); var os2 = __importStar(__require("os")); - var path3 = __importStar(__require("path")); + var path4 = __importStar(__require("path")); var oidc_utils_1 = require_oidc_utils(); var ExitCode; (function(ExitCode2) { @@ -19684,7 +19684,7 @@ var require_core = __commonJS({ } else { (0, command_1.issueCommand)("add-path", {}, inputPath); } - process.env["PATH"] = `${inputPath}${path3.delimiter}${process.env["PATH"]}`; + process.env["PATH"] = `${inputPath}${path4.delimiter}${process.env["PATH"]}`; } exports.addPath = addPath; function getInput2(name, options) { @@ -20804,15 +20804,15 @@ var require_route = __commonJS({ }; } function wrapConversion(toModel, graph) { - const path3 = [graph[toModel].parent, toModel]; + const path4 = [graph[toModel].parent, toModel]; let fn2 = conversions[graph[toModel].parent][toModel]; let cur = graph[toModel].parent; while (graph[cur].parent) { - path3.unshift(graph[cur].parent); + path4.unshift(graph[cur].parent); fn2 = link(conversions[graph[cur].parent][cur], fn2); cur = graph[cur].parent; } - fn2.conversion = path3; + fn2.conversion = path4; return fn2; } module.exports = function(fromModel) { @@ -26013,8 +26013,8 @@ var init_parseUtil = __esm({ init_errors(); init_en(); makeIssue2 = (params) => { - const { data, path: path3, errorMaps, issueData } = params; - const fullPath = [...path3, ...issueData.path || []]; + const { data, path: path4, errorMaps, issueData } = params; + const fullPath = [...path4, ...issueData.path || []]; const fullIssue = { ...issueData, path: fullPath @@ -26322,11 +26322,11 @@ var init_types = __esm({ init_parseUtil(); init_util(); ParseInputLazyPath2 = class { - constructor(parent, value2, path3, key) { + constructor(parent, value2, path4, key) { this._cachedPath = []; this.parent = parent; this.data = value2; - this._path = path3; + this._path = path4; this._key = key; } get path() { @@ -30529,8 +30529,8 @@ var require_uri_all2 = __commonJS({ wsComponents.secure = void 0; } if (wsComponents.resourceName) { - var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path3 = _wsComponents$resourc2[0], query2 = _wsComponents$resourc2[1]; - wsComponents.path = path3 && path3 !== "/" ? path3 : void 0; + var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path4 = _wsComponents$resourc2[0], query2 = _wsComponents$resourc2[1]; + wsComponents.path = path4 && path4 !== "/" ? path4 : void 0; wsComponents.query = query2; wsComponents.resourceName = void 0; } @@ -30868,12 +30868,12 @@ var require_util9 = __commonJS({ return "'" + escapeQuotes(str) + "'"; } function getPathExpr(currentPath, expr, jsonPointers, isNumber2) { - var path3 = jsonPointers ? "'/' + " + expr + (isNumber2 ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber2 ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'"; - return joinPaths(currentPath, path3); + var path4 = jsonPointers ? "'/' + " + expr + (isNumber2 ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber2 ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'"; + return joinPaths(currentPath, path4); } function getPath(currentPath, prop, jsonPointers) { - var path3 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop)); - return joinPaths(currentPath, path3); + var path4 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop)); + return joinPaths(currentPath, path4); } var JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/; var RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/; @@ -36962,14 +36962,14 @@ var require_util11 = __commonJS({ } const port = url2.port != null ? url2.port : url2.protocol === "https:" ? 443 : 80; let origin = url2.origin != null ? url2.origin : `${url2.protocol || ""}//${url2.hostname || ""}:${port}`; - let path3 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`; + let path4 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`; if (origin[origin.length - 1] === "/") { origin = origin.slice(0, origin.length - 1); } - if (path3 && path3[0] !== "/") { - path3 = `/${path3}`; + if (path4 && path4[0] !== "/") { + path4 = `/${path4}`; } - return new URL(`${origin}${path3}`); + return new URL(`${origin}${path4}`); } if (!isHttpOrHttpsPrefixed(url2.origin || url2.protocol)) { throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`."); @@ -37530,9 +37530,9 @@ var require_diagnostics = __commonJS({ "undici:client:sendHeaders", (evt) => { const { - request: { method, path: path3, origin } + request: { method, path: path4, origin } } = evt; - debugLog("sending request to %s %s%s", method, origin, path3); + debugLog("sending request to %s %s%s", method, origin, path4); } ); } @@ -37546,14 +37546,14 @@ var require_diagnostics = __commonJS({ "undici:request:headers", (evt) => { const { - request: { method, path: path3, origin }, + request: { method, path: path4, origin }, response: { statusCode } } = evt; debugLog( "received response to %s %s%s - HTTP %d", method, origin, - path3, + path4, statusCode ); } @@ -37562,23 +37562,23 @@ var require_diagnostics = __commonJS({ "undici:request:trailers", (evt) => { const { - request: { method, path: path3, origin } + request: { method, path: path4, origin } } = evt; - debugLog("trailers received from %s %s%s", method, origin, path3); + debugLog("trailers received from %s %s%s", method, origin, path4); } ); diagnosticsChannel.subscribe( "undici:request:error", (evt) => { const { - request: { method, path: path3, origin }, + request: { method, path: path4, origin }, error: error41 } = evt; debugLog( "request to %s %s%s errored - %s", method, origin, - path3, + path4, error41.message ); } @@ -37674,7 +37674,7 @@ var require_request3 = __commonJS({ var kHandler = Symbol("handler"); var Request2 = class { constructor(origin, { - path: path3, + path: path4, method, body, headers, @@ -37690,11 +37690,11 @@ var require_request3 = __commonJS({ throwOnError, maxRedirections }, handler2) { - if (typeof path3 !== "string") { + if (typeof path4 !== "string") { throw new InvalidArgumentError("path must be a string"); - } else if (path3[0] !== "/" && !(path3.startsWith("http://") || path3.startsWith("https://")) && method !== "CONNECT") { + } else if (path4[0] !== "/" && !(path4.startsWith("http://") || path4.startsWith("https://")) && method !== "CONNECT") { throw new InvalidArgumentError("path must be an absolute URL or start with a slash"); - } else if (invalidPathRegex.test(path3)) { + } else if (invalidPathRegex.test(path4)) { throw new InvalidArgumentError("invalid request path"); } if (typeof method !== "string") { @@ -37762,7 +37762,7 @@ var require_request3 = __commonJS({ this.completed = false; this.aborted = false; this.upgrade = upgrade || null; - this.path = query2 ? serializePathWithQuery(path3, query2) : path3; + this.path = query2 ? serializePathWithQuery(path4, query2) : path4; this.origin = origin; this.protocol = getProtocolFromUrlString(origin); this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent; @@ -42569,7 +42569,7 @@ var require_client_h1 = __commonJS({ return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT"; } function writeH1(client, request2) { - const { method, path: path3, host, upgrade, blocking, reset } = request2; + const { method, path: path4, host, upgrade, blocking, reset } = request2; let { body, headers, contentLength } = request2; const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH"; if (util3.isFormDataLike(body)) { @@ -42635,7 +42635,7 @@ var require_client_h1 = __commonJS({ if (blocking) { socket[kBlocking] = true; } - let header = `${method} ${path3} HTTP/1.1\r + let header = `${method} ${path4} HTTP/1.1\r `; if (typeof host === "string") { header += `host: ${host}\r @@ -43192,7 +43192,7 @@ var require_client_h2 = __commonJS({ function writeH2(client, request2) { const requestTimeout = request2.bodyTimeout ?? client[kBodyTimeout]; const session = client[kHTTP2Session]; - const { method, path: path3, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2; + const { method, path: path4, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request2; let { body } = request2; if (upgrade) { util3.errorRequest(client, request2, new Error("Upgrade not supported for H2")); @@ -43271,7 +43271,7 @@ var require_client_h2 = __commonJS({ stream.setTimeout(requestTimeout); return true; } - headers[HTTP2_HEADER_PATH] = path3; + headers[HTTP2_HEADER_PATH] = path4; headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https"; const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH"; if (body && typeof body.read === "function") { @@ -44743,10 +44743,10 @@ var require_proxy_agent2 = __commonJS({ }; const { origin, - path: path3 = "/", + path: path4 = "/", headers = {} } = opts; - opts.path = origin + path3; + opts.path = origin + path4; if (!("host" in headers) && !("Host" in headers)) { const { host } = new URL(origin); headers.host = host; @@ -46832,20 +46832,20 @@ var require_mock_utils2 = __commonJS({ } return normalizedQp; } - function safeUrl(path3) { - if (typeof path3 !== "string") { - return path3; + function safeUrl(path4) { + if (typeof path4 !== "string") { + return path4; } - const pathSegments = path3.split("?", 3); + const pathSegments = path4.split("?", 3); if (pathSegments.length !== 2) { - return path3; + return path4; } const qp = new URLSearchParams(pathSegments.pop()); qp.sort(); return [...pathSegments, qp.toString()].join("?"); } - function matchKey(mockDispatch2, { path: path3, method, body, headers }) { - const pathMatch = matchValue(mockDispatch2.path, path3); + function matchKey(mockDispatch2, { path: path4, method, body, headers }) { + const pathMatch = matchValue(mockDispatch2.path, path4); const methodMatch = matchValue(mockDispatch2.method, method); const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true; const headersMatch = matchHeaders(mockDispatch2, headers); @@ -46870,8 +46870,8 @@ var require_mock_utils2 = __commonJS({ const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path; const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath; const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath); - let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path3, ignoreTrailingSlash }) => { - return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path3)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path3), resolvedPath); + let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path4, ignoreTrailingSlash }) => { + return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path4)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path4), resolvedPath); }); if (matchedMockDispatches.length === 0) { throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`); @@ -46909,19 +46909,19 @@ var require_mock_utils2 = __commonJS({ mockDispatches.splice(index, 1); } } - function removeTrailingSlash(path3) { - while (path3.endsWith("/")) { - path3 = path3.slice(0, -1); + function removeTrailingSlash(path4) { + while (path4.endsWith("/")) { + path4 = path4.slice(0, -1); } - if (path3.length === 0) { - path3 = "/"; + if (path4.length === 0) { + path4 = "/"; } - return path3; + return path4; } function buildKey(opts) { - const { path: path3, method, body, headers, query: query2 } = opts; + const { path: path4, method, body, headers, query: query2 } = opts; return { - path: path3, + path: path4, method, body, headers, @@ -47579,10 +47579,10 @@ var require_pending_interceptors_formatter2 = __commonJS({ } format(pendingInterceptors) { const withPrettyHeaders = pendingInterceptors.map( - ({ method, path: path3, data: { statusCode }, persist, times, timesInvoked, origin }) => ({ + ({ method, path: path4, data: { statusCode }, persist, times, timesInvoked, origin }) => ({ Method: method, Origin: origin, - Path: path3, + Path: path4, "Status code": statusCode, Persistent: persist ? PERSISTENT : NOT_PERSISTENT, Invocations: timesInvoked, @@ -47662,9 +47662,9 @@ var require_mock_agent2 = __commonJS({ const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters]; const dispatchOpts = { ...opts }; if (acceptNonStandardSearchParameters && dispatchOpts.path) { - const [path3, searchParams] = dispatchOpts.path.split("?"); + const [path4, searchParams] = dispatchOpts.path.split("?"); const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters); - dispatchOpts.path = `${path3}?${normalizedSearchParams}`; + dispatchOpts.path = `${path4}?${normalizedSearchParams}`; } return this[kAgent].dispatch(dispatchOpts, handler2); } @@ -48061,12 +48061,12 @@ var require_snapshot_recorder = __commonJS({ * @return {Promise} - Resolves when snapshots are loaded */ async loadSnapshots(filePath) { - const path3 = filePath || this.#snapshotPath; - if (!path3) { + const path4 = filePath || this.#snapshotPath; + if (!path4) { throw new InvalidArgumentError("Snapshot path is required"); } try { - const data = await readFile(resolve(path3), "utf8"); + const data = await readFile(resolve(path4), "utf8"); const parsed2 = JSON.parse(data); if (Array.isArray(parsed2)) { this.#snapshots.clear(); @@ -48080,7 +48080,7 @@ var require_snapshot_recorder = __commonJS({ if (error41.code === "ENOENT") { this.#snapshots.clear(); } else { - throw new UndiciError(`Failed to load snapshots from ${path3}`, { cause: error41 }); + throw new UndiciError(`Failed to load snapshots from ${path4}`, { cause: error41 }); } } } @@ -48091,11 +48091,11 @@ var require_snapshot_recorder = __commonJS({ * @returns {Promise} - Resolves when snapshots are saved */ async saveSnapshots(filePath) { - const path3 = filePath || this.#snapshotPath; - if (!path3) { + const path4 = filePath || this.#snapshotPath; + if (!path4) { throw new InvalidArgumentError("Snapshot path is required"); } - const resolvedPath = resolve(path3); + const resolvedPath = resolve(path4); await mkdir(dirname2(resolvedPath), { recursive: true }); const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot2]) => ({ hash, @@ -48721,15 +48721,15 @@ var require_redirect_handler = __commonJS({ return; } const { origin, pathname, search: search2 } = util3.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))); - const path3 = search2 ? `${pathname}${search2}` : pathname; - const redirectUrlString = `${origin}${path3}`; + const path4 = search2 ? `${pathname}${search2}` : pathname; + const redirectUrlString = `${origin}${path4}`; for (const historyUrl of this.history) { if (historyUrl.toString() === redirectUrlString) { throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`); } } this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin); - this.opts.path = path3; + this.opts.path = path4; this.opts.origin = origin; this.opts.query = null; } @@ -49006,7 +49006,7 @@ var require_dns = __commonJS({ "node_modules/.pnpm/undici@7.16.0/node_modules/undici/lib/interceptor/dns.js"(exports, module) { "use strict"; var { isIP } = __require("node:net"); - var { lookup } = __require("node:dns"); + var { lookup: lookup2 } = __require("node:dns"); var DecoratorHandler = require_decorator_handler(); var { InvalidArgumentError, InformationalError } = require_errors2(); var maxInt = Math.pow(2, 31) - 1; @@ -49096,7 +49096,7 @@ var require_dns = __commonJS({ } } #defaultLookup(origin, opts, cb) { - lookup( + lookup2( origin.hostname, { all: true, @@ -55120,9 +55120,9 @@ var require_util14 = __commonJS({ } } } - function validateCookiePath(path3) { - for (let i = 0; i < path3.length; ++i) { - const code = path3.charCodeAt(i); + function validateCookiePath(path4) { + for (let i = 0; i < path4.length; ++i) { + const code = path4.charCodeAt(i); if (code < 32 || // exclude CTLs (0-31) code === 127 || // DEL code === 59) { @@ -58230,11 +58230,11 @@ var require_undici2 = __commonJS({ if (typeof opts.path !== "string") { throw new InvalidArgumentError("invalid opts.path"); } - let path3 = opts.path; + let path4 = opts.path; if (!opts.path.startsWith("/")) { - path3 = `/${path3}`; + path4 = `/${path4}`; } - url2 = new URL(util3.parseOrigin(url2).origin + path3); + url2 = new URL(util3.parseOrigin(url2).origin + path4); } else { if (!opts) { opts = typeof url2 === "object" ? url2 : {}; @@ -59032,10 +59032,10 @@ function assignProp(target, prop, value2) { configurable: true }); } -function getElementAtPath(obj, path3) { - if (!path3) +function getElementAtPath(obj, path4) { + if (!path4) return obj; - return path3.reduce((acc, key) => acc?.[key], obj); + return path4.reduce((acc, key) => acc?.[key], obj); } function promiseAllObject(promisesObj) { const keys = Object.keys(promisesObj); @@ -59284,11 +59284,11 @@ function aborted(x, startIndex = 0) { } return false; } -function prefixIssues(path3, issues) { +function prefixIssues(path4, issues) { return issues.map((iss) => { var _a; (_a = iss).path ?? (_a.path = []); - iss.path.unshift(path3); + iss.path.unshift(path4); return iss; }); } @@ -59477,7 +59477,7 @@ function treeifyError(error41, _mapper) { return issue2.message; }; const result = { errors: [] }; - const processError = (error42, path3 = []) => { + const processError = (error42, path4 = []) => { var _a, _b; for (const issue2 of error42.issues) { if (issue2.code === "invalid_union" && issue2.errors.length) { @@ -59487,7 +59487,7 @@ function treeifyError(error41, _mapper) { } else if (issue2.code === "invalid_element") { processError({ issues: issue2.issues }, issue2.path); } else { - const fullpath = [...path3, ...issue2.path]; + const fullpath = [...path4, ...issue2.path]; if (fullpath.length === 0) { result.errors.push(mapper(issue2)); continue; @@ -59517,9 +59517,9 @@ function treeifyError(error41, _mapper) { processError(error41); return result; } -function toDotPath(path3) { +function toDotPath(path4) { const segs = []; - for (const seg of path3) { + for (const seg of path4) { if (typeof seg === "number") segs.push(`[${seg}]`); else if (typeof seg === "symbol") @@ -71872,8 +71872,8 @@ var require_uri_all = __commonJS2((exports, module) => { wsComponents.secure = void 0; } if (wsComponents.resourceName) { - var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path3 = _wsComponents$resourc2[0], query2 = _wsComponents$resourc2[1]; - wsComponents.path = path3 && path3 !== "/" ? path3 : void 0; + var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path4 = _wsComponents$resourc2[0], query2 = _wsComponents$resourc2[1]; + wsComponents.path = path4 && path4 !== "/" ? path4 : void 0; wsComponents.query = query2; wsComponents.resourceName = void 0; } @@ -72260,12 +72260,12 @@ var require_util8 = __commonJS2((exports, module) => { return "'" + escapeQuotes(str) + "'"; } function getPathExpr(currentPath, expr, jsonPointers, isNumber2) { - var path3 = jsonPointers ? "'/' + " + expr + (isNumber2 ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber2 ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'"; - return joinPaths(currentPath, path3); + var path4 = jsonPointers ? "'/' + " + expr + (isNumber2 ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber2 ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'"; + return joinPaths(currentPath, path4); } function getPath(currentPath, prop, jsonPointers) { - var path3 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop)); - return joinPaths(currentPath, path3); + var path4 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop)); + return joinPaths(currentPath, path4); } var JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/; var RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/; @@ -77204,29 +77204,29 @@ var NodeFsOperations = { } } }, - appendFileSync(path3, data) { - fs.appendFileSync(path3, data); + appendFileSync(path4, data) { + fs.appendFileSync(path4, data); }, copyFileSync(src, dest) { fs.copyFileSync(src, dest); }, - unlinkSync(path3) { - fs.unlinkSync(path3); + unlinkSync(path4) { + fs.unlinkSync(path4); }, renameSync(oldPath, newPath) { fs.renameSync(oldPath, newPath); }, - linkSync(target, path3) { - fs.linkSync(target, path3); + linkSync(target, path4) { + fs.linkSync(target, path4); }, - symlinkSync(target, path3) { - fs.symlinkSync(target, path3); + symlinkSync(target, path4) { + fs.symlinkSync(target, path4); }, - readlinkSync(path3) { - return fs.readlinkSync(path3); + readlinkSync(path4) { + return fs.readlinkSync(path4); }, - realpathSync(path3) { - return fs.realpathSync(path3); + realpathSync(path4) { + return fs.realpathSync(path4); }, mkdirSync(dirPath) { if (!fs.existsSync(dirPath)) { @@ -77246,11 +77246,11 @@ var NodeFsOperations = { rmdirSync(dirPath) { fs.rmdirSync(dirPath); }, - rmSync(path3, options) { - fs.rmSync(path3, options); + rmSync(path4, options) { + fs.rmSync(path4, options); }, - createWriteStream(path3) { - return fs.createWriteStream(path3); + createWriteStream(path4) { + return fs.createWriteStream(path4); } }; var activeFs = NodeFsOperations; @@ -79153,8 +79153,8 @@ function getErrorMap() { return overrideErrorMap; } var makeIssue = (params) => { - const { data, path: path3, errorMaps, issueData } = params; - const fullPath = [...path3, ...issueData.path || []]; + const { data, path: path4, errorMaps, issueData } = params; + const fullPath = [...path4, ...issueData.path || []]; const fullIssue = { ...issueData, path: fullPath @@ -79262,11 +79262,11 @@ var errorUtil; errorUtil22.toString = (message) => typeof message === "string" ? message : message?.message; })(errorUtil || (errorUtil = {})); var ParseInputLazyPath = class { - constructor(parent, value2, path3, key) { + constructor(parent, value2, path4, key) { this._cachedPath = []; this.parent = parent; this.data = value2; - this._path = path3; + this._path = path4; this._key = key; } get path() { @@ -83361,6 +83361,7 @@ var package_default = { "@opencode-ai/sdk": "^1.0.143", "@standard-schema/spec": "1.0.0", arktype: "2.1.28", + "package-manager-detector": "^1.6.0", dotenv: "^17.2.3", execa: "^9.6.0", fastmcp: "^3.20.0", @@ -84677,29 +84678,29 @@ var timeWithUnnecessarySeconds = /:\d\d:00$/; var pad = (value2, length) => String(value2).padStart(length, "0"); // node_modules/.pnpm/@ark+util@0.56.0/node_modules/@ark/util/out/path.js -var appendStringifiedKey = (path3, prop, ...[opts]) => { +var appendStringifiedKey = (path4, prop, ...[opts]) => { const stringifySymbol = opts?.stringifySymbol ?? printable2; - let propAccessChain = path3; + let propAccessChain = path4; switch (typeof prop) { case "string": - propAccessChain = isDotAccessible2(prop) ? path3 === "" ? prop : `${path3}.${prop}` : `${path3}[${JSON.stringify(prop)}]`; + propAccessChain = isDotAccessible2(prop) ? path4 === "" ? prop : `${path4}.${prop}` : `${path4}[${JSON.stringify(prop)}]`; break; case "number": - propAccessChain = `${path3}[${prop}]`; + propAccessChain = `${path4}[${prop}]`; break; case "symbol": - propAccessChain = `${path3}[${stringifySymbol(prop)}]`; + propAccessChain = `${path4}[${stringifySymbol(prop)}]`; break; default: if (opts?.stringifyNonKey) - propAccessChain = `${path3}[${opts.stringifyNonKey(prop)}]`; + propAccessChain = `${path4}[${opts.stringifyNonKey(prop)}]`; else { throwParseError2(`${printable2(prop)} must be a PropertyKey or stringifyNonKey must be passed to options`); } } return propAccessChain; }; -var stringifyPath = (path3, ...opts) => path3.reduce((s, k) => appendStringifiedKey(s, k, ...opts), ""); +var stringifyPath = (path4, ...opts) => path4.reduce((s, k) => appendStringifiedKey(s, k, ...opts), ""); var ReadonlyPath = class extends ReadonlyArray2 { // alternate strategy for caching since the base object is frozen cache = {}; @@ -84726,8 +84727,8 @@ var ReadonlyPath = class extends ReadonlyArray2 { return this.cache.stringifyAncestors; let propString = ""; const result = [propString]; - for (const path3 of this) { - propString = appendStringifiedKey(propString, path3); + for (const path4 of this) { + propString = appendStringifiedKey(propString, path4); result.push(propString); } return this.cache.stringifyAncestors = result; @@ -85370,15 +85371,15 @@ var ArkErrors = class _ArkErrors extends ReadonlyArray2 { /** * @internal */ - affectsPath(path3) { + affectsPath(path4) { if (this.length === 0) return false; return ( // this would occur if there is an existing error at a prefix of path // e.g. the path is ["foo", "bar"] and there is an error at ["foo"] - path3.stringifyAncestors().some((s) => s in this.byPath) || // this would occur if there is an existing error at a suffix of path + path4.stringifyAncestors().some((s) => s in this.byPath) || // this would occur if there is an existing error at a suffix of path // e.g. the path is ["foo"] and there is an error at ["foo", "bar"] - path3.stringify() in this.byAncestorPath + path4.stringify() in this.byAncestorPath ); } /** @@ -85565,23 +85566,23 @@ var Traversal = class { while (this.queuedMorphs.length) { const queuedMorphs = this.queuedMorphs; this.queuedMorphs = []; - for (const { path: path3, morphs } of queuedMorphs) { - if (this.errors.affectsPath(path3)) + for (const { path: path4, morphs } of queuedMorphs) { + if (this.errors.affectsPath(path4)) continue; - this.applyMorphsAtPath(path3, morphs); + this.applyMorphsAtPath(path4, morphs); } } } - applyMorphsAtPath(path3, morphs) { - const key = path3[path3.length - 1]; + applyMorphsAtPath(path4, morphs) { + const key = path4[path4.length - 1]; let parent; if (key !== void 0) { parent = this.root; - for (let pathIndex = 0; pathIndex < path3.length - 1; pathIndex++) - parent = parent[path3[pathIndex]]; + for (let pathIndex = 0; pathIndex < path4.length - 1; pathIndex++) + parent = parent[path4[pathIndex]]; } for (const morph of morphs) { - this.path = [...path3]; + this.path = [...path4]; const morphIsNode = isNode(morph); const result = morph(parent === void 0 ? this.root : parent[key], this); if (result instanceof ArkError) { @@ -85957,15 +85958,15 @@ var NodeSelector = { normalize: (selector) => typeof selector === "function" ? { boundary: "references", method: "filter", where: selector } : typeof selector === "string" ? isKeyOf2(selector, NodeSelector.applyBoundary) ? { method: "filter", boundary: selector } : { boundary: "references", method: "filter", kind: selector } : { boundary: "references", method: "filter", ...selector } }; var writeSelectAssertionMessage = (from, selector) => `${from} had no references matching ${printable2(selector)}.`; -var typePathToPropString = (path3) => stringifyPath(path3, { +var typePathToPropString = (path4) => stringifyPath(path4, { stringifyNonKey: (node2) => node2.expression }); var referenceMatcher = /"(\$ark\.[^"]+)"/g; var compileMeta = (metaJson) => JSON.stringify(metaJson).replace(referenceMatcher, "$1"); -var flatRef = (path3, node2) => ({ - path: path3, +var flatRef = (path4, node2) => ({ + path: path4, node: node2, - propString: typePathToPropString(path3) + propString: typePathToPropString(path4) }); var flatRefsAreEqual = (l, r) => l.propString === r.propString && l.node.equals(r.node); var appendUniqueFlatRefs = (existing, refs) => appendUnique(existing, refs, { @@ -86001,12 +86002,12 @@ var Disjoint = class _Disjoint extends Array { } describeReasons() { if (this.length === 1) { - const { path: path3, l, r } = this[0]; - const pathString = stringifyPath(path3); + const { path: path4, l, r } = this[0]; + const pathString = stringifyPath(path4); return writeUnsatisfiableExpressionError(`Intersection${pathString && ` at ${pathString}`} of ${describeReasons(l, r)}`); } return `The following intersections result in unsatisfiable types: -\u2022 ${this.map(({ path: path3, l, r }) => `${path3}: ${describeReasons(l, r)}`).join("\n\u2022 ")}`; +\u2022 ${this.map(({ path: path4, l, r }) => `${path4}: ${describeReasons(l, r)}`).join("\n\u2022 ")}`; } throw() { return throwParseError2(this.describeReasons()); @@ -87403,10 +87404,10 @@ var BaseRoot = class extends BaseNode { }); }); } - get(...path3) { - if (path3[0] === void 0) + get(...path4) { + if (path4[0] === void 0) return this; - return this.$.schema(this.applyStructuralOperation("get", path3)); + return this.$.schema(this.applyStructuralOperation("get", path4)); } extract(r) { const rNode = this.$.parseDefinition(r); @@ -88348,13 +88349,13 @@ var implementation17 = implementNode({ description: (node2) => node2.distribute((branch) => branch.description, describeBranches), expected: (ctx) => { const byPath = groupBy(ctx.errors, "propString"); - const pathDescriptions = Object.entries(byPath).map(([path3, errors]) => { + const pathDescriptions = Object.entries(byPath).map(([path4, errors]) => { const branchesAtPath = []; for (const errorAtPath of errors) appendUnique(branchesAtPath, errorAtPath.expected); const expected = describeBranches(branchesAtPath); const actual = errors.every((e) => e.actual === errors[0].actual) ? errors[0].actual : printable2(errors[0].data); - return `${path3 && `${path3} `}must be ${expected}${actual && ` (was ${actual})`}`; + return `${path4 && `${path4} `}must be ${expected}${actual && ` (was ${actual})`}`; }); return describeBranches(pathDescriptions); }, @@ -88736,10 +88737,10 @@ var viableOrderedCandidates = (candidates, originalBranches) => { }); return viableCandidates; }; -var discriminantCaseToNode = (caseDiscriminant, path3, $2) => { +var discriminantCaseToNode = (caseDiscriminant, path4, $2) => { let node2 = caseDiscriminant === "undefined" ? $2.node("unit", { unit: void 0 }) : caseDiscriminant === "null" ? $2.node("unit", { unit: null }) : caseDiscriminant === "boolean" ? $2.units([true, false]) : caseDiscriminant; - for (let i = path3.length - 1; i >= 0; i--) { - const key = path3[i]; + for (let i = path4.length - 1; i >= 0; i--) { + const key = path4[i]; node2 = $2.node("intersection", typeof key === "number" ? { proto: "Array", // create unknown for preceding elements (could be optimized with safe imports) @@ -88751,7 +88752,7 @@ var discriminantCaseToNode = (caseDiscriminant, path3, $2) => { } return node2; }; -var optionallyChainPropString = (path3) => path3.reduce((acc, k) => acc + compileLiteralPropAccess(k, true), "data"); +var optionallyChainPropString = (path4) => path4.reduce((acc, k) => acc + compileLiteralPropAccess(k, true), "data"); var serializedTypeOfDescriptions = registeredReference(jsTypeOfDescriptions2); var serializedPrintable = registeredReference(printable2); var Union = { @@ -89737,7 +89738,7 @@ var StructureNode = class extends BaseConstraint { return throwParseError2(writeInvalidKeysMessage(this.expression, invalidKeys)); } } - get(indexer, ...path3) { + get(indexer, ...path4) { let value2; let required2 = false; const key = indexerToKey(indexer); @@ -89773,7 +89774,7 @@ var StructureNode = class extends BaseConstraint { } return throwParseError2(writeInvalidKeysMessage(this.expression, [key])); } - const result = value2.get(...path3); + const result = value2.get(...path4); return required2 ? result : result.or($ark.intrinsic.undefined); } pick(...keys) { @@ -91682,12 +91683,12 @@ var parseStandardSchema = (def, ctx) => ctx.$.intrinsic.unknown.pipe((v, ctx2) = const result = def["~standard"].validate(v); if (!result.issues) return result.value; - for (const { message, path: path3 } of result.issues) { - if (path3) { - if (path3.length) { + for (const { message, path: path4 } of result.issues) { + if (path4) { + if (path4.length) { ctx2.error({ problem: uncapitalize(message), - relativePath: path3.map((k) => typeof k === "object" ? k.key : k) + relativePath: path4.map((k) => typeof k === "object" ? k.key : k) }); } else { ctx2.error({ @@ -92551,13 +92552,17 @@ var AgentName = type.enumerated(...Object.keys(agentsManifest)); // modes.ts var reportProgressInstruction = `Use ${ghPullfrogMcpName}/report_progress to share progress and results. Continue calling it as you make progress - it will update the same comment. Never create additional comments manually.`; -function getModes({ disableProgressComment }) { +function getModes({ + disableProgressComment, + dependenciesPreinstalled +}) { + const depsContext = dependenciesPreinstalled ? "Dependencies have already been installed." : "understand how to install dependencies,"; return [ { 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. 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. +1. If the request requires understanding the codebase structure, dependencies, or conventions, gather relevant context. Read AGENTS.md if it exists, ${depsContext} run tests, run builds, and make changes according to best practices). Skip this step if the prompt is trivial and self-contained. 2. Create a branch using ${ghPullfrogMcpName}/create_branch. The branch name should be prefixed with "pullfrog/". The rest of the name should reflect the exact changes you are making. It should be specific to avoid collisions with other branches. Never commit directly to main, master, or production. Do NOT use git commands directly - always use ${ghPullfrogMcpName} MCP tools for git operations. @@ -92647,7 +92652,7 @@ ${disableProgressComment ? "" : ` 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. 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. +1. If the request requires understanding the codebase structure, dependencies, or conventions, gather relevant context (read AGENTS.md if it exists, ${depsContext} run tests, run builds, and make changes according to best practices). Skip this step if the prompt is trivial and self-contained. 2. Analyze the request and break it down into clear, actionable tasks @@ -92676,16 +92681,75 @@ ${disableProgressComment ? "" : ` } ]; } -var modes = getModes({ disableProgressComment: void 0 }); +var modes = getModes({ + disableProgressComment: void 0, + dependenciesPreinstalled: void 0 +}); // agents/instructions.ts -var addInstructions = (payload) => { +function formatPrepResults(results) { + if (results.length === 0) { + return ""; + } + const lines = []; + for (const result of results) { + if (result.language === "unknown") { + continue; + } + const langDisplay = result.language === "node" ? "Node.js" : "Python"; + if (result.language === "node") { + if (result.dependenciesInstalled) { + lines.push( + `\u2705 ${langDisplay} dependencies installed successfully via \`${result.packageManager}\`.` + ); + } else { + lines.push( + `\u26A0\uFE0F ${langDisplay} dependency installation FAILED (using \`${result.packageManager}\`).` + ); + for (const issue2 of result.issues) { + lines.push(` - ${issue2}`); + } + lines.push( + ` You may need to run \`${result.packageManager} install\` or address this issue before proceeding.` + ); + } + } + if (result.language === "python") { + if (result.dependenciesInstalled) { + lines.push( + `\u2705 ${langDisplay} dependencies installed successfully via \`${result.packageManager}\` (from ${result.configFile}).` + ); + } else { + lines.push( + `\u26A0\uFE0F ${langDisplay} dependency installation FAILED (using \`${result.packageManager}\` from ${result.configFile}).` + ); + for (const issue2 of result.issues) { + lines.push(` - ${issue2}`); + } + lines.push( + ` You may need to run the appropriate install command or address this issue before proceeding.` + ); + } + } + } + if (lines.length === 0) { + return ""; + } + return `************* ENVIRONMENT SETUP ************* + +${lines.join("\n")} + +`; +} +var addInstructions = ({ payload, prepResults }) => { let encodedEvent = ""; const eventKeys = Object.keys(payload.event); if (eventKeys.length === 1 && eventKeys[0] === "trigger") { } else { encodedEvent = encode(payload.event); } + const envSetup = formatPrepResults(prepResults); + const dependenciesPreinstalled = prepResults.every((r) => r.dependenciesInstalled) || void 0; return ` *********************************************** ************* SYSTEM INSTRUCTIONS ************* @@ -92782,7 +92846,7 @@ Before starting any work, you must first determine which mode to use by examinin Available modes: -${[...getModes({ disableProgressComment: payload.disableProgressComment }), ...payload.modes].map((w) => ` - "${w.name}": ${w.description}`).join("\n")} +${[...getModes({ disableProgressComment: payload.disableProgressComment, dependenciesPreinstalled }), ...payload.modes].map((w) => ` - "${w.name}": ${w.description}`).join("\n")} **Required first step**: 1. Examine the user's request/prompt carefully @@ -92812,7 +92876,8 @@ ${encodedEvent}` : ""} ************* RUNTIME CONTEXT ************* working_directory: ${process.cwd()} -`; + +${envSetup}`; }; // agents/shared.ts @@ -92882,9 +92947,9 @@ var generateJWT = (appId, privateKey) => { const signature = createSign("RSA-SHA256").update(signaturePart).sign(privateKey, "base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); return `${signaturePart}.${signature}`; }; -var githubRequest = async (path3, options = {}) => { +var githubRequest = async (path4, options = {}) => { const { method = "GET", headers = {}, body } = options; - const url2 = `https://api.github.com${path3}`; + const url2 = `https://api.github.com${path4}`; const requestHeaders = { Accept: "application/vnd.github.v3+json", "User-Agent": "Pullfrog-Installation-Token-Generator/1.0", @@ -93233,9 +93298,9 @@ var claude = agent({ executablePath: "cli.js" }); }, - run: async ({ payload, mcpServers, apiKey, cliPath }) => { + run: async ({ payload, mcpServers, apiKey, cliPath, prepResults }) => { delete process.env.ANTHROPIC_API_KEY; - const prompt = addInstructions(payload); + const prompt = addInstructions({ payload, prepResults }); console.log(prompt); const sandboxOptions = payload.sandbox ? { permissionMode: "default", @@ -93691,7 +93756,7 @@ var codex = agent({ executablePath: "bin/codex.js" }); }, - run: async ({ payload, mcpServers, apiKey, cliPath }) => { + run: async ({ payload, mcpServers, apiKey, cliPath, prepResults }) => { const tempHome = process.env.PULLFROG_TEMP_DIR; const configDir = join5(tempHome, ".config", "codex"); mkdirSync2(configDir, { recursive: true }); @@ -93721,7 +93786,7 @@ var codex = agent({ } ); try { - const streamedTurn = await thread.runStreamed(addInstructions(payload)); + const streamedTurn = await thread.runStreamed(addInstructions({ payload, prepResults })); let finalOutput2 = ""; for await (const event of streamedTurn.events) { const handler2 = messageHandlers2[event.type]; @@ -93863,7 +93928,7 @@ var cursor = agent({ executableName: "cursor-agent" }); }, - run: async ({ payload, apiKey, cliPath, mcpServers }) => { + run: async ({ payload, apiKey, cliPath, mcpServers, prepResults }) => { configureCursorMcpServers({ mcpServers, cliPath }); configureCursorSandbox({ sandbox: payload.sandbox ?? false }); const loggedModelCallIds = /* @__PURE__ */ new Set(); @@ -93916,7 +93981,7 @@ var cursor = agent({ } }; try { - const fullPrompt = addInstructions(payload); + const fullPrompt = addInstructions({ payload, prepResults }); const cursorArgs = payload.sandbox ? [ "--print", fullPrompt, @@ -94220,12 +94285,12 @@ var gemini = agent({ ...githubInstallationToken2 && { githubInstallationToken: githubInstallationToken2 } }); }, - run: async ({ payload, apiKey, mcpServers, cliPath }) => { + run: async ({ payload, apiKey, mcpServers, cliPath, prepResults }) => { configureGeminiMcpServers({ mcpServers, cliPath }); if (!apiKey) { throw new Error("google_api_key or gemini_api_key is required for gemini agent"); } - const sessionPrompt = addInstructions(payload); + const sessionPrompt = addInstructions({ payload, prepResults }); log.info(`Starting Gemini CLI with prompt: ${payload.prompt.substring(0, 100)}...`); const args3 = payload.sandbox ? [ "--allowed-tools", @@ -94481,13 +94546,13 @@ var opencode = agent({ installDependencies: true }); }, - run: async ({ payload, apiKey: _apiKey, apiKeys, mcpServers, cliPath }) => { + run: async ({ payload, apiKey: _apiKey, apiKeys, mcpServers, cliPath, prepResults }) => { const tempHome = process.env.PULLFROG_TEMP_DIR; const configDir = join7(tempHome, ".config", "opencode"); mkdirSync4(configDir, { recursive: true }); configureOpenCodeMcpServers({ mcpServers }); configureOpenCodeSandbox({ sandbox: payload.sandbox ?? false }); - const prompt = addInstructions(payload); + const prompt = addInstructions({ payload, prepResults }); const args3 = ["run", "--format", "json", prompt]; if (payload.sandbox) { log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); @@ -94672,7 +94737,7 @@ var agents = { // main.ts import { mkdtemp as mkdtemp2 } from "node:fs/promises"; import { tmpdir as tmpdir2 } from "node:os"; -import { join as join8 } from "node:path"; +import { join as join10 } from "node:path"; // node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js function getUserAgent() { @@ -95618,17 +95683,17 @@ function requestLog(octokit) { octokit.log.debug("request", options); const start = Date.now(); const requestOptions = octokit.request.endpoint.parse(options); - const path3 = requestOptions.url.replace(options.baseUrl, ""); + const path4 = requestOptions.url.replace(options.baseUrl, ""); return request2(options).then((response) => { const requestId = response.headers["x-github-request-id"]; octokit.log.info( - `${requestOptions.method} ${path3} - ${response.status} with id ${requestId} in ${Date.now() - start}ms` + `${requestOptions.method} ${path4} - ${response.status} with id ${requestId} in ${Date.now() - start}ms` ); return response; }).catch((error41) => { const requestId = error41.response?.headers["x-github-request-id"] || "UNKNOWN"; octokit.log.error( - `${requestOptions.method} ${path3} - ${error41.status} with id ${requestId} in ${Date.now() - start}ms` + `${requestOptions.method} ${path4} - ${error41.status} with id ${requestId} in ${Date.now() - start}ms` ); throw error41; }); @@ -100326,14 +100391,14 @@ var KeyStore = class { } }; function createKey(key) { - let path3 = null; + let path4 = null; let id = null; let src = null; let weight = 1; let getFn = null; if (isString(key) || isArray2(key)) { src = key; - path3 = createKeyPath(key); + path4 = createKeyPath(key); id = createKeyId(key); } else { if (!hasOwn.call(key, "name")) { @@ -100347,11 +100412,11 @@ function createKey(key) { throw new Error(INVALID_KEY_WEIGHT_VALUE(name)); } } - path3 = createKeyPath(name); + path4 = createKeyPath(name); id = createKeyId(name); getFn = key.getFn; } - return { path: path3, id, weight, src, getFn }; + return { path: path4, id, weight, src, getFn }; } function createKeyPath(key) { return isArray2(key) ? key : key.split("."); @@ -100359,34 +100424,34 @@ function createKeyPath(key) { function createKeyId(key) { return isArray2(key) ? key.join(".") : key; } -function get(obj, path3) { +function get(obj, path4) { let list = []; let arr = false; - const deepGet = (obj2, path4, index) => { + const deepGet = (obj2, path5, index) => { if (!isDefined2(obj2)) { return; } - if (!path4[index]) { + if (!path5[index]) { list.push(obj2); } else { - let key = path4[index]; + let key = path5[index]; const value2 = obj2[key]; if (!isDefined2(value2)) { return; } - if (index === path4.length - 1 && (isString(value2) || isNumber(value2) || isBoolean(value2))) { + if (index === path5.length - 1 && (isString(value2) || isNumber(value2) || isBoolean(value2))) { list.push(toString(value2)); } else if (isArray2(value2)) { arr = true; for (let i = 0, len = value2.length; i < len; i += 1) { - deepGet(value2[i], path4, index + 1); + deepGet(value2[i], path5, index + 1); } - } else if (path4.length) { - deepGet(value2, path4, index + 1); + } else if (path5.length) { + deepGet(value2, path5, index + 1); } } }; - deepGet(obj, isString(path3) ? path3.split(".") : path3, 0); + deepGet(obj, isString(path4) ? path4.split(".") : path4, 0); return arr ? list : list[0]; } var MatchOptions = { @@ -101959,8 +102024,8 @@ function getErrorMap3() { return overrideErrorMap3; } var makeIssue3 = (params) => { - const { data, path: path3, errorMaps, issueData } = params; - const fullPath = [...path3, ...issueData.path || []]; + const { data, path: path4, errorMaps, issueData } = params; + const fullPath = [...path4, ...issueData.path || []]; const fullIssue = { ...issueData, path: fullPath @@ -102066,11 +102131,11 @@ var errorUtil3; errorUtil$1.toString = (message) => typeof message === "string" ? message : message?.message; })(errorUtil3 || (errorUtil3 = {})); var ParseInputLazyPath3 = class { - constructor(parent, value2, path3, key$1) { + constructor(parent, value2, path4, key$1) { this._cachedPath = []; this.parent = parent; this.data = value2; - this._path = path3; + this._path = path4; this._key = key$1; } get path() { @@ -116793,8 +116858,8 @@ var require_uri_all3 = /* @__PURE__ */ __commonJS3({ "node_modules/.pnpm/uri-js@ wsComponents.secure = void 0; } if (wsComponents.resourceName) { - var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path3 = _wsComponents$resourc2[0], query2 = _wsComponents$resourc2[1]; - wsComponents.path = path3 && path3 !== "/" ? path3 : void 0; + var _wsComponents$resourc = wsComponents.resourceName.split("?"), _wsComponents$resourc2 = slicedToArray(_wsComponents$resourc, 2), path4 = _wsComponents$resourc2[0], query2 = _wsComponents$resourc2[1]; + wsComponents.path = path4 && path4 !== "/" ? path4 : void 0; wsComponents.query = query2; wsComponents.resourceName = void 0; } @@ -117131,12 +117196,12 @@ var require_util10 = /* @__PURE__ */ __commonJS3({ "node_modules/.pnpm/ajv@6.12. return "'" + escapeQuotes(str) + "'"; } function getPathExpr(currentPath, expr, jsonPointers, isNumber2) { - var path3 = jsonPointers ? "'/' + " + expr + (isNumber2 ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber2 ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'"; - return joinPaths(currentPath, path3); + var path4 = jsonPointers ? "'/' + " + expr + (isNumber2 ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber2 ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'"; + return joinPaths(currentPath, path4); } function getPath(currentPath, prop, jsonPointers) { - var path3 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop)); - return joinPaths(currentPath, path3); + var path4 = jsonPointers ? toQuotedString("/" + escapeJsonPointer(prop)) : toQuotedString(getProperty(prop)); + return joinPaths(currentPath, path4); } var JSON_POINTER$1 = /^\/(?:[^~]|~0|~1)*$/; var RELATIVE_JSON_POINTER$1 = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/; @@ -122311,8 +122376,8 @@ ${error41 instanceof Error ? error41.stack : JSON.stringify(error41)}` ); if (parsed2.issues) { const friendlyErrors = this.#utils?.formatInvalidParamsErrorMessage ? this.#utils.formatInvalidParamsErrorMessage(parsed2.issues) : parsed2.issues.map((issue2) => { - const path3 = issue2.path?.join(".") || "root"; - return `${path3}: ${issue2.message}`; + const path4 = issue2.path?.join(".") || "root"; + return `${path4}: ${issue2.message}`; }).join(", "); throw new McpError( ErrorCode2.InvalidParams, @@ -122756,10 +122821,10 @@ var FastMCP = class extends FastMCPEventEmitter { const healthConfig = this.#options.health ?? {}; const enabled = healthConfig.enabled === void 0 ? true : healthConfig.enabled; if (enabled) { - const path3 = healthConfig.path ?? "/health"; + const path4 = healthConfig.path ?? "/health"; const url2 = new URL(req.url || "", `http://${host}`); try { - if (req.method === "GET" && url2.pathname === path3) { + if (req.method === "GET" && url2.pathname === path4) { res.writeHead(healthConfig.status ?? 200, { "Content-Type": "text/plain" }).end(healthConfig.message ?? "\u2713 Ok"); @@ -123789,6 +123854,556 @@ async function startMcpHttpServer(ctx) { }; } +// prep/installNodeDependencies.ts +import { existsSync as existsSync4 } from "node:fs"; +import { join as join8 } from "node:path"; + +// node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/commands.mjs +function dashDashArg(agent2, agentCommand) { + return (args3) => { + if (args3.length > 1) { + return [agent2, agentCommand, args3[0], "--", ...args3.slice(1)]; + } else { + return [agent2, agentCommand, args3[0]]; + } + }; +} +function denoExecute() { + return (args3) => { + return ["deno", "run", `npm:${args3[0]}`, ...args3.slice(1)]; + }; +} +var npm = { + "agent": ["npm", 0], + "run": dashDashArg("npm", "run"), + "install": ["npm", "i", 0], + "frozen": ["npm", "ci", 0], + "global": ["npm", "i", "-g", 0], + "add": ["npm", "i", 0], + "upgrade": ["npm", "update", 0], + "upgrade-interactive": null, + "dedupe": ["npm", "dedupe", 0], + "execute": ["npx", 0], + "execute-local": ["npx", 0], + "uninstall": ["npm", "uninstall", 0], + "global_uninstall": ["npm", "uninstall", "-g", 0] +}; +var yarn = { + "agent": ["yarn", 0], + "run": ["yarn", "run", 0], + "install": ["yarn", "install", 0], + "frozen": ["yarn", "install", "--frozen-lockfile", 0], + "global": ["yarn", "global", "add", 0], + "add": ["yarn", "add", 0], + "upgrade": ["yarn", "upgrade", 0], + "upgrade-interactive": ["yarn", "upgrade-interactive", 0], + "dedupe": null, + "execute": ["npx", 0], + "execute-local": dashDashArg("yarn", "exec"), + "uninstall": ["yarn", "remove", 0], + "global_uninstall": ["yarn", "global", "remove", 0] +}; +var yarnBerry = { + ...yarn, + "frozen": ["yarn", "install", "--immutable", 0], + "upgrade": ["yarn", "up", 0], + "upgrade-interactive": ["yarn", "up", "-i", 0], + "dedupe": ["yarn", "dedupe", 0], + "execute": ["yarn", "dlx", 0], + "execute-local": ["yarn", "exec", 0], + // Yarn 2+ removed 'global', see https://github.com/yarnpkg/berry/issues/821 + "global": ["npm", "i", "-g", 0], + "global_uninstall": ["npm", "uninstall", "-g", 0] +}; +var pnpm = { + "agent": ["pnpm", 0], + "run": ["pnpm", "run", 0], + "install": ["pnpm", "i", 0], + "frozen": ["pnpm", "i", "--frozen-lockfile", 0], + "global": ["pnpm", "add", "-g", 0], + "add": ["pnpm", "add", 0], + "upgrade": ["pnpm", "update", 0], + "upgrade-interactive": ["pnpm", "update", "-i", 0], + "dedupe": ["pnpm", "dedupe", 0], + "execute": ["pnpm", "dlx", 0], + "execute-local": ["pnpm", "exec", 0], + "uninstall": ["pnpm", "remove", 0], + "global_uninstall": ["pnpm", "remove", "--global", 0] +}; +var bun = { + "agent": ["bun", 0], + "run": ["bun", "run", 0], + "install": ["bun", "install", 0], + "frozen": ["bun", "install", "--frozen-lockfile", 0], + "global": ["bun", "add", "-g", 0], + "add": ["bun", "add", 0], + "upgrade": ["bun", "update", 0], + "upgrade-interactive": ["bun", "update", "-i", 0], + "dedupe": null, + "execute": ["bun", "x", 0], + "execute-local": ["bun", "x", 0], + "uninstall": ["bun", "remove", 0], + "global_uninstall": ["bun", "remove", "-g", 0] +}; +var deno = { + "agent": ["deno", 0], + "run": ["deno", "task", 0], + "install": ["deno", "install", 0], + "frozen": ["deno", "install", "--frozen", 0], + "global": ["deno", "install", "-g", 0], + "add": ["deno", "add", 0], + "upgrade": ["deno", "outdated", "--update", 0], + "upgrade-interactive": ["deno", "outdated", "--update", 0], + "dedupe": null, + "execute": denoExecute(), + "execute-local": ["deno", "task", "--eval", 0], + "uninstall": ["deno", "remove", 0], + "global_uninstall": ["deno", "uninstall", "-g", 0] +}; +var COMMANDS = { + "npm": npm, + "yarn": yarn, + "yarn@berry": yarnBerry, + "pnpm": pnpm, + // pnpm v6.x or below + "pnpm@6": { + ...pnpm, + run: dashDashArg("pnpm", "run") + }, + "bun": bun, + "deno": deno +}; +function resolveCommand(agent2, command, args3) { + const value2 = COMMANDS[agent2][command]; + return constructCommand(value2, args3); +} +function constructCommand(value2, args3) { + if (value2 == null) + return null; + const list = typeof value2 === "function" ? value2(args3) : value2.flatMap((v) => { + if (typeof v === "number") + return args3; + return [v]; + }); + return { + command: list[0], + args: list.slice(1) + }; +} + +// node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/constants.mjs +var AGENTS = [ + "npm", + "yarn", + "yarn@berry", + "pnpm", + "pnpm@6", + "bun", + "deno" +]; +var LOCKS = { + "bun.lock": "bun", + "bun.lockb": "bun", + "deno.lock": "deno", + "pnpm-lock.yaml": "pnpm", + "pnpm-workspace.yaml": "pnpm", + "yarn.lock": "yarn", + "package-lock.json": "npm", + "npm-shrinkwrap.json": "npm" +}; +var INSTALL_METADATA = { + "node_modules/.deno/": "deno", + "node_modules/.pnpm/": "pnpm", + "node_modules/.yarn-state.yml": "yarn", + // yarn v2+ (node-modules) + "node_modules/.yarn_integrity": "yarn", + // yarn v1 + "node_modules/.package-lock.json": "npm", + ".pnp.cjs": "yarn", + // yarn v3+ (pnp) + ".pnp.js": "yarn", + // yarn v2 (pnp) + "bun.lock": "bun", + "bun.lockb": "bun" +}; + +// node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/detect.mjs +import fs3 from "node:fs/promises"; +import path3 from "node:path"; +import process3 from "node:process"; +async function pathExists(path22, type2) { + try { + const stat = await fs3.stat(path22); + return type2 === "file" ? stat.isFile() : stat.isDirectory(); + } catch { + return false; + } +} +function* lookup(cwd2 = process3.cwd()) { + let directory = path3.resolve(cwd2); + const { root: root2 } = path3.parse(directory); + while (directory && directory !== root2) { + yield directory; + directory = path3.dirname(directory); + } +} +async function parsePackageJson(filepath, options) { + if (!filepath || !await pathExists(filepath, "file")) + return null; + return await handlePackageManager(filepath, options); +} +async function detect(options = {}) { + const { + cwd: cwd2, + strategies = ["lockfile", "packageManager-field", "devEngines-field"] + } = options; + let stopDir; + if (typeof options.stopDir === "string") { + const resolved = path3.resolve(options.stopDir); + stopDir = (dir) => dir === resolved; + } else { + stopDir = options.stopDir; + } + for (const directory of lookup(cwd2)) { + for (const strategy of strategies) { + switch (strategy) { + case "lockfile": { + for (const lock of Object.keys(LOCKS)) { + if (await pathExists(path3.join(directory, lock), "file")) { + const name = LOCKS[lock]; + const result = await parsePackageJson(path3.join(directory, "package.json"), options); + if (result) + return result; + else + return { name, agent: name }; + } + } + break; + } + case "packageManager-field": + case "devEngines-field": { + const result = await parsePackageJson(path3.join(directory, "package.json"), options); + if (result) + return result; + break; + } + case "install-metadata": { + for (const metadata of Object.keys(INSTALL_METADATA)) { + const fileOrDir = metadata.endsWith("/") ? "dir" : "file"; + if (await pathExists(path3.join(directory, metadata), fileOrDir)) { + const name = INSTALL_METADATA[metadata]; + const agent2 = name === "yarn" ? isMetadataYarnClassic(metadata) ? "yarn" : "yarn@berry" : name; + return { name, agent: agent2 }; + } + } + break; + } + } + } + if (stopDir?.(directory)) + break; + } + return null; +} +function getNameAndVer(pkg) { + const handelVer = (version2) => version2?.match(/\d+(\.\d+){0,2}/)?.[0] ?? version2; + if (typeof pkg.packageManager === "string") { + const [name, ver] = pkg.packageManager.replace(/^\^/, "").split("@"); + return { name, ver: handelVer(ver) }; + } + if (typeof pkg.devEngines?.packageManager?.name === "string") { + return { + name: pkg.devEngines.packageManager.name, + ver: handelVer(pkg.devEngines.packageManager.version) + }; + } + return void 0; +} +async function handlePackageManager(filepath, options) { + try { + const content = await fs3.readFile(filepath, "utf8"); + const pkg = options.packageJsonParser ? await options.packageJsonParser(content, filepath) : JSON.parse(content); + let agent2; + const nameAndVer = getNameAndVer(pkg); + if (nameAndVer) { + const name = nameAndVer.name; + const ver = nameAndVer.ver; + let version2 = ver; + if (name === "yarn" && ver && Number.parseInt(ver) > 1) { + agent2 = "yarn@berry"; + version2 = "berry"; + return { name, agent: agent2, version: version2 }; + } else if (name === "pnpm" && ver && Number.parseInt(ver) < 7) { + agent2 = "pnpm@6"; + return { name, agent: agent2, version: version2 }; + } else if (AGENTS.includes(name)) { + agent2 = name; + return { name, agent: agent2, version: version2 }; + } else { + return options.onUnknown?.(pkg.packageManager) ?? null; + } + } + } catch { + } + return null; +} +function isMetadataYarnClassic(metadataPath) { + return metadataPath.endsWith(".yarn_integrity"); +} + +// prep/installNodeDependencies.ts +var PM_INSTALL_COMMANDS = { + pnpm: ["npm", "install", "-g", "pnpm"], + yarn: ["npm", "install", "-g", "yarn"], + bun: ["npm", "install", "-g", "bun"], + deno: ["sh", "-c", "curl -fsSL https://deno.land/install.sh | sh"] +}; +async function isCommandAvailable(command) { + const result = await spawn4({ + cmd: "which", + args: [command], + env: { PATH: process.env.PATH || "" } + }); + return result.exitCode === 0; +} +async function installPackageManager(name) { + log.info(`\u{1F4E6} installing ${name}...`); + const [cmd, ...args3] = PM_INSTALL_COMMANDS[name]; + const result = await spawn4({ + cmd, + args: args3, + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, + onStderr: (chunk) => process.stderr.write(chunk) + }); + if (result.exitCode !== 0) { + return result.stderr || `failed to install ${name}`; + } + if (name === "deno") { + const denoPath = join8(process.env.HOME || "", ".deno", "bin"); + process.env.PATH = `${denoPath}:${process.env.PATH}`; + } + log.info(`\u2705 installed ${name}`); + return null; +} +var installNodeDependencies = { + name: "installNodeDependencies", + shouldRun: () => { + const packageJsonPath = join8(process.cwd(), "package.json"); + return existsSync4(packageJsonPath); + }, + run: async () => { + const detected = await detect({ cwd: process.cwd() }); + if (!detected) { + return { + language: "node", + packageManager: "npm", + dependenciesInstalled: false, + issues: ["no package manager detected from lockfile"] + }; + } + const packageManager = detected.name; + log.info(`\u{1F4E6} detected package manager: ${packageManager} (${detected.agent})`); + if (packageManager !== "npm" && !await isCommandAvailable(packageManager)) { + log.info(`${packageManager} not found, attempting to install...`); + const installError = await installPackageManager(packageManager); + if (installError) { + return { + language: "node", + packageManager, + dependenciesInstalled: false, + issues: [installError] + }; + } + } + const resolved = resolveCommand(detected.agent, "frozen", []) || resolveCommand(detected.agent, "install", []); + if (!resolved) { + return { + language: "node", + packageManager, + dependenciesInstalled: false, + issues: [`no install command found for ${detected.agent}`] + }; + } + log.info(`running: ${resolved.command} ${resolved.args.join(" ")}`); + const result = await spawn4({ + cmd: resolved.command, + args: resolved.args, + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, + onStderr: (chunk) => process.stderr.write(chunk) + }); + if (result.exitCode !== 0) { + return { + language: "node", + packageManager, + dependenciesInstalled: false, + issues: [result.stderr || `${resolved.command} exited with code ${result.exitCode}`] + }; + } + return { + language: "node", + packageManager, + dependenciesInstalled: true, + issues: [] + }; + } +}; + +// prep/installPythonDependencies.ts +import { existsSync as existsSync5 } from "node:fs"; +import { join as join9 } from "node:path"; +var PYTHON_CONFIGS = [ + { + file: "requirements.txt", + tool: "pip", + installCmd: ["pip", "install", "-r", "requirements.txt"] + }, + { + file: "pyproject.toml", + tool: "pip", + installCmd: ["pip", "install", "."] + }, + { + file: "Pipfile", + tool: "pipenv", + installCmd: ["pipenv", "install"] + }, + { + file: "Pipfile.lock", + tool: "pipenv", + installCmd: ["pipenv", "sync"] + }, + { + file: "poetry.lock", + tool: "poetry", + installCmd: ["poetry", "install", "--no-interaction"] + }, + { + file: "setup.py", + tool: "pip", + installCmd: ["pip", "install", "-e", "."] + } +]; +var TOOL_INSTALL_COMMANDS = { + pipenv: ["pip", "install", "pipenv"], + poetry: ["pip", "install", "poetry"] +}; +async function isCommandAvailable2(command) { + const result = await spawn4({ + cmd: "which", + args: [command], + env: { PATH: process.env.PATH || "" } + }); + return result.exitCode === 0; +} +async function installTool(name) { + const installCmd = TOOL_INSTALL_COMMANDS[name]; + if (!installCmd) { + return null; + } + log.info(`\u{1F4E6} installing ${name}...`); + const [cmd, ...args3] = installCmd; + const result = await spawn4({ + cmd, + args: args3, + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, + onStderr: (chunk) => process.stderr.write(chunk) + }); + if (result.exitCode !== 0) { + return result.stderr || `failed to install ${name}`; + } + log.info(`\u2705 installed ${name}`); + return null; +} +var installPythonDependencies = { + name: "installPythonDependencies", + shouldRun: async () => { + const hasPython = await isCommandAvailable2("python3") || await isCommandAvailable2("python"); + if (!hasPython) { + return false; + } + const cwd2 = process.cwd(); + return PYTHON_CONFIGS.some((config2) => existsSync5(join9(cwd2, config2.file))); + }, + run: async () => { + const cwd2 = process.cwd(); + const config2 = PYTHON_CONFIGS.find((c) => existsSync5(join9(cwd2, c.file))); + if (!config2) { + return { + language: "python", + packageManager: "pip", + configFile: "unknown", + dependenciesInstalled: false, + issues: ["no python config file found"] + }; + } + log.info(`\u{1F40D} detected python config: ${config2.file} (using ${config2.tool})`); + const isAvailable = await isCommandAvailable2(config2.tool); + if (!isAvailable) { + log.info(`${config2.tool} not found, attempting to install...`); + const installError = await installTool(config2.tool); + if (installError) { + return { + language: "python", + packageManager: config2.tool, + configFile: config2.file, + dependenciesInstalled: false, + issues: [installError] + }; + } + } + const [cmd, ...args3] = config2.installCmd; + log.info(`running: ${cmd} ${args3.join(" ")}`); + const result = await spawn4({ + cmd, + args: args3, + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, + onStderr: (chunk) => process.stderr.write(chunk) + }); + if (result.exitCode !== 0) { + return { + language: "python", + packageManager: config2.tool, + configFile: config2.file, + dependenciesInstalled: false, + issues: [result.stderr || `${cmd} exited with code ${result.exitCode}`] + }; + } + return { + language: "python", + packageManager: config2.tool, + configFile: config2.file, + dependenciesInstalled: true, + issues: [] + }; + } +}; + +// prep/index.ts +var prepSteps = [installNodeDependencies, installPythonDependencies]; +async function runPrepPhase() { + log.info("\u{1F527} starting prep phase..."); + const startTime = Date.now(); + const results = []; + for (const step of prepSteps) { + const shouldRun = await step.shouldRun(); + if (!shouldRun) { + log.info(`\u23ED\uFE0F skipping ${step.name} (not applicable)`); + continue; + } + log.info(`\u25B6\uFE0F running ${step.name}...`); + const result = await step.run(); + results.push(result); + if (result.dependenciesInstalled) { + log.info(`\u2705 ${step.name}: dependencies installed`); + } else if (result.issues.length > 0) { + log.warning(`\u26A0\uFE0F ${step.name}: ${result.issues[0]}`); + } + } + const totalDurationMs = Date.now() - startTime; + log.info(`\u{1F527} prep phase completed (${totalDurationMs}ms)`); + return results; +} + // utils/errorReport.ts function getProgressCommentIdFromEnv2() { const envCommentId = process.env.PULLFROG_PROGRESS_COMMENT_ID; @@ -123942,6 +124557,17 @@ async function main(inputs) { timer.checkpoint("setupGit"); await setupTempDirectory(ctx); timer.checkpoint("setupTempDirectory"); + const [, prepResults] = await Promise.all([installAgentCli(ctx), runPrepPhase()]); + ctx.prepResults = prepResults; + const dependenciesPreinstalled = prepResults.every((r) => r.dependenciesInstalled) || void 0; + ctx.modes = [ + ...getModes({ + disableProgressComment: ctx.payload.disableProgressComment, + dependenciesPreinstalled + }), + ...ctx.payload.modes || [] + ]; + timer.checkpoint("installAgentCli+prepPhase"); await startMcpServer(ctx); mcpServerClose = ctx.mcpServerClose; timer.checkpoint("startMcpServer"); @@ -123954,8 +124580,6 @@ To use "Fix \u{1F44D}s", add a \u{1F44D} reaction to one or more inline review c return { success: true }; } setupMcpServers(ctx); - await installAgentCli(ctx); - timer.checkpoint("installAgentCli"); await validateApiKey(ctx); const result = await runAgent(ctx); const mainResult = await handleAgentResult(result); @@ -124052,7 +124676,10 @@ async function initializeContext(inputs, payload) { }); const resolvedPayload = { ...payload, agent: agentName }; const computedModes = [ - ...getModes({ disableProgressComment: resolvedPayload.disableProgressComment }), + ...getModes({ + disableProgressComment: resolvedPayload.disableProgressComment, + dependenciesPreinstalled: void 0 + }), ...resolvedPayload.modes || [] ]; return { @@ -124110,7 +124737,7 @@ function resolveAgent({ return { agentName, agent: agent2 }; } async function setupTempDirectory(ctx) { - ctx.sharedTempDir = await mkdtemp2(join8(tmpdir2(), "pullfrog-")); + ctx.sharedTempDir = await mkdtemp2(join10(tmpdir2(), "pullfrog-")); process.env.PULLFROG_TEMP_DIR = ctx.sharedTempDir; log.info(`\u{1F4C2} PULLFROG_TEMP_DIR has been created at ${ctx.sharedTempDir}`); } @@ -124193,7 +124820,8 @@ ${encode(eventWithoutContext)}`; mcpServers: ctx.mcpServers, apiKey: ctx.apiKey, apiKeys: ctx.apiKeys, - cliPath: ctx.cliPath + cliPath: ctx.cliPath, + prepResults: ctx.prepResults }); } async function handleAgentResult(result) { diff --git a/main.ts b/main.ts index 92ede1c..48f1964 100644 --- a/main.ts +++ b/main.ts @@ -14,6 +14,7 @@ import { createMcpConfigs } from "./mcp/config.ts"; import { startMcpHttpServer } from "./mcp/server.ts"; import { getModes, type Mode, modes } from "./modes.ts"; import packageJson from "./package.json" with { type: "json" }; +import { type PrepResult, runPrepPhase } from "./prep/index.ts"; import { fetchRepoSettings, fetchWorkflowRunInfo, type RepoSettings } from "./utils/api.ts"; import { log } from "./utils/cli.ts"; import { reportErrorToComment } from "./utils/errorReport.ts"; @@ -71,6 +72,21 @@ export async function main(inputs: Inputs): Promise { await setupTempDirectory(ctx); timer.checkpoint("setupTempDirectory"); + // run agent CLI installation and prep phase in parallel + const [, prepResults] = await Promise.all([installAgentCli(ctx), runPrepPhase()]); + ctx.prepResults = prepResults; + + // recompute modes now that we know if dependencies were preinstalled + const dependenciesPreinstalled = prepResults.every((r) => r.dependenciesInstalled) || undefined; + ctx.modes = [ + ...getModes({ + disableProgressComment: ctx.payload.disableProgressComment, + dependenciesPreinstalled, + }), + ...(ctx.payload.modes || []), + ]; + timer.checkpoint("installAgentCli+prepPhase"); + await startMcpServer(ctx); mcpServerClose = ctx.mcpServerClose; timer.checkpoint("startMcpServer"); @@ -89,9 +105,6 @@ export async function main(inputs: Inputs): Promise { setupMcpServers(ctx); - await installAgentCli(ctx); - timer.checkpoint("installAgentCli"); - await validateApiKey(ctx); const result = await runAgent(ctx); @@ -223,6 +236,9 @@ export interface Context { cliPath: string; apiKey: string; apiKeys: Record; + + // prep phase results + prepResults: PrepResult[]; } async function initializeContext( @@ -238,6 +254,7 @@ async function initializeContext( | "apiKey" | "apiKeys" | "pushRemote" + | "prepResults" > > { log.info(`🐸 Running pullfrog/action@${packageJson.version}...`); @@ -274,8 +291,12 @@ async function initializeContext( const resolvedPayload = { ...payload, agent: agentName }; // compute modes from defaults + payload overrides + // note: dependenciesPreinstalled is undefined here since prepPhase runs after this const computedModes = [ - ...getModes({ disableProgressComment: resolvedPayload.disableProgressComment }), + ...getModes({ + disableProgressComment: resolvedPayload.disableProgressComment, + dependenciesPreinstalled: undefined, + }), ...(resolvedPayload.modes || []), ]; @@ -462,6 +483,7 @@ async function runAgent(ctx: Context): Promise { apiKey: ctx.apiKey, apiKeys: ctx.apiKeys, cliPath: ctx.cliPath, + prepResults: ctx.prepResults, }); } diff --git a/modes.ts b/modes.ts index 9fb8ffc..cd2152c 100644 --- a/modes.ts +++ b/modes.ts @@ -8,18 +8,26 @@ export interface Mode { export interface GetModesParams { disableProgressComment: true | undefined; + dependenciesPreinstalled: true | undefined; } const reportProgressInstruction = `Use ${ghPullfrogMcpName}/report_progress to share progress and results. Continue calling it as you make progress - it will update the same comment. Never create additional comments manually.`; -export function getModes({ disableProgressComment }: GetModesParams): Mode[] { +export function getModes({ + disableProgressComment, + dependenciesPreinstalled, +}: GetModesParams): Mode[] { + const depsContext = dependenciesPreinstalled + ? "Dependencies have already been installed." + : "understand how to install dependencies,"; + return [ { 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. 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. +1. If the request requires understanding the codebase structure, dependencies, or conventions, gather relevant context. Read AGENTS.md if it exists, ${depsContext} run tests, run builds, and make changes according to best practices). Skip this step if the prompt is trivial and self-contained. 2. Create a branch using ${ghPullfrogMcpName}/create_branch. The branch name should be prefixed with "pullfrog/". The rest of the name should reflect the exact changes you are making. It should be specific to avoid collisions with other branches. Never commit directly to main, master, or production. Do NOT use git commands directly - always use ${ghPullfrogMcpName} MCP tools for git operations. @@ -116,7 +124,7 @@ ${ description: "Create plans, break down tasks, outline steps, analyze requirements, understand scope of work, or provide task breakdowns", prompt: `Follow these steps: -1. 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. +1. If the request requires understanding the codebase structure, dependencies, or conventions, gather relevant context (read AGENTS.md if it exists, ${depsContext} run tests, run builds, and make changes according to best practices). Skip this step if the prompt is trivial and self-contained. 2. Analyze the request and break it down into clear, actionable tasks @@ -145,4 +153,7 @@ ${ ]; } -export const modes: Mode[] = getModes({ disableProgressComment: undefined }); +export const modes: Mode[] = getModes({ + disableProgressComment: undefined, + dependenciesPreinstalled: undefined, +}); diff --git a/package.json b/package.json index 36635a5..7bb4254 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@opencode-ai/sdk": "^1.0.143", "@standard-schema/spec": "1.0.0", "arktype": "2.1.28", + "package-manager-detector": "^1.6.0", "dotenv": "^17.2.3", "execa": "^9.6.0", "fastmcp": "^3.20.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37785e8..a9c5d9b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: fastmcp: specifier: ^3.20.0 version: 3.20.0(arktype@2.1.28) + package-manager-detector: + specifier: ^1.6.0 + version: 1.6.0 table: specifier: ^6.9.0 version: 6.9.0 @@ -836,6 +839,9 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} @@ -1843,6 +1849,8 @@ snapshots: dependencies: wrappy: 1.0.2 + package-manager-detector@1.6.0: {} + parse-ms@4.0.0: {} parseurl@1.3.3: {} diff --git a/prep/index.ts b/prep/index.ts new file mode 100644 index 0000000..c014d78 --- /dev/null +++ b/prep/index.ts @@ -0,0 +1,42 @@ +import { log } from "../utils/cli.ts"; +import { installNodeDependencies } from "./installNodeDependencies.ts"; +import { installPythonDependencies } from "./installPythonDependencies.ts"; +import type { PrepDefinition, PrepResult } from "./types.ts"; + +export type { PrepResult } from "./types.ts"; + +// register all prep steps here +const prepSteps: PrepDefinition[] = [installNodeDependencies, installPythonDependencies]; + +/** + * run all prep steps sequentially. + * failures are logged as warnings but don't stop the run. + */ +export async function runPrepPhase(): Promise { + log.info("🔧 starting prep phase..."); + const startTime = Date.now(); + const results: PrepResult[] = []; + + for (const step of prepSteps) { + const shouldRun = await step.shouldRun(); + if (!shouldRun) { + log.info(`⏭️ skipping ${step.name} (not applicable)`); + continue; + } + + log.info(`▶️ running ${step.name}...`); + const result = await step.run(); + results.push(result); + + if (result.dependenciesInstalled) { + log.info(`✅ ${step.name}: dependencies installed`); + } else if (result.issues.length > 0) { + log.warning(`⚠️ ${step.name}: ${result.issues[0]}`); + } + } + + const totalDurationMs = Date.now() - startTime; + log.info(`🔧 prep phase completed (${totalDurationMs}ms)`); + + return results; +} diff --git a/prep/installNodeDependencies.ts b/prep/installNodeDependencies.ts new file mode 100644 index 0000000..6682c01 --- /dev/null +++ b/prep/installNodeDependencies.ts @@ -0,0 +1,126 @@ +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { detect } from "package-manager-detector"; +import { resolveCommand } from "package-manager-detector/commands"; +import { log } from "../utils/cli.ts"; +import { spawn } from "../utils/subprocess.ts"; +import type { NodePackageManager, NodePrepResult, PrepDefinition } from "./types.ts"; + +// package managers that need installation (npm is always available) +type InstallablePackageManager = Exclude; + +// install commands for each package manager +const PM_INSTALL_COMMANDS: Record = { + pnpm: ["npm", "install", "-g", "pnpm"], + yarn: ["npm", "install", "-g", "yarn"], + bun: ["npm", "install", "-g", "bun"], + deno: ["sh", "-c", "curl -fsSL https://deno.land/install.sh | sh"], +}; + +async function isCommandAvailable(command: string): Promise { + const result = await spawn({ + cmd: "which", + args: [command], + env: { PATH: process.env.PATH || "" }, + }); + return result.exitCode === 0; +} + +async function installPackageManager(name: InstallablePackageManager): Promise { + log.info(`📦 installing ${name}...`); + const [cmd, ...args] = PM_INSTALL_COMMANDS[name]; + const result = await spawn({ + cmd, + args, + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, + onStderr: (chunk) => process.stderr.write(chunk), + }); + + if (result.exitCode !== 0) { + return result.stderr || `failed to install ${name}`; + } + + // deno installs to $HOME/.deno/bin - add to PATH for subsequent commands + if (name === "deno") { + const denoPath = join(process.env.HOME || "", ".deno", "bin"); + process.env.PATH = `${denoPath}:${process.env.PATH}`; + } + + log.info(`✅ installed ${name}`); + return null; +} + +export const installNodeDependencies: PrepDefinition = { + name: "installNodeDependencies", + + shouldRun: () => { + const packageJsonPath = join(process.cwd(), "package.json"); + return existsSync(packageJsonPath); + }, + + run: async (): Promise => { + // detect package manager + const detected = await detect({ cwd: process.cwd() }); + if (!detected) { + return { + language: "node", + packageManager: "npm", + dependenciesInstalled: false, + issues: ["no package manager detected from lockfile"], + }; + } + + const packageManager = detected.name as NodePackageManager; + log.info(`📦 detected package manager: ${packageManager} (${detected.agent})`); + + // check if package manager is available, install if needed (npm is always available) + if (packageManager !== "npm" && !(await isCommandAvailable(packageManager))) { + log.info(`${packageManager} not found, attempting to install...`); + const installError = await installPackageManager(packageManager); + if (installError) { + return { + language: "node", + packageManager, + dependenciesInstalled: false, + issues: [installError], + }; + } + } + + // get the frozen install command (or fallback to regular install) + const resolved = + resolveCommand(detected.agent, "frozen", []) || resolveCommand(detected.agent, "install", []); + if (!resolved) { + return { + language: "node", + packageManager, + dependenciesInstalled: false, + issues: [`no install command found for ${detected.agent}`], + }; + } + + log.info(`running: ${resolved.command} ${resolved.args.join(" ")}`); + const result = await spawn({ + cmd: resolved.command, + args: resolved.args, + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, + onStderr: (chunk) => process.stderr.write(chunk), + }); + + if (result.exitCode !== 0) { + return { + language: "node", + packageManager, + dependenciesInstalled: false, + issues: [result.stderr || `${resolved.command} exited with code ${result.exitCode}`], + }; + } + + return { + language: "node", + packageManager, + dependenciesInstalled: true, + issues: [], + }; + }, +}; diff --git a/prep/installPythonDependencies.ts b/prep/installPythonDependencies.ts new file mode 100644 index 0000000..65d12eb --- /dev/null +++ b/prep/installPythonDependencies.ts @@ -0,0 +1,162 @@ +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { log } from "../utils/cli.ts"; +import { spawn } from "../utils/subprocess.ts"; +import type { PrepDefinition, PythonPackageManager, PythonPrepResult } from "./types.ts"; + +interface PythonConfig { + file: string; + tool: PythonPackageManager; + installCmd: string[]; +} + +// python dependency file patterns in priority order +const PYTHON_CONFIGS: PythonConfig[] = [ + { + file: "requirements.txt", + tool: "pip", + installCmd: ["pip", "install", "-r", "requirements.txt"], + }, + { + file: "pyproject.toml", + tool: "pip", + installCmd: ["pip", "install", "."], + }, + { + file: "Pipfile", + tool: "pipenv", + installCmd: ["pipenv", "install"], + }, + { + file: "Pipfile.lock", + tool: "pipenv", + installCmd: ["pipenv", "sync"], + }, + { + file: "poetry.lock", + tool: "poetry", + installCmd: ["poetry", "install", "--no-interaction"], + }, + { + file: "setup.py", + tool: "pip", + installCmd: ["pip", "install", "-e", "."], + }, +]; + +// tool install commands (via pip) +const TOOL_INSTALL_COMMANDS: Record = { + pipenv: ["pip", "install", "pipenv"], + poetry: ["pip", "install", "poetry"], +}; + +async function isCommandAvailable(command: string): Promise { + const result = await spawn({ + cmd: "which", + args: [command], + env: { PATH: process.env.PATH || "" }, + }); + return result.exitCode === 0; +} + +async function installTool(name: string): Promise { + const installCmd = TOOL_INSTALL_COMMANDS[name]; + if (!installCmd) { + // tool doesn't need installation (e.g., pip) + return null; + } + + log.info(`📦 installing ${name}...`); + const [cmd, ...args] = installCmd; + const result = await spawn({ + cmd, + args, + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, + onStderr: (chunk) => process.stderr.write(chunk), + }); + + if (result.exitCode !== 0) { + return result.stderr || `failed to install ${name}`; + } + + log.info(`✅ installed ${name}`); + return null; +} + +export const installPythonDependencies: PrepDefinition = { + name: "installPythonDependencies", + + shouldRun: async () => { + // check if python is available + const hasPython = (await isCommandAvailable("python3")) || (await isCommandAvailable("python")); + if (!hasPython) { + return false; + } + + // check if any python config file exists + const cwd = process.cwd(); + return PYTHON_CONFIGS.some((config) => existsSync(join(cwd, config.file))); + }, + + run: async (): Promise => { + const cwd = process.cwd(); + + // find the first matching config + const config = PYTHON_CONFIGS.find((c) => existsSync(join(cwd, c.file))); + if (!config) { + return { + language: "python", + packageManager: "pip", + configFile: "unknown", + dependenciesInstalled: false, + issues: ["no python config file found"], + }; + } + + log.info(`🐍 detected python config: ${config.file} (using ${config.tool})`); + + // check if the tool is available, install if needed + const isAvailable = await isCommandAvailable(config.tool); + if (!isAvailable) { + log.info(`${config.tool} not found, attempting to install...`); + const installError = await installTool(config.tool); + if (installError) { + return { + language: "python", + packageManager: config.tool, + configFile: config.file, + dependenciesInstalled: false, + issues: [installError], + }; + } + } + + // run the install command + const [cmd, ...args] = config.installCmd; + log.info(`running: ${cmd} ${args.join(" ")}`); + const result = await spawn({ + cmd, + args, + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, + onStderr: (chunk) => process.stderr.write(chunk), + }); + + if (result.exitCode !== 0) { + return { + language: "python", + packageManager: config.tool, + configFile: config.file, + dependenciesInstalled: false, + issues: [result.stderr || `${cmd} exited with code ${result.exitCode}`], + }; + } + + return { + language: "python", + packageManager: config.tool, + configFile: config.file, + dependenciesInstalled: true, + issues: [], + }; + }, +}; diff --git a/prep/types.ts b/prep/types.ts new file mode 100644 index 0000000..a955e7b --- /dev/null +++ b/prep/types.ts @@ -0,0 +1,31 @@ +interface PrepResultBase { + dependenciesInstalled: boolean; + issues: string[]; +} + +export type NodePackageManager = "npm" | "pnpm" | "yarn" | "bun" | "deno"; + +export interface NodePrepResult extends PrepResultBase { + language: "node"; + packageManager: NodePackageManager; +} + +export type PythonPackageManager = "pip" | "pipenv" | "poetry"; + +export interface PythonPrepResult extends PrepResultBase { + language: "python"; + packageManager: PythonPackageManager; + configFile: string; +} + +export interface UnknownLanguagePrepResult extends PrepResultBase { + language: "unknown"; +} + +export type PrepResult = NodePrepResult | PythonPrepResult | UnknownLanguagePrepResult; + +export interface PrepDefinition { + name: string; + shouldRun: () => Promise | boolean; + run: () => Promise; +}