pullfrog 0.1.57 → 0.1.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/codex.d.ts +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/opencodeShared.d.ts +24 -0
- package/dist/cli.mjs +1059 -388
- package/dist/external.d.ts +2 -1
- package/dist/index.js +1094 -419
- package/dist/internal.js +18 -0
- package/dist/models.d.ts +42 -1
- package/dist/utils/agent.d.ts +10 -0
- package/dist/utils/codexHome.d.ts +27 -0
- package/dist/utils/roleMirror.d.ts +14 -0
- package/dist/utils/runContext.d.ts +1 -0
- package/package.json +3 -1
package/dist/cli.mjs
CHANGED
|
@@ -3955,7 +3955,7 @@ var require_util2 = __commonJS({
|
|
|
3955
3955
|
"use strict";
|
|
3956
3956
|
var { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = require_constants2();
|
|
3957
3957
|
var { getGlobalOrigin } = require_global();
|
|
3958
|
-
var { performance:
|
|
3958
|
+
var { performance: performance10 } = __require("perf_hooks");
|
|
3959
3959
|
var { isBlobLike, toUSVString, ReadableStreamFrom } = require_util();
|
|
3960
3960
|
var assert3 = __require("assert");
|
|
3961
3961
|
var { isUint8Array } = __require("util/types");
|
|
@@ -4118,7 +4118,7 @@ var require_util2 = __commonJS({
|
|
|
4118
4118
|
}
|
|
4119
4119
|
}
|
|
4120
4120
|
function coarsenedSharedCurrentTime(crossOriginIsolatedCapability) {
|
|
4121
|
-
return
|
|
4121
|
+
return performance10.now();
|
|
4122
4122
|
}
|
|
4123
4123
|
function createOpaqueTimingInfo(timingInfo) {
|
|
4124
4124
|
return {
|
|
@@ -20099,14 +20099,14 @@ Support boolean input list: \`true | True | TRUE | false | False | FALSE\``);
|
|
|
20099
20099
|
});
|
|
20100
20100
|
}
|
|
20101
20101
|
exports.group = group2;
|
|
20102
|
-
function
|
|
20102
|
+
function saveState4(name, value2) {
|
|
20103
20103
|
const filePath = process.env["GITHUB_STATE"] || "";
|
|
20104
20104
|
if (filePath) {
|
|
20105
20105
|
return (0, file_command_1.issueFileCommand)("STATE", (0, file_command_1.prepareKeyValueMessage)(name, value2));
|
|
20106
20106
|
}
|
|
20107
20107
|
(0, command_1.issueCommand)("save-state", { name }, (0, utils_1.toCommandValue)(value2));
|
|
20108
20108
|
}
|
|
20109
|
-
exports.saveState =
|
|
20109
|
+
exports.saveState = saveState4;
|
|
20110
20110
|
function getState2(name) {
|
|
20111
20111
|
return process.env[`STATE_${name}`] || "";
|
|
20112
20112
|
}
|
|
@@ -27894,11 +27894,11 @@ var require_mode = __commonJS({
|
|
|
27894
27894
|
var require_isexe = __commonJS({
|
|
27895
27895
|
"node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports, module) {
|
|
27896
27896
|
var fs5 = __require("fs");
|
|
27897
|
-
var
|
|
27897
|
+
var core12;
|
|
27898
27898
|
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
27899
|
-
|
|
27899
|
+
core12 = require_windows();
|
|
27900
27900
|
} else {
|
|
27901
|
-
|
|
27901
|
+
core12 = require_mode();
|
|
27902
27902
|
}
|
|
27903
27903
|
module.exports = isexe;
|
|
27904
27904
|
isexe.sync = sync;
|
|
@@ -27921,7 +27921,7 @@ var require_isexe = __commonJS({
|
|
|
27921
27921
|
});
|
|
27922
27922
|
});
|
|
27923
27923
|
}
|
|
27924
|
-
|
|
27924
|
+
core12(path4, options || {}, function(er, is) {
|
|
27925
27925
|
if (er) {
|
|
27926
27926
|
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
27927
27927
|
er = null;
|
|
@@ -27933,7 +27933,7 @@ var require_isexe = __commonJS({
|
|
|
27933
27933
|
}
|
|
27934
27934
|
function sync(path4, options) {
|
|
27935
27935
|
try {
|
|
27936
|
-
return
|
|
27936
|
+
return core12.sync(path4, options || {});
|
|
27937
27937
|
} catch (er) {
|
|
27938
27938
|
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
27939
27939
|
return false;
|
|
@@ -33299,7 +33299,7 @@ var require_util9 = __commonJS({
|
|
|
33299
33299
|
var { redirectStatusSet, referrerPolicyTokens, badPortsSet } = require_constants9();
|
|
33300
33300
|
var { getGlobalOrigin } = require_global3();
|
|
33301
33301
|
var { collectAnHTTPQuotedString, parseMIMEType } = require_data_url();
|
|
33302
|
-
var { performance:
|
|
33302
|
+
var { performance: performance10 } = __require("node:perf_hooks");
|
|
33303
33303
|
var { ReadableStreamFrom, isValidHTTPToken, normalizedMethodRecordsBase } = require_util8();
|
|
33304
33304
|
var assert3 = __require("node:assert");
|
|
33305
33305
|
var { isUint8Array } = __require("node:util/types");
|
|
@@ -33454,7 +33454,7 @@ var require_util9 = __commonJS({
|
|
|
33454
33454
|
};
|
|
33455
33455
|
}
|
|
33456
33456
|
function coarsenedSharedCurrentTime(crossOriginIsolatedCapability) {
|
|
33457
|
-
return coarsenTime(
|
|
33457
|
+
return coarsenTime(performance10.now(), crossOriginIsolatedCapability);
|
|
33458
33458
|
}
|
|
33459
33459
|
function createOpaqueTimingInfo(timingInfo) {
|
|
33460
33460
|
return {
|
|
@@ -76726,7 +76726,7 @@ var require_core3 = __commonJS({
|
|
|
76726
76726
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
76727
76727
|
var id_1 = require_id();
|
|
76728
76728
|
var ref_1 = require_ref();
|
|
76729
|
-
var
|
|
76729
|
+
var core12 = [
|
|
76730
76730
|
"$schema",
|
|
76731
76731
|
"$id",
|
|
76732
76732
|
"$defs",
|
|
@@ -76736,7 +76736,7 @@ var require_core3 = __commonJS({
|
|
|
76736
76736
|
id_1.default,
|
|
76737
76737
|
ref_1.default
|
|
76738
76738
|
];
|
|
76739
|
-
exports.default =
|
|
76739
|
+
exports.default = core12;
|
|
76740
76740
|
}
|
|
76741
76741
|
});
|
|
76742
76742
|
|
|
@@ -98607,14 +98607,14 @@ var require_turndown_cjs = __commonJS({
|
|
|
98607
98607
|
} else if (node2.nodeType === 1) {
|
|
98608
98608
|
replacement = replacementForNode.call(self2, node2);
|
|
98609
98609
|
}
|
|
98610
|
-
return
|
|
98610
|
+
return join29(output, replacement);
|
|
98611
98611
|
}, "");
|
|
98612
98612
|
}
|
|
98613
98613
|
function postProcess(output) {
|
|
98614
98614
|
var self2 = this;
|
|
98615
98615
|
this.rules.forEach(function(rule) {
|
|
98616
98616
|
if (typeof rule.append === "function") {
|
|
98617
|
-
output =
|
|
98617
|
+
output = join29(output, rule.append(self2.options));
|
|
98618
98618
|
}
|
|
98619
98619
|
});
|
|
98620
98620
|
return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
|
|
@@ -98626,7 +98626,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
98626
98626
|
if (whitespace.leading || whitespace.trailing) content = content.trim();
|
|
98627
98627
|
return whitespace.leading + rule.replacement(content, node2, this.options) + whitespace.trailing;
|
|
98628
98628
|
}
|
|
98629
|
-
function
|
|
98629
|
+
function join29(output, replacement) {
|
|
98630
98630
|
var s1 = trimTrailingNewlines(output);
|
|
98631
98631
|
var s2 = trimLeadingNewlines(replacement);
|
|
98632
98632
|
var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
|
|
@@ -105306,14 +105306,14 @@ async function runClaudeAuth() {
|
|
|
105306
105306
|
}
|
|
105307
105307
|
|
|
105308
105308
|
// commands/gha.ts
|
|
105309
|
-
var
|
|
105309
|
+
var core11 = __toESM(require_core(), 1);
|
|
105310
105310
|
var import_arg2 = __toESM(require_arg(), 1);
|
|
105311
105311
|
import { dirname as dirname6 } from "node:path";
|
|
105312
105312
|
|
|
105313
105313
|
// main.ts
|
|
105314
|
-
import { existsSync as
|
|
105314
|
+
import { existsSync as existsSync9, readdirSync as readdirSync2 } from "node:fs";
|
|
105315
105315
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
105316
|
-
import { join as
|
|
105316
|
+
import { join as join28 } from "node:path";
|
|
105317
105317
|
|
|
105318
105318
|
// node_modules/.pnpm/package-manager-detector@1.8.0/node_modules/package-manager-detector/dist/commands.mjs
|
|
105319
105319
|
function splitRunArgs(args2, valueFlags = []) {
|
|
@@ -106186,6 +106186,22 @@ var providers = {
|
|
|
106186
106186
|
}
|
|
106187
106187
|
}
|
|
106188
106188
|
}),
|
|
106189
|
+
azure: provider({
|
|
106190
|
+
displayName: "Azure OpenAI",
|
|
106191
|
+
// the resource name is half the endpoint URL and the deployment is the model
|
|
106192
|
+
// id, so both are as load-bearing as the key. only the key is sensitive.
|
|
106193
|
+
envVars: ["AZURE_API_KEY", "AZURE_RESOURCE_NAME", "AZURE_DEPLOYMENT"],
|
|
106194
|
+
models: {
|
|
106195
|
+
// single routing entry — the real model is the customer's deployment name,
|
|
106196
|
+
// read from AZURE_DEPLOYMENT at run time. see ModelRouting docs for why
|
|
106197
|
+
// Azure can't be cataloged even though models.dev lists it.
|
|
106198
|
+
byok: {
|
|
106199
|
+
displayName: "Azure OpenAI",
|
|
106200
|
+
resolve: "azure",
|
|
106201
|
+
routing: "azure"
|
|
106202
|
+
}
|
|
106203
|
+
}
|
|
106204
|
+
}),
|
|
106189
106205
|
"openai-compatible": provider({
|
|
106190
106206
|
// "Custom" is the picker group, "OpenAI-compatible" the entry under it, so the
|
|
106191
106207
|
// menu reads `Custom › OpenAI-compatible` and a second custom backend (a
|
|
@@ -106411,6 +106427,11 @@ function getModelEnvVars(slug2) {
|
|
|
106411
106427
|
}
|
|
106412
106428
|
return providerConfig.envVars.slice();
|
|
106413
106429
|
}
|
|
106430
|
+
function getModelManagedCredentials(slug2) {
|
|
106431
|
+
const parsed2 = parseModel(slug2);
|
|
106432
|
+
const providerConfig = providers[parsed2.provider];
|
|
106433
|
+
return providerConfig?.managedCredentials?.slice() ?? [];
|
|
106434
|
+
}
|
|
106414
106435
|
var modelAliases = Object.entries(providers).flatMap(
|
|
106415
106436
|
([providerKey, config3]) => Object.entries(config3.models).map(([modelId, def]) => ({
|
|
106416
106437
|
slug: `${providerKey}/${modelId}`,
|
|
@@ -106508,6 +106529,13 @@ function isOssAllowedModel(slug2) {
|
|
|
106508
106529
|
}
|
|
106509
106530
|
var BEDROCK_MODEL_ID_ENV = "BEDROCK_MODEL_ID";
|
|
106510
106531
|
var VERTEX_MODEL_ID_ENV = "VERTEX_MODEL_ID";
|
|
106532
|
+
var AZURE_PROVIDER = "azure";
|
|
106533
|
+
var AZURE_RESOURCE_NAME_ENV = "AZURE_RESOURCE_NAME";
|
|
106534
|
+
var AZURE_API_KEY_ENV = "AZURE_API_KEY";
|
|
106535
|
+
var AZURE_DEPLOYMENT_ENV = "AZURE_DEPLOYMENT";
|
|
106536
|
+
var AZURE_CONTEXT_ENV = "AZURE_CONTEXT";
|
|
106537
|
+
var AZURE_MAX_OUTPUT_ENV = "AZURE_MAX_OUTPUT";
|
|
106538
|
+
var AZURE_USE_CHAT_COMPLETIONS_ENV = "AZURE_USE_CHAT_COMPLETIONS";
|
|
106511
106539
|
var OPENAI_COMPATIBLE_PROVIDER = "openai-compatible";
|
|
106512
106540
|
var OPENAI_COMPATIBLE_BASE_URL_ENV = "OPENAI_COMPATIBLE_BASE_URL";
|
|
106513
106541
|
var OPENAI_COMPATIBLE_API_KEY_ENV = "OPENAI_COMPATIBLE_API_KEY";
|
|
@@ -106527,6 +106555,8 @@ function formatMcpToolRef(agentId, toolName) {
|
|
|
106527
106555
|
switch (agentId) {
|
|
106528
106556
|
case "claude":
|
|
106529
106557
|
return `mcp__${pullfrogMcpName}__${toolName}`;
|
|
106558
|
+
case "codex":
|
|
106559
|
+
return `${pullfrogMcpName}__${toolName}`;
|
|
106530
106560
|
case "opencode":
|
|
106531
106561
|
return `${pullfrogMcpName}_${toolName}`;
|
|
106532
106562
|
default:
|
|
@@ -107028,7 +107058,8 @@ import { pipeline } from "node:stream/promises";
|
|
|
107028
107058
|
async function installFromNpmTarball(params) {
|
|
107029
107059
|
const tempDir = process.env.PULLFROG_TEMP_DIR;
|
|
107030
107060
|
if (!tempDir) throw new Error("PULLFROG_TEMP_DIR is not set");
|
|
107031
|
-
const
|
|
107061
|
+
const packageRoot = join2(tempDir, `npm-${params.packageName.replace(/[^a-z0-9]+/gi, "-")}`);
|
|
107062
|
+
const extractedDir = join2(packageRoot, "package");
|
|
107032
107063
|
const cliPath = join2(extractedDir, params.executablePath);
|
|
107033
107064
|
if (existsSync2(cliPath)) {
|
|
107034
107065
|
log2.debug(`\xBB using cached binary at ${cliPath}`);
|
|
@@ -107054,7 +107085,8 @@ async function installFromNpmTarball(params) {
|
|
|
107054
107085
|
}
|
|
107055
107086
|
}
|
|
107056
107087
|
log2.debug(`\xBB installing ${params.packageName}@${resolvedVersion}...`);
|
|
107057
|
-
|
|
107088
|
+
mkdirSync(packageRoot, { recursive: true });
|
|
107089
|
+
const tarballPath = join2(packageRoot, "package.tgz");
|
|
107058
107090
|
const npmRegistry = process.env.NPM_REGISTRY || "https://registry.npmjs.org";
|
|
107059
107091
|
let tarballUrl;
|
|
107060
107092
|
if (params.packageName.startsWith("@")) {
|
|
@@ -107074,7 +107106,7 @@ async function installFromNpmTarball(params) {
|
|
|
107074
107106
|
await pipeline(response.body, fileStream);
|
|
107075
107107
|
log2.debug(`\xBB downloaded tarball to ${tarballPath}`);
|
|
107076
107108
|
log2.debug(`\xBB extracting tarball...`);
|
|
107077
|
-
const extractResult = spawnSync("tar", ["-xzf", tarballPath, "-C",
|
|
107109
|
+
const extractResult = spawnSync("tar", ["-xzf", tarballPath, "-C", packageRoot], {
|
|
107078
107110
|
stdio: "pipe",
|
|
107079
107111
|
encoding: "utf-8"
|
|
107080
107112
|
});
|
|
@@ -107083,9 +107115,6 @@ async function installFromNpmTarball(params) {
|
|
|
107083
107115
|
`Failed to extract tarball: ${extractResult.stderr || extractResult.stdout || "Unknown error"}`
|
|
107084
107116
|
);
|
|
107085
107117
|
}
|
|
107086
|
-
if (!existsSync2(cliPath)) {
|
|
107087
|
-
throw new Error(`Executable not found in extracted package at ${cliPath}`);
|
|
107088
|
-
}
|
|
107089
107118
|
if (params.installDependencies) {
|
|
107090
107119
|
log2.debug(`\xBB installing dependencies for ${params.packageName}...`);
|
|
107091
107120
|
const installResult = spawnSync("npm", ["install", "--production"], {
|
|
@@ -107106,6 +107135,9 @@ async function installFromNpmTarball(params) {
|
|
|
107106
107135
|
}
|
|
107107
107136
|
log2.debug(`\xBB dependencies installed`);
|
|
107108
107137
|
}
|
|
107138
|
+
if (!existsSync2(cliPath)) {
|
|
107139
|
+
throw new Error(`Executable not found in extracted package at ${cliPath}`);
|
|
107140
|
+
}
|
|
107109
107141
|
chmodSync(cliPath, 493);
|
|
107110
107142
|
log2.debug(`\xBB ${params.packageName} installed at ${cliPath}`);
|
|
107111
107143
|
return cliPath;
|
|
@@ -107279,6 +107311,7 @@ function resolveRunAlias(ctx) {
|
|
|
107279
107311
|
}
|
|
107280
107312
|
const model = ctx.resolvedModel;
|
|
107281
107313
|
if (!model) return void 0;
|
|
107314
|
+
if (model.startsWith(`${AZURE_PROVIDER}/`)) return void 0;
|
|
107282
107315
|
return modelAliases.find((a2) => !a2.fallback && a2.resolve === model) ?? matchHostedAnthropicAlias(model);
|
|
107283
107316
|
}
|
|
107284
107317
|
function ossEffortFloor(ctx) {
|
|
@@ -107317,7 +107350,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
107317
107350
|
// package.json
|
|
107318
107351
|
var package_default = {
|
|
107319
107352
|
name: "pullfrog",
|
|
107320
|
-
version: "0.1.
|
|
107353
|
+
version: "0.1.59",
|
|
107321
107354
|
type: "module",
|
|
107322
107355
|
bin: {
|
|
107323
107356
|
pullfrog: "dist/cli.mjs",
|
|
@@ -107349,6 +107382,8 @@ var package_default = {
|
|
|
107349
107382
|
"@clack/prompts": "^1.2.0",
|
|
107350
107383
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
107351
107384
|
"@opencode-ai/sdk": "1.18.5",
|
|
107385
|
+
"@openai/codex": "0.147.0",
|
|
107386
|
+
"@openai/codex-sdk": "0.147.0",
|
|
107352
107387
|
"@octokit/plugin-throttling": "^11.0.3",
|
|
107353
107388
|
"@octokit/rest": "^22.0.0",
|
|
107354
107389
|
"@octokit/webhooks-types": "^7.6.1",
|
|
@@ -109470,13 +109505,735 @@ var claude = agent({
|
|
|
109470
109505
|
}
|
|
109471
109506
|
});
|
|
109472
109507
|
|
|
109473
|
-
// agents/
|
|
109508
|
+
// agents/codex.ts
|
|
109474
109509
|
var core2 = __toESM(require_core(), 1);
|
|
109475
|
-
import {
|
|
109476
|
-
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
109510
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
109477
109511
|
import { join as join7 } from "node:path";
|
|
109478
109512
|
import { performance as performance6 } from "node:perf_hooks";
|
|
109479
109513
|
|
|
109514
|
+
// utils/codexHome.ts
|
|
109515
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
109516
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
109517
|
+
import { homedir as homedir2, userInfo } from "node:os";
|
|
109518
|
+
import { join as join6 } from "node:path";
|
|
109519
|
+
var CODEX_AUTH_ENV = "CODEX_AUTH_JSON";
|
|
109520
|
+
var PULLFROG_DATA_DIR = "/var/lib/pullfrog";
|
|
109521
|
+
function isRejectedChain(body) {
|
|
109522
|
+
if (!body.refresh_rejected_at) return false;
|
|
109523
|
+
log2.warning(
|
|
109524
|
+
`\xBB ${CODEX_AUTH_ENV} was rejected by OpenAI at ${body.refresh_rejected_at} and cannot be refreshed \u2014 re-run \`npx pullfrog auth codex\`. skipping it for this run.`
|
|
109525
|
+
);
|
|
109526
|
+
return true;
|
|
109527
|
+
}
|
|
109528
|
+
function installCodexAuth() {
|
|
109529
|
+
const raw2 = process.env[CODEX_AUTH_ENV];
|
|
109530
|
+
if (!raw2) return null;
|
|
109531
|
+
const body = parseCodexAuthBody(raw2);
|
|
109532
|
+
if (!body) {
|
|
109533
|
+
log2.warning(`\xBB ${CODEX_AUTH_ENV} present but malformed; ignoring`);
|
|
109534
|
+
return null;
|
|
109535
|
+
}
|
|
109536
|
+
if (isRejectedChain(body)) return null;
|
|
109537
|
+
const expiresMs = decodeJwtExpMs(body.tokens.access_token) ?? 0;
|
|
109538
|
+
const xdgDataHome = resolveDataHome();
|
|
109539
|
+
const opencodeDir = join6(xdgDataHome, "opencode");
|
|
109540
|
+
const authPath = join6(opencodeDir, "auth.json");
|
|
109541
|
+
const opencodeAuth = {
|
|
109542
|
+
openai: {
|
|
109543
|
+
type: "oauth",
|
|
109544
|
+
refresh: body.tokens.refresh_token,
|
|
109545
|
+
access: body.tokens.access_token,
|
|
109546
|
+
expires: expiresMs,
|
|
109547
|
+
...body.tokens.account_id ? { accountId: body.tokens.account_id } : {}
|
|
109548
|
+
}
|
|
109549
|
+
};
|
|
109550
|
+
mkdirSync5(opencodeDir, { recursive: true });
|
|
109551
|
+
writeFileSync5(authPath, `${JSON.stringify(opencodeAuth, null, 2)}
|
|
109552
|
+
`, { mode: 384 });
|
|
109553
|
+
process.env.XDG_DATA_HOME = xdgDataHome;
|
|
109554
|
+
log2.info(`\xBB installed Codex auth at ${authPath}`);
|
|
109555
|
+
return {
|
|
109556
|
+
authPath,
|
|
109557
|
+
xdgDataHome,
|
|
109558
|
+
originalRefresh: body.tokens.refresh_token,
|
|
109559
|
+
originalIdToken: body.tokens.id_token
|
|
109560
|
+
};
|
|
109561
|
+
}
|
|
109562
|
+
function installCodexHome() {
|
|
109563
|
+
const raw2 = process.env[CODEX_AUTH_ENV];
|
|
109564
|
+
if (!raw2) return null;
|
|
109565
|
+
const body = parseCodexAuthBody(raw2);
|
|
109566
|
+
if (!body) {
|
|
109567
|
+
log2.warning(`\xBB ${CODEX_AUTH_ENV} present but malformed; ignoring`);
|
|
109568
|
+
return null;
|
|
109569
|
+
}
|
|
109570
|
+
if (isRejectedChain(body)) return null;
|
|
109571
|
+
if (!body.tokens.id_token) {
|
|
109572
|
+
log2.warning(
|
|
109573
|
+
`\xBB ${CODEX_AUTH_ENV} carries no id_token \u2014 the codex CLI cannot load it. re-run \`npx pullfrog auth codex\` to mint a complete credential.`
|
|
109574
|
+
);
|
|
109575
|
+
return null;
|
|
109576
|
+
}
|
|
109577
|
+
const codexHome = join6(resolveDataHome(), "codex");
|
|
109578
|
+
const authPath = join6(codexHome, "auth.json");
|
|
109579
|
+
mkdirSync5(codexHome, { recursive: true });
|
|
109580
|
+
writeFileSync5(authPath, stringifyCodexAuthBody(body), { mode: 384 });
|
|
109581
|
+
log2.info(`\xBB installed Codex auth at ${authPath}`);
|
|
109582
|
+
return { codexHome, authPath, originalRefresh: body.tokens.refresh_token };
|
|
109583
|
+
}
|
|
109584
|
+
function resolveDataHome() {
|
|
109585
|
+
if (process.env.CI !== "true") return join6(homedir2(), ".local", "share");
|
|
109586
|
+
bootstrapPullfrogDataDir();
|
|
109587
|
+
return PULLFROG_DATA_DIR;
|
|
109588
|
+
}
|
|
109589
|
+
function bootstrapPullfrogDataDir() {
|
|
109590
|
+
const user = userInfo().username;
|
|
109591
|
+
let primaryGroup;
|
|
109592
|
+
try {
|
|
109593
|
+
primaryGroup = execFileSync4("id", ["-gn", user], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
109594
|
+
} catch {
|
|
109595
|
+
primaryGroup = user;
|
|
109596
|
+
}
|
|
109597
|
+
try {
|
|
109598
|
+
execFileSync4("sudo", ["-n", "mkdir", "-p", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
109599
|
+
execFileSync4("sudo", ["-n", "chown", `${user}:${primaryGroup}`, PULLFROG_DATA_DIR], {
|
|
109600
|
+
stdio: "pipe"
|
|
109601
|
+
});
|
|
109602
|
+
execFileSync4("sudo", ["-n", "chmod", "700", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
109603
|
+
} catch (err) {
|
|
109604
|
+
throw new Error(
|
|
109605
|
+
`failed to bootstrap ${PULLFROG_DATA_DIR} (required for codex auth in CI): ${err instanceof Error ? err.message : String(err)}. the MCP shell's mount-namespace sandbox cannot protect the auth file when it lives under $HOME, and silently falling back would contradict the "three independent layers" claim in wiki/codex-auth.md. passwordless sudo is required for codex auth on this runner \u2014 either configure it, or remove CODEX_AUTH_JSON from the run.`
|
|
109606
|
+
);
|
|
109607
|
+
}
|
|
109608
|
+
}
|
|
109609
|
+
|
|
109610
|
+
// utils/secrets.ts
|
|
109611
|
+
var SENSITIVE_PATTERNS = [
|
|
109612
|
+
/_KEY$/i,
|
|
109613
|
+
/_SECRET$/i,
|
|
109614
|
+
/_TOKEN$/i,
|
|
109615
|
+
/_PASSWORD$/i,
|
|
109616
|
+
/_CREDENTIAL$/i
|
|
109617
|
+
];
|
|
109618
|
+
function isSensitiveEnvName(key) {
|
|
109619
|
+
return SENSITIVE_PATTERNS.some((p) => p.test(key));
|
|
109620
|
+
}
|
|
109621
|
+
var SAFE_ENV_PREFIXES = ["GITHUB_", "RUNNER_", "JAVA_HOME_", "GOROOT_"];
|
|
109622
|
+
var SAFE_ENV_NAMES = /* @__PURE__ */ new Set([
|
|
109623
|
+
// system
|
|
109624
|
+
"CI",
|
|
109625
|
+
"HOME",
|
|
109626
|
+
"LANG",
|
|
109627
|
+
"LOGNAME",
|
|
109628
|
+
"PATH",
|
|
109629
|
+
"SHELL",
|
|
109630
|
+
"SHLVL",
|
|
109631
|
+
"TERM",
|
|
109632
|
+
"TMPDIR",
|
|
109633
|
+
"TZ",
|
|
109634
|
+
"USER",
|
|
109635
|
+
"XDG_CONFIG_HOME",
|
|
109636
|
+
"XDG_RUNTIME_DIR",
|
|
109637
|
+
"DEBIAN_FRONTEND",
|
|
109638
|
+
// runner image toolchain
|
|
109639
|
+
"ACCEPT_EULA",
|
|
109640
|
+
"AGENT_TOOLSDIRECTORY",
|
|
109641
|
+
"ANDROID_HOME",
|
|
109642
|
+
"ANDROID_NDK",
|
|
109643
|
+
"ANDROID_NDK_HOME",
|
|
109644
|
+
"ANDROID_NDK_LATEST_HOME",
|
|
109645
|
+
"ANDROID_NDK_ROOT",
|
|
109646
|
+
"ANDROID_SDK_ROOT",
|
|
109647
|
+
"ANT_HOME",
|
|
109648
|
+
"AZURE_EXTENSION_DIR",
|
|
109649
|
+
"BOOTSTRAP_HASKELL_NONINTERACTIVE",
|
|
109650
|
+
"CHROME_BIN",
|
|
109651
|
+
"CHROMEWEBDRIVER",
|
|
109652
|
+
"CONDA",
|
|
109653
|
+
"DOTNET_MULTILEVEL_LOOKUP",
|
|
109654
|
+
"DOTNET_NOLOGO",
|
|
109655
|
+
"DOTNET_SKIP_FIRST_TIME_EXPERIENCE",
|
|
109656
|
+
"EDGEWEBDRIVER",
|
|
109657
|
+
"GECKOWEBDRIVER",
|
|
109658
|
+
"GHCUP_INSTALL_BASE_PREFIX",
|
|
109659
|
+
"GRADLE_HOME",
|
|
109660
|
+
"JAVA_HOME",
|
|
109661
|
+
"HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS",
|
|
109662
|
+
"HOMEBREW_NO_AUTO_UPDATE",
|
|
109663
|
+
"ImageOS",
|
|
109664
|
+
"ImageVersion",
|
|
109665
|
+
"NVM_DIR",
|
|
109666
|
+
"PIPX_BIN_DIR",
|
|
109667
|
+
"PIPX_HOME",
|
|
109668
|
+
"PSModulePath",
|
|
109669
|
+
"SELENIUM_JAR_PATH",
|
|
109670
|
+
"SGX_AESM_ADDR",
|
|
109671
|
+
"SWIFT_PATH",
|
|
109672
|
+
"VCPKG_INSTALLATION_ROOT"
|
|
109673
|
+
]);
|
|
109674
|
+
var _userAllowlist = null;
|
|
109675
|
+
function setEnvAllowlist(raw2) {
|
|
109676
|
+
const names = raw2.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
109677
|
+
_userAllowlist = new Set(names);
|
|
109678
|
+
}
|
|
109679
|
+
function isSafeEnvVar(key) {
|
|
109680
|
+
if (SAFE_ENV_NAMES.has(key)) return true;
|
|
109681
|
+
return SAFE_ENV_PREFIXES.some((p) => key.startsWith(p));
|
|
109682
|
+
}
|
|
109683
|
+
var WORKFLOW_COMMAND_ENV_NAMES = [
|
|
109684
|
+
"GITHUB_ENV",
|
|
109685
|
+
"GITHUB_PATH",
|
|
109686
|
+
"GITHUB_OUTPUT",
|
|
109687
|
+
"GITHUB_STATE",
|
|
109688
|
+
"GITHUB_STEP_SUMMARY",
|
|
109689
|
+
// dropping the five paths above but keeping RUNNER_TEMP would be theatre:
|
|
109690
|
+
// the file-command files live in `$RUNNER_TEMP/_runner_file_commands/`, so the
|
|
109691
|
+
// directory is one `ls` away. nothing in the install path reads it (only our
|
|
109692
|
+
// own leak-surface wipe in `setup.ts`, which runs in the parent), and package
|
|
109693
|
+
// managers use TMPDIR.
|
|
109694
|
+
"RUNNER_TEMP"
|
|
109695
|
+
];
|
|
109696
|
+
function filterEnvForUntrustedCode() {
|
|
109697
|
+
const env2 = filterEnv();
|
|
109698
|
+
for (const name of WORKFLOW_COMMAND_ENV_NAMES) delete env2[name];
|
|
109699
|
+
return env2;
|
|
109700
|
+
}
|
|
109701
|
+
function filterEnv() {
|
|
109702
|
+
const filtered = {};
|
|
109703
|
+
for (const [key, value2] of Object.entries(process.env)) {
|
|
109704
|
+
if (value2 === void 0) continue;
|
|
109705
|
+
const userAllowed = _userAllowlist?.has(key) ?? false;
|
|
109706
|
+
if (isSensitiveEnvName(key) && !userAllowed) continue;
|
|
109707
|
+
if (isSafeEnvVar(key) || userAllowed) {
|
|
109708
|
+
filtered[key] = value2;
|
|
109709
|
+
}
|
|
109710
|
+
}
|
|
109711
|
+
return filtered;
|
|
109712
|
+
}
|
|
109713
|
+
function resolveEnv(mode) {
|
|
109714
|
+
if (mode === "inherit") {
|
|
109715
|
+
return process.env;
|
|
109716
|
+
}
|
|
109717
|
+
if (mode === "restricted" || mode === void 0) {
|
|
109718
|
+
return filterEnv();
|
|
109719
|
+
}
|
|
109720
|
+
return { ...filterEnv(), ...mode };
|
|
109721
|
+
}
|
|
109722
|
+
|
|
109723
|
+
// agents/codex.ts
|
|
109724
|
+
var CODEX_TARGETS = {
|
|
109725
|
+
"linux-x64": "x86_64-unknown-linux-musl",
|
|
109726
|
+
"linux-arm64": "aarch64-unknown-linux-musl",
|
|
109727
|
+
"darwin-x64": "x86_64-apple-darwin",
|
|
109728
|
+
"darwin-arm64": "aarch64-apple-darwin",
|
|
109729
|
+
"win32-x64": "x86_64-pc-windows-msvc",
|
|
109730
|
+
"win32-arm64": "aarch64-pc-windows-msvc"
|
|
109731
|
+
};
|
|
109732
|
+
async function installCodexCli() {
|
|
109733
|
+
const target = CODEX_TARGETS[`${process.platform}-${process.arch}`];
|
|
109734
|
+
if (!target) {
|
|
109735
|
+
throw new Error(`the codex CLI ships no binary for ${process.platform}-${process.arch}`);
|
|
109736
|
+
}
|
|
109737
|
+
const binary = process.platform === "win32" ? "codex.exe" : "codex";
|
|
109738
|
+
return await installFromNpmTarball({
|
|
109739
|
+
packageName: "@openai/codex",
|
|
109740
|
+
version: getDevDependencyVersion("@openai/codex"),
|
|
109741
|
+
executablePath: `node_modules/@openai/codex-${process.platform}-${process.arch}/vendor/${target}/bin/${binary}`,
|
|
109742
|
+
installDependencies: true
|
|
109743
|
+
});
|
|
109744
|
+
}
|
|
109745
|
+
var CODEX_DISABLED_FEATURES = [
|
|
109746
|
+
// browser / desktop control — network reach and arbitrary JS
|
|
109747
|
+
"browser_use",
|
|
109748
|
+
"browser_use_external",
|
|
109749
|
+
"browser_use_full_cdp_access",
|
|
109750
|
+
"computer_use",
|
|
109751
|
+
"in_app_browser",
|
|
109752
|
+
// third-party code loaded into the agent process
|
|
109753
|
+
"plugins",
|
|
109754
|
+
"remote_plugin",
|
|
109755
|
+
"plugin_sharing",
|
|
109756
|
+
"skill_mcp_dependency_install",
|
|
109757
|
+
// lifecycle hooks run commands sourced from repo config, which a PR can edit
|
|
109758
|
+
"hooks",
|
|
109759
|
+
// connectors
|
|
109760
|
+
"apps",
|
|
109761
|
+
// ungated subagent fan-out (see the file header)
|
|
109762
|
+
"multi_agent",
|
|
109763
|
+
"multi_agent_v2"
|
|
109764
|
+
];
|
|
109765
|
+
var CODEX_SHELL_FEATURES = ["shell_tool", "unified_exec"];
|
|
109766
|
+
function tomlBool(entries, value2) {
|
|
109767
|
+
return entries.map((name) => `${name} = ${value2}`).join("\n");
|
|
109768
|
+
}
|
|
109769
|
+
function securityOverrideFlags(params) {
|
|
109770
|
+
const shellEnabled = params.ctx.payload.shell === "enabled";
|
|
109771
|
+
const features = [
|
|
109772
|
+
...CODEX_DISABLED_FEATURES.map((name) => `${name}=false`),
|
|
109773
|
+
...CODEX_SHELL_FEATURES.map((name) => `${name}=${shellEnabled}`)
|
|
109774
|
+
];
|
|
109775
|
+
return [
|
|
109776
|
+
"-c",
|
|
109777
|
+
`approval_policy=${JSON.stringify("never")}`,
|
|
109778
|
+
"-c",
|
|
109779
|
+
`sandbox_mode=${JSON.stringify(params.sandboxMode)}`,
|
|
109780
|
+
// the sandbox's EXTENT has to be locked too, not just its mode: a repo
|
|
109781
|
+
// setting `writable_roots = ["/"]` walked straight out of the checkout with
|
|
109782
|
+
// `sandbox_mode` already flag-locked (measured — apply_patch wrote a file
|
|
109783
|
+
// under $HOME).
|
|
109784
|
+
"-c",
|
|
109785
|
+
`sandbox_workspace_write.writable_roots=[${JSON.stringify(params.repoDir)}]`,
|
|
109786
|
+
"-c",
|
|
109787
|
+
"sandbox_workspace_write.network_access=true",
|
|
109788
|
+
// our own MCP server, for a third time in the same class: a repo pointing
|
|
109789
|
+
// `mcp_servers.pullfrog.url` at its own endpoint (measured — `codex mcp get`
|
|
109790
|
+
// reported the repo's URL) turns every pullfrog tool call into an
|
|
109791
|
+
// exfiltration channel, carrying diffs, file contents and cross-repo
|
|
109792
|
+
// learnings to whoever it names.
|
|
109793
|
+
"-c",
|
|
109794
|
+
`mcp_servers.${pullfrogMcpName}.url=${JSON.stringify(params.mcpServerUrl)}`,
|
|
109795
|
+
"-c",
|
|
109796
|
+
`mcp_servers.${pullfrogMcpName}.${APPROVAL_MODE_KEY}=${JSON.stringify("approve")}`,
|
|
109797
|
+
"-c",
|
|
109798
|
+
`mcp_servers.${pullfrogMcpName}.required=true`,
|
|
109799
|
+
"-c",
|
|
109800
|
+
`mcp_servers.${pullfrogMcpName}.tool_timeout_sec=660`,
|
|
109801
|
+
// `enabled` closes the silent-DoS variant: a repo setting it false would
|
|
109802
|
+
// otherwise strip every GitHub tool and leave the agent narrating failure.
|
|
109803
|
+
"-c",
|
|
109804
|
+
`mcp_servers.${pullfrogMcpName}.enabled=true`,
|
|
109805
|
+
// not a boundary, but the same override: a repo silently re-pointing the
|
|
109806
|
+
// model spends the account's money on a pick it never made, and makes the
|
|
109807
|
+
// "Using `…`" run footer a lie about what actually ran.
|
|
109808
|
+
...params.model ? ["-c", `model=${JSON.stringify(params.model)}`] : [],
|
|
109809
|
+
...params.effortRung ? ["-c", `model_reasoning_effort=${JSON.stringify(params.effortRung)}`] : [],
|
|
109810
|
+
...features.flatMap((entry) => ["-c", `features.${entry}`])
|
|
109811
|
+
];
|
|
109812
|
+
}
|
|
109813
|
+
var CODEX_EFFORTS = ["minimal", "low", "medium", "high", "xhigh"];
|
|
109814
|
+
function resolveCodexModel(ctx) {
|
|
109815
|
+
const specifier = ctx.payload.proxyModel ?? ctx.resolvedModel;
|
|
109816
|
+
if (!specifier) return void 0;
|
|
109817
|
+
try {
|
|
109818
|
+
if (getModelProvider(specifier) === "openai") return stripProviderPrefix(specifier);
|
|
109819
|
+
} catch {
|
|
109820
|
+
}
|
|
109821
|
+
log2.warning(`\xBB ${specifier} isn't an OpenAI model \u2014 running codex on its own default instead`);
|
|
109822
|
+
return void 0;
|
|
109823
|
+
}
|
|
109824
|
+
var APPROVAL_MODE_KEY = "default_tools_approval_mode";
|
|
109825
|
+
var APPROVE_TOOLS = `${APPROVAL_MODE_KEY} = "approve"`;
|
|
109826
|
+
function repoMcpApprovals(repoDir) {
|
|
109827
|
+
const path4 = join7(repoDir, ".codex", "config.toml");
|
|
109828
|
+
if (!existsSync4(path4)) return [];
|
|
109829
|
+
const out = [];
|
|
109830
|
+
let section = [];
|
|
109831
|
+
let isServerTable = false;
|
|
109832
|
+
function flush() {
|
|
109833
|
+
if (section.length === 0) return;
|
|
109834
|
+
const declared = section.some((line) => line.trimStart().startsWith(APPROVAL_MODE_KEY));
|
|
109835
|
+
if (isServerTable && !declared) section.splice(1, 0, APPROVE_TOOLS);
|
|
109836
|
+
out.push(...section, "");
|
|
109837
|
+
section = [];
|
|
109838
|
+
}
|
|
109839
|
+
for (const line of readFileSync3(path4, "utf8").split("\n")) {
|
|
109840
|
+
const header = line.trim().match(/^\[(?<key>[^\]]+)\]$/);
|
|
109841
|
+
if (!header?.groups) {
|
|
109842
|
+
if (section.length > 0) section.push(line);
|
|
109843
|
+
continue;
|
|
109844
|
+
}
|
|
109845
|
+
flush();
|
|
109846
|
+
const key = header.groups.key.trim();
|
|
109847
|
+
if (!key.startsWith("mcp_servers.")) continue;
|
|
109848
|
+
const name = key.slice("mcp_servers.".length).replace(/^"([^"]*)"/, "$1");
|
|
109849
|
+
if (name === pullfrogMcpName || name.startsWith(`${pullfrogMcpName}.`)) continue;
|
|
109850
|
+
isServerTable = !name.includes(".");
|
|
109851
|
+
section = [line.trim()];
|
|
109852
|
+
}
|
|
109853
|
+
flush();
|
|
109854
|
+
return out;
|
|
109855
|
+
}
|
|
109856
|
+
function warnIfNativeEditsUnavailable(ctx) {
|
|
109857
|
+
if (process.platform !== "linux" || ctx.payload.shell !== "disabled") return;
|
|
109858
|
+
log2.warning(
|
|
109859
|
+
"\xBB this run cannot change files: codex's native write tool depends on bubblewrap, which Ubuntu 24.04 blocks (https://github.com/openai/codex/issues/29908), and the MCP shell is disabled for this repo. read-only work is unaffected \u2014 set `shell: restricted` if the agent needs to edit anything."
|
|
109860
|
+
);
|
|
109861
|
+
}
|
|
109862
|
+
function writeCodexConfig(params) {
|
|
109863
|
+
const shellEnabled = params.ctx.payload.shell === "enabled";
|
|
109864
|
+
const sandboxMode = params.ctx.payload.push === "disabled" ? "read-only" : "workspace-write";
|
|
109865
|
+
const repoDir = process.cwd();
|
|
109866
|
+
const config3 = [
|
|
109867
|
+
"# written by pullfrog",
|
|
109868
|
+
// "never" keeps the run non-interactive WITHOUT
|
|
109869
|
+
// --dangerously-bypass-approvals-and-sandbox, which would also switch the
|
|
109870
|
+
// sandbox off and let the native apply_patch tool write anywhere.
|
|
109871
|
+
'approval_policy = "never"',
|
|
109872
|
+
`sandbox_mode = ${JSON.stringify(sandboxMode)}`,
|
|
109873
|
+
// matches opencode's `webfetch: "allow"` — research is part of the job and
|
|
109874
|
+
// neither harness gates it on a permission.
|
|
109875
|
+
'web_search = "live"',
|
|
109876
|
+
...params.model ? [`model = ${JSON.stringify(params.model)}`] : [],
|
|
109877
|
+
...params.effortRung ? [`model_reasoning_effort = ${JSON.stringify(params.effortRung)}`] : [],
|
|
109878
|
+
"",
|
|
109879
|
+
"[features]",
|
|
109880
|
+
tomlBool(CODEX_DISABLED_FEATURES, false),
|
|
109881
|
+
tomlBool(CODEX_SHELL_FEATURES, shellEnabled),
|
|
109882
|
+
"",
|
|
109883
|
+
"[sandbox_workspace_write]",
|
|
109884
|
+
"network_access = true",
|
|
109885
|
+
// the checkout, named explicitly rather than left to `workspace-write` to
|
|
109886
|
+
// imply. does NOT fix the Linux native-write failure — nothing here does;
|
|
109887
|
+
// see wiki/codex-agent.md "The Linux native-write blocker".
|
|
109888
|
+
`writable_roots = [${JSON.stringify(repoDir)}]`,
|
|
109889
|
+
"",
|
|
109890
|
+
`[mcp_servers.${pullfrogMcpName}]`,
|
|
109891
|
+
`url = ${JSON.stringify(params.ctx.mcpServerUrl)}`,
|
|
109892
|
+
// codex's default MCP approval mode PROMPTS for anything it can't read as
|
|
109893
|
+
// read-only, and a `codex exec` run has nobody to answer — the call comes
|
|
109894
|
+
// back "user cancelled MCP tool call" and the agent silently accomplishes
|
|
109895
|
+
// nothing. our own server is the trusted one; the boundary is what we
|
|
109896
|
+
// register, not a second confirmation.
|
|
109897
|
+
APPROVE_TOOLS,
|
|
109898
|
+
// a run whose GitHub tools never registered can't do its job, so fail loudly
|
|
109899
|
+
// rather than let the agent improvise without them.
|
|
109900
|
+
"required = true",
|
|
109901
|
+
// mirrors the opencode harness's 660s: `checkout_pr` runs a multi-minute
|
|
109902
|
+
// fetch on large repos and enforces its own 600s deadline, so a shorter
|
|
109903
|
+
// client abort turns a working checkout into a spurious tool error.
|
|
109904
|
+
"tool_timeout_sec = 660",
|
|
109905
|
+
"",
|
|
109906
|
+
...repoMcpApprovals(repoDir),
|
|
109907
|
+
// UNTRUSTED, deliberately, and this one line is the whole config-precedence
|
|
109908
|
+
// boundary. Codex loads `<repo>/.codex/config.toml` as a layer that
|
|
109909
|
+
// OUTRANKS ours (project 25 vs user 20), and its denylist strips none of
|
|
109910
|
+
// `sandbox_mode`, `approval_policy`, `features` or `mcp_servers` — so a
|
|
109911
|
+
// fork PR could ship a config re-enabling the native shell. Marking the
|
|
109912
|
+
// checkout untrusted makes that layer load `disabled`, closing the class
|
|
109913
|
+
// outright rather than key by key: `RawMcpServerConfig` alone has ~26
|
|
109914
|
+
// fields and enumeration can never finish.
|
|
109915
|
+
//
|
|
109916
|
+
// It costs nothing. `codex exec`'s only startup gate is a GIT-REPO check
|
|
109917
|
+
// (`exec/src/lib.rs:796` — `get_git_repo_root(...).is_none()`, whose error
|
|
109918
|
+
// text unhelpfully says "Not inside a trusted directory"), so an untrusted
|
|
109919
|
+
// checkout still runs. And the repo's own MCP servers survive, because
|
|
109920
|
+
// `repoMcpApprovals` above copies them into OUR layer — which is why that
|
|
109921
|
+
// copying exists at all.
|
|
109922
|
+
//
|
|
109923
|
+
// Measured both ways at 0.147.0: `trusted` → the repo's `model` won;
|
|
109924
|
+
// `untrusted` → it did not, and the run proceeded normally.
|
|
109925
|
+
`[projects.${JSON.stringify(repoDir)}]`,
|
|
109926
|
+
'trust_level = "untrusted"',
|
|
109927
|
+
""
|
|
109928
|
+
].join("\n");
|
|
109929
|
+
writeFileSync6(join7(params.codexHome, "config.toml"), config3, { mode: 384 });
|
|
109930
|
+
log2.info(`\xBB codex config: sandbox=${sandboxMode}, nativeShell=${shellEnabled}`);
|
|
109931
|
+
}
|
|
109932
|
+
function toTodoWriteInput(item) {
|
|
109933
|
+
return {
|
|
109934
|
+
todos: item.items.map((todo, index) => ({
|
|
109935
|
+
id: String(index),
|
|
109936
|
+
content: todo.text,
|
|
109937
|
+
status: todo.completed ? "completed" : "pending"
|
|
109938
|
+
}))
|
|
109939
|
+
};
|
|
109940
|
+
}
|
|
109941
|
+
async function runCodex2(params) {
|
|
109942
|
+
const startTime = performance6.now();
|
|
109943
|
+
const thinkingTimer = new ThinkingTimer();
|
|
109944
|
+
const output = new TailBuffer(DEFAULT_MAX_RETAINED_BYTES);
|
|
109945
|
+
const recentStderr = [];
|
|
109946
|
+
let eventCount = 0;
|
|
109947
|
+
let finalOutput = "";
|
|
109948
|
+
let threadId;
|
|
109949
|
+
let turnError = null;
|
|
109950
|
+
let lastProviderError = null;
|
|
109951
|
+
let stdoutBuffer = "";
|
|
109952
|
+
const tokens = { input: 0, cacheRead: 0, output: 0 };
|
|
109953
|
+
function buildUsage2() {
|
|
109954
|
+
if (tokens.input === 0 && tokens.output === 0) return void 0;
|
|
109955
|
+
return {
|
|
109956
|
+
agent: "codex",
|
|
109957
|
+
inputTokens: tokens.input,
|
|
109958
|
+
outputTokens: tokens.output,
|
|
109959
|
+
cacheReadTokens: tokens.cacheRead || void 0
|
|
109960
|
+
};
|
|
109961
|
+
}
|
|
109962
|
+
function onItem(item, phase) {
|
|
109963
|
+
switch (item.type) {
|
|
109964
|
+
case "agent_message":
|
|
109965
|
+
if (phase === "completed" && item.text.trim()) {
|
|
109966
|
+
finalOutput = item.text.trim();
|
|
109967
|
+
log2.box(finalOutput, { title: "Pullfrog" });
|
|
109968
|
+
}
|
|
109969
|
+
return;
|
|
109970
|
+
case "reasoning":
|
|
109971
|
+
if (phase === "completed" && item.text.trim()) {
|
|
109972
|
+
log2.box(item.text.trim(), { title: "Pullfrog" });
|
|
109973
|
+
}
|
|
109974
|
+
return;
|
|
109975
|
+
case "command_execution":
|
|
109976
|
+
if (phase === "started") {
|
|
109977
|
+
thinkingTimer.markToolCall();
|
|
109978
|
+
log2.toolCall({ toolName: "shell", input: { command: item.command } });
|
|
109979
|
+
return;
|
|
109980
|
+
}
|
|
109981
|
+
thinkingTimer.markToolResult();
|
|
109982
|
+
log2.startGroup("shell output");
|
|
109983
|
+
log2.info(item.aggregated_output || "");
|
|
109984
|
+
log2.endGroup();
|
|
109985
|
+
return;
|
|
109986
|
+
case "mcp_tool_call":
|
|
109987
|
+
if (phase === "started") {
|
|
109988
|
+
thinkingTimer.markToolCall();
|
|
109989
|
+
params.onToolUse?.({ toolName: item.tool, input: item.arguments });
|
|
109990
|
+
log2.toolCall({ toolName: `${item.server}__${item.tool}`, input: item.arguments });
|
|
109991
|
+
if (item.tool.includes("report_progress")) params.todoTracker?.cancel();
|
|
109992
|
+
return;
|
|
109993
|
+
}
|
|
109994
|
+
thinkingTimer.markToolResult();
|
|
109995
|
+
if (item.error) log2.info(`\xBB tool error: ${item.error.message}`);
|
|
109996
|
+
return;
|
|
109997
|
+
case "file_change":
|
|
109998
|
+
if (phase === "completed") {
|
|
109999
|
+
const paths = item.changes.map((c2) => `${c2.kind} ${c2.path}`).join(", ");
|
|
110000
|
+
log2.info(`\xBB apply_patch (${item.status}): ${paths}`);
|
|
110001
|
+
}
|
|
110002
|
+
return;
|
|
110003
|
+
case "web_search":
|
|
110004
|
+
if (phase === "started") log2.toolCall({ toolName: "web_search", input: item.query });
|
|
110005
|
+
return;
|
|
110006
|
+
case "todo_list":
|
|
110007
|
+
if (params.todoTracker?.enabled) params.todoTracker.update(toTodoWriteInput(item));
|
|
110008
|
+
return;
|
|
110009
|
+
case "error":
|
|
110010
|
+
log2.info(`\xBB ${item.message}`);
|
|
110011
|
+
return;
|
|
110012
|
+
default:
|
|
110013
|
+
item;
|
|
110014
|
+
}
|
|
110015
|
+
}
|
|
110016
|
+
function onEvent(event) {
|
|
110017
|
+
switch (event.type) {
|
|
110018
|
+
case "thread.started":
|
|
110019
|
+
threadId = event.thread_id;
|
|
110020
|
+
return;
|
|
110021
|
+
case "turn.completed":
|
|
110022
|
+
tokens.input += event.usage.input_tokens ?? 0;
|
|
110023
|
+
tokens.cacheRead += event.usage.cached_input_tokens ?? 0;
|
|
110024
|
+
tokens.output += event.usage.output_tokens ?? 0;
|
|
110025
|
+
return;
|
|
110026
|
+
case "turn.failed":
|
|
110027
|
+
turnError = event.error.message;
|
|
110028
|
+
log2.info(`\xBB turn failed: ${turnError}`);
|
|
110029
|
+
return;
|
|
110030
|
+
case "error":
|
|
110031
|
+
turnError = event.message;
|
|
110032
|
+
log2.info(`\xBB codex error: ${event.message}`);
|
|
110033
|
+
return;
|
|
110034
|
+
case "item.started":
|
|
110035
|
+
onItem(event.item, "started");
|
|
110036
|
+
return;
|
|
110037
|
+
case "item.completed":
|
|
110038
|
+
onItem(event.item, "completed");
|
|
110039
|
+
return;
|
|
110040
|
+
case "item.updated":
|
|
110041
|
+
if (event.item.type === "todo_list") onItem(event.item, "started");
|
|
110042
|
+
return;
|
|
110043
|
+
case "turn.started":
|
|
110044
|
+
return;
|
|
110045
|
+
default:
|
|
110046
|
+
event;
|
|
110047
|
+
}
|
|
110048
|
+
}
|
|
110049
|
+
try {
|
|
110050
|
+
const result = await spawn3({
|
|
110051
|
+
cmd: params.cliPath,
|
|
110052
|
+
args: params.args,
|
|
110053
|
+
cwd: params.cwd,
|
|
110054
|
+
env: params.env,
|
|
110055
|
+
activityTimeout: AGENT_ACTIVITY_TIMEOUT_MS,
|
|
110056
|
+
onActivityTimeout: params.onActivityTimeout,
|
|
110057
|
+
// stdin MUST be `ignore`: codex reads a piped stdin as an extra `<stdin>`
|
|
110058
|
+
// prompt block and blocks on EOF, so an inherited pipe hangs the run
|
|
110059
|
+
// before the first model call.
|
|
110060
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
110061
|
+
killGroup: true,
|
|
110062
|
+
retain: "none",
|
|
110063
|
+
onStdout: (chunk) => {
|
|
110064
|
+
output.append(chunk);
|
|
110065
|
+
markActivity();
|
|
110066
|
+
stdoutBuffer += chunk;
|
|
110067
|
+
const lines = stdoutBuffer.split("\n");
|
|
110068
|
+
stdoutBuffer = lines.pop() || "";
|
|
110069
|
+
for (const line of lines) {
|
|
110070
|
+
const trimmed = line.trim();
|
|
110071
|
+
if (!trimmed) continue;
|
|
110072
|
+
let event;
|
|
110073
|
+
try {
|
|
110074
|
+
event = JSON.parse(trimmed);
|
|
110075
|
+
} catch {
|
|
110076
|
+
log2.debug(`\xBB non-JSON stdout line: ${trimmed.substring(0, 200)}`);
|
|
110077
|
+
continue;
|
|
110078
|
+
}
|
|
110079
|
+
eventCount++;
|
|
110080
|
+
log2.debug(JSON.stringify(event, null, 2));
|
|
110081
|
+
const idleMs = getIdleMs();
|
|
110082
|
+
if (idleMs > 1e4) {
|
|
110083
|
+
log2.info(
|
|
110084
|
+
`\xBB no activity for ${(idleMs / 1e3).toFixed(1)}s (${eventCount} events processed so far)`
|
|
110085
|
+
);
|
|
110086
|
+
}
|
|
110087
|
+
markActivity();
|
|
110088
|
+
onEvent(event);
|
|
110089
|
+
}
|
|
110090
|
+
},
|
|
110091
|
+
onStderr: (chunk) => {
|
|
110092
|
+
const trimmed = chunk.trim();
|
|
110093
|
+
if (!trimmed) return;
|
|
110094
|
+
recentStderr.push(trimmed);
|
|
110095
|
+
if (recentStderr.length > MAX_STDERR_LINES) recentStderr.shift();
|
|
110096
|
+
const match3 = findProviderErrorMatch(trimmed);
|
|
110097
|
+
if (match3) {
|
|
110098
|
+
lastProviderError = match3.label;
|
|
110099
|
+
log2.info(`\xBB provider error detected (${match3.label}): ${match3.excerpt}`);
|
|
110100
|
+
} else {
|
|
110101
|
+
log2.debug(trimmed);
|
|
110102
|
+
}
|
|
110103
|
+
}
|
|
110104
|
+
});
|
|
110105
|
+
const duration4 = performance6.now() - startTime;
|
|
110106
|
+
log2.info(`\xBB codex completed in ${Math.round(duration4)}ms with exit code ${result.exitCode}`);
|
|
110107
|
+
const usage = buildUsage2();
|
|
110108
|
+
if (usage) {
|
|
110109
|
+
logTokenTable({
|
|
110110
|
+
input: tokens.input - tokens.cacheRead,
|
|
110111
|
+
cacheRead: tokens.cacheRead,
|
|
110112
|
+
cacheWrite: 0,
|
|
110113
|
+
output: tokens.output
|
|
110114
|
+
});
|
|
110115
|
+
}
|
|
110116
|
+
if (result.exitCode !== 0 || turnError) {
|
|
110117
|
+
const stderrSnapshot = recentStderr.join("\n");
|
|
110118
|
+
const error52 = turnError || stderrSnapshot || lastProviderError && `provider error: ${lastProviderError}` || `unknown error - no output from Codex CLI (exit ${result.exitCode})`;
|
|
110119
|
+
log2.error(`codex exited with code ${result.exitCode}: ${error52}`);
|
|
110120
|
+
return { success: false, output: finalOutput || output.toString(), error: error52, usage, threadId };
|
|
110121
|
+
}
|
|
110122
|
+
return { success: true, output: finalOutput || output.toString(), usage, threadId };
|
|
110123
|
+
} catch (error52) {
|
|
110124
|
+
const duration4 = performance6.now() - startTime;
|
|
110125
|
+
const message = error52 instanceof Error ? error52.message : String(error52);
|
|
110126
|
+
const isActivityTimeout = error52 instanceof SpawnTimeoutError && error52.code === SPAWN_ACTIVITY_TIMEOUT_CODE;
|
|
110127
|
+
const diagnosis = lastProviderError ? `likely cause: ${lastProviderError}` : eventCount === 0 ? "codex produced 0 stdout events - check if the API is reachable" : `${eventCount} events were processed before the hang`;
|
|
110128
|
+
log2.info(
|
|
110129
|
+
`\xBB codex ${isActivityTimeout ? "hung" : "failed"} after ${(duration4 / 1e3).toFixed(1)}s: ${message}`
|
|
110130
|
+
);
|
|
110131
|
+
log2.info(`\xBB diagnosis: ${diagnosis}`);
|
|
110132
|
+
if (recentStderr.length > 0) log2.info(`\xBB recent stderr:
|
|
110133
|
+
${recentStderr.join("\n")}`);
|
|
110134
|
+
return {
|
|
110135
|
+
success: false,
|
|
110136
|
+
output: finalOutput || output.toString(),
|
|
110137
|
+
error: `${message} [${diagnosis}]`,
|
|
110138
|
+
usage: buildUsage2(),
|
|
110139
|
+
threadId
|
|
110140
|
+
};
|
|
110141
|
+
}
|
|
110142
|
+
}
|
|
110143
|
+
var codex = agent({
|
|
110144
|
+
name: "codex",
|
|
110145
|
+
install: installCodexCli,
|
|
110146
|
+
run: async (ctx) => {
|
|
110147
|
+
const cliPath = await installCodexCli();
|
|
110148
|
+
warnIfNativeEditsUnavailable(ctx);
|
|
110149
|
+
const codexHomeAuth = installCodexHome();
|
|
110150
|
+
const codexHome = codexHomeAuth?.codexHome ?? join7(ctx.tmpdir, ".codex");
|
|
110151
|
+
mkdirSync6(codexHome, { recursive: true });
|
|
110152
|
+
const effort = resolveRunEffort(ctx);
|
|
110153
|
+
if (effort.rung && !CODEX_EFFORTS.includes(effort.rung)) {
|
|
110154
|
+
log2.warning(`\xBB effort ${effort.rung} not sent \u2014 codex doesn't accept that level`);
|
|
110155
|
+
}
|
|
110156
|
+
writeCodexConfig({
|
|
110157
|
+
ctx,
|
|
110158
|
+
codexHome,
|
|
110159
|
+
model: resolveCodexModel(ctx),
|
|
110160
|
+
effortRung: effort.rung && CODEX_EFFORTS.includes(effort.rung) ? effort.rung : void 0
|
|
110161
|
+
});
|
|
110162
|
+
if (codexHomeAuth) {
|
|
110163
|
+
core2.saveState(
|
|
110164
|
+
"codex_writeback",
|
|
110165
|
+
JSON.stringify({
|
|
110166
|
+
apiToken: ctx.apiToken,
|
|
110167
|
+
authPath: codexHomeAuth.authPath,
|
|
110168
|
+
originalRefresh: codexHomeAuth.originalRefresh
|
|
110169
|
+
})
|
|
110170
|
+
);
|
|
110171
|
+
}
|
|
110172
|
+
const baseEnv = ctx.payload.shell === "enabled" ? process.env : filterEnv();
|
|
110173
|
+
const env2 = {
|
|
110174
|
+
...baseEnv,
|
|
110175
|
+
CODEX_HOME: codexHome,
|
|
110176
|
+
PWD: process.cwd()
|
|
110177
|
+
};
|
|
110178
|
+
delete env2.CODEX_API_KEY;
|
|
110179
|
+
if (codexHomeAuth) {
|
|
110180
|
+
delete env2.OPENAI_API_KEY;
|
|
110181
|
+
} else if (process.env.OPENAI_API_KEY) {
|
|
110182
|
+
env2.CODEX_API_KEY = process.env.OPENAI_API_KEY;
|
|
110183
|
+
}
|
|
110184
|
+
const securityFlags = securityOverrideFlags({
|
|
110185
|
+
ctx,
|
|
110186
|
+
sandboxMode: ctx.payload.push === "disabled" ? "read-only" : "workspace-write",
|
|
110187
|
+
repoDir: process.cwd(),
|
|
110188
|
+
mcpServerUrl: ctx.mcpServerUrl,
|
|
110189
|
+
model: resolveCodexModel(ctx),
|
|
110190
|
+
effortRung: effort.rung && CODEX_EFFORTS.includes(effort.rung) ? effort.rung : void 0
|
|
110191
|
+
});
|
|
110192
|
+
const runnerArgs = { cliPath, cwd: process.cwd(), env: env2, todoTracker: ctx.todoTracker };
|
|
110193
|
+
const initial = await runCodex2({
|
|
110194
|
+
...runnerArgs,
|
|
110195
|
+
args: [...securityFlags, "exec", "--json", ctx.instructions.full],
|
|
110196
|
+
onActivityTimeout: ctx.onActivityTimeout,
|
|
110197
|
+
onToolUse: ctx.onToolUse
|
|
110198
|
+
});
|
|
110199
|
+
const result = await runPostRunRetryLoop({
|
|
110200
|
+
ctx,
|
|
110201
|
+
initialResult: initial,
|
|
110202
|
+
initialUsage: initial.usage,
|
|
110203
|
+
reflectionPrompt: buildReflectionPrompt(ctx.toolState),
|
|
110204
|
+
// a resume needs the thread codex recorded. without one there is nothing
|
|
110205
|
+
// to continue, and `resume --last` would be worse than not resuming: it
|
|
110206
|
+
// picks the newest recorded session in this cwd, which on a self-hosted
|
|
110207
|
+
// runner with a shared CODEX_HOME is somebody else's run.
|
|
110208
|
+
canResume: (r2) => r2.threadId !== void 0,
|
|
110209
|
+
resume: async (c2) => runCodex2({
|
|
110210
|
+
...runnerArgs,
|
|
110211
|
+
args: [
|
|
110212
|
+
...securityFlags,
|
|
110213
|
+
"exec",
|
|
110214
|
+
"resume",
|
|
110215
|
+
"--json",
|
|
110216
|
+
c2.previousResult.threadId ?? "",
|
|
110217
|
+
c2.prompt
|
|
110218
|
+
]
|
|
110219
|
+
})
|
|
110220
|
+
});
|
|
110221
|
+
if (result.success) {
|
|
110222
|
+
await ctx.todoTracker?.flush();
|
|
110223
|
+
} else {
|
|
110224
|
+
ctx.todoTracker?.cancel();
|
|
110225
|
+
}
|
|
110226
|
+
return result;
|
|
110227
|
+
}
|
|
110228
|
+
});
|
|
110229
|
+
|
|
110230
|
+
// agents/opencode.ts
|
|
110231
|
+
var core3 = __toESM(require_core(), 1);
|
|
110232
|
+
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
110233
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
110234
|
+
import { join as join8 } from "node:path";
|
|
110235
|
+
import { performance as performance7 } from "node:perf_hooks";
|
|
110236
|
+
|
|
109480
110237
|
// node_modules/.pnpm/@opencode-ai+sdk@1.18.5/node_modules/@opencode-ai/sdk/dist/v2/gen/core/serverSentEvents.gen.js
|
|
109481
110238
|
var createSseClient = ({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url: url4, ...options }) => {
|
|
109482
110239
|
let lastEventId;
|
|
@@ -114883,71 +115640,6 @@ var import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
|
114883
115640
|
// agents/opencode.ts
|
|
114884
115641
|
var import_undici = __toESM(require_undici2(), 1);
|
|
114885
115642
|
|
|
114886
|
-
// utils/codexHome.ts
|
|
114887
|
-
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
114888
|
-
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
114889
|
-
import { homedir as homedir2, userInfo } from "node:os";
|
|
114890
|
-
import { join as join6 } from "node:path";
|
|
114891
|
-
var CODEX_AUTH_ENV = "CODEX_AUTH_JSON";
|
|
114892
|
-
var PULLFROG_DATA_DIR = "/var/lib/pullfrog";
|
|
114893
|
-
function installCodexAuth() {
|
|
114894
|
-
const raw2 = process.env[CODEX_AUTH_ENV];
|
|
114895
|
-
if (!raw2) return null;
|
|
114896
|
-
const body = parseCodexAuthBody(raw2);
|
|
114897
|
-
if (!body) {
|
|
114898
|
-
log2.warning(`\xBB ${CODEX_AUTH_ENV} present but malformed; ignoring`);
|
|
114899
|
-
return null;
|
|
114900
|
-
}
|
|
114901
|
-
const expiresMs = decodeJwtExpMs(body.tokens.access_token) ?? 0;
|
|
114902
|
-
const xdgDataHome = resolveDataHome();
|
|
114903
|
-
const opencodeDir = join6(xdgDataHome, "opencode");
|
|
114904
|
-
const authPath = join6(opencodeDir, "auth.json");
|
|
114905
|
-
const opencodeAuth = {
|
|
114906
|
-
openai: {
|
|
114907
|
-
type: "oauth",
|
|
114908
|
-
refresh: body.tokens.refresh_token,
|
|
114909
|
-
access: body.tokens.access_token,
|
|
114910
|
-
expires: expiresMs,
|
|
114911
|
-
...body.tokens.account_id ? { accountId: body.tokens.account_id } : {}
|
|
114912
|
-
}
|
|
114913
|
-
};
|
|
114914
|
-
mkdirSync5(opencodeDir, { recursive: true });
|
|
114915
|
-
writeFileSync5(authPath, `${JSON.stringify(opencodeAuth, null, 2)}
|
|
114916
|
-
`, { mode: 384 });
|
|
114917
|
-
process.env.XDG_DATA_HOME = xdgDataHome;
|
|
114918
|
-
log2.info(`\xBB installed Codex auth at ${authPath}`);
|
|
114919
|
-
return {
|
|
114920
|
-
authPath,
|
|
114921
|
-
xdgDataHome,
|
|
114922
|
-
originalRefresh: body.tokens.refresh_token
|
|
114923
|
-
};
|
|
114924
|
-
}
|
|
114925
|
-
function resolveDataHome() {
|
|
114926
|
-
if (process.env.CI !== "true") return join6(homedir2(), ".local", "share");
|
|
114927
|
-
bootstrapPullfrogDataDir();
|
|
114928
|
-
return PULLFROG_DATA_DIR;
|
|
114929
|
-
}
|
|
114930
|
-
function bootstrapPullfrogDataDir() {
|
|
114931
|
-
const user = userInfo().username;
|
|
114932
|
-
let primaryGroup;
|
|
114933
|
-
try {
|
|
114934
|
-
primaryGroup = execFileSync4("id", ["-gn", user], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
114935
|
-
} catch {
|
|
114936
|
-
primaryGroup = user;
|
|
114937
|
-
}
|
|
114938
|
-
try {
|
|
114939
|
-
execFileSync4("sudo", ["-n", "mkdir", "-p", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
114940
|
-
execFileSync4("sudo", ["-n", "chown", `${user}:${primaryGroup}`, PULLFROG_DATA_DIR], {
|
|
114941
|
-
stdio: "pipe"
|
|
114942
|
-
});
|
|
114943
|
-
execFileSync4("sudo", ["-n", "chmod", "700", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
114944
|
-
} catch (err) {
|
|
114945
|
-
throw new Error(
|
|
114946
|
-
`failed to bootstrap ${PULLFROG_DATA_DIR} (required for codex auth in CI): ${err instanceof Error ? err.message : String(err)}. the MCP shell's mount-namespace sandbox cannot protect the auth file when it lives under $HOME, and silently falling back would contradict the "three independent layers" claim in wiki/codex-auth.md. passwordless sudo is required for codex auth on this runner \u2014 either configure it, or remove CODEX_AUTH_JSON from the run.`
|
|
114947
|
-
);
|
|
114948
|
-
}
|
|
114949
|
-
}
|
|
114950
|
-
|
|
114951
115643
|
// utils/worktree.ts
|
|
114952
115644
|
async function dirtyTrackedPaths(params = {}) {
|
|
114953
115645
|
const result = await spawn3({
|
|
@@ -115215,6 +115907,30 @@ function openAICompatibleProvider(model) {
|
|
|
115215
115907
|
}
|
|
115216
115908
|
};
|
|
115217
115909
|
}
|
|
115910
|
+
function azureProvider(model) {
|
|
115911
|
+
const prefix = `${AZURE_PROVIDER}/`;
|
|
115912
|
+
if (!model?.startsWith(prefix)) return {};
|
|
115913
|
+
const deployment = model.slice(prefix.length);
|
|
115914
|
+
return {
|
|
115915
|
+
[AZURE_PROVIDER]: {
|
|
115916
|
+
// always sent: opencode reads it as `Boolean(options?.useCompletionUrls)`,
|
|
115917
|
+
// so `false` and absent are the same, and the deep merge keeps the native
|
|
115918
|
+
// loader's `resourceName` either way.
|
|
115919
|
+
options: {
|
|
115920
|
+
useCompletionUrls: process.env[AZURE_USE_CHAT_COMPLETIONS_ENV]?.trim() === "true"
|
|
115921
|
+
},
|
|
115922
|
+
models: {
|
|
115923
|
+
[deployment]: {
|
|
115924
|
+
name: deployment,
|
|
115925
|
+
limit: {
|
|
115926
|
+
context: Number(process.env[AZURE_CONTEXT_ENV]),
|
|
115927
|
+
output: Number(process.env[AZURE_MAX_OUTPUT_ENV])
|
|
115928
|
+
}
|
|
115929
|
+
}
|
|
115930
|
+
}
|
|
115931
|
+
}
|
|
115932
|
+
};
|
|
115933
|
+
}
|
|
115218
115934
|
var KIMI_ENFORCERLESS_PROVIDERS = ["siliconflow", "together"];
|
|
115219
115935
|
function kimiOpenRouterProviderOverrides() {
|
|
115220
115936
|
return Object.fromEntries(
|
|
@@ -115306,7 +116022,8 @@ function buildSecurityConfig(ctx, model) {
|
|
|
115306
116022
|
// see opencodeShared.ts.
|
|
115307
116023
|
provider: {
|
|
115308
116024
|
openrouter: { models: kimiOpenRouterProviderOverrides() },
|
|
115309
|
-
...openAICompatibleProvider(model)
|
|
116025
|
+
...openAICompatibleProvider(model),
|
|
116026
|
+
...azureProvider(model)
|
|
115310
116027
|
}
|
|
115311
116028
|
};
|
|
115312
116029
|
if (model) {
|
|
@@ -115474,7 +116191,7 @@ function isModelOutput(ctx, part) {
|
|
|
115474
116191
|
}
|
|
115475
116192
|
async function dispatchEvent(ctx, event) {
|
|
115476
116193
|
if (event.type === "message.part.updated") {
|
|
115477
|
-
ctx.lastEventAt =
|
|
116194
|
+
ctx.lastEventAt = performance7.now();
|
|
115478
116195
|
if (isModelOutput(ctx, event.properties.part)) ctx.sawModelOutput = true;
|
|
115479
116196
|
await onPartUpdated(ctx, event.properties.part);
|
|
115480
116197
|
return;
|
|
@@ -115541,7 +116258,7 @@ async function onToolPart(ctx, part, label, isOrchestrator) {
|
|
|
115541
116258
|
if (toolName === "task" && status === "running" && isOrchestrator && !ctx.taskDispatchByCallID.has(toolId)) {
|
|
115542
116259
|
const input = part.state.input ?? {};
|
|
115543
116260
|
const dispatched = ctx.labeler.recordTaskDispatch(input);
|
|
115544
|
-
ctx.taskDispatchByCallID.set(toolId, { label: dispatched, startedAt:
|
|
116261
|
+
ctx.taskDispatchByCallID.set(toolId, { label: dispatched, startedAt: performance7.now() });
|
|
115545
116262
|
log2.info(
|
|
115546
116263
|
`\xBB dispatching subagent: ${dispatched}` + (input.subagent_type ? ` (subagent_type=${input.subagent_type})` : "")
|
|
115547
116264
|
);
|
|
@@ -115571,7 +116288,7 @@ function processTerminalToolPart(ctx, part, label, isOrchestrator) {
|
|
|
115571
116288
|
if (toolName === "task") {
|
|
115572
116289
|
const dispatch = ctx.taskDispatchByCallID.get(toolId);
|
|
115573
116290
|
if (dispatch) {
|
|
115574
|
-
const dur = ((
|
|
116291
|
+
const dur = ((performance7.now() - dispatch.startedAt) / 1e3).toFixed(1);
|
|
115575
116292
|
const outputStr = state.status === "completed" ? state.output : "";
|
|
115576
116293
|
const preview = typeof outputStr === "string" && outputStr.length > 120 ? `${outputStr.slice(0, 120)}\u2026` : outputStr;
|
|
115577
116294
|
log2.info(
|
|
@@ -115614,7 +116331,7 @@ function withLabel(label, message) {
|
|
|
115614
116331
|
return label === ORCHESTRATOR_LABEL ? message : formatWithLabel(label, message);
|
|
115615
116332
|
}
|
|
115616
116333
|
async function runPromptTurn(ctx, params) {
|
|
115617
|
-
const start =
|
|
116334
|
+
const start = performance7.now();
|
|
115618
116335
|
const turnStartMs = Date.now();
|
|
115619
116336
|
ctx.currentTurn = newTurn();
|
|
115620
116337
|
const turn = ctx.currentTurn;
|
|
@@ -115648,7 +116365,7 @@ async function runPromptTurn(ctx, params) {
|
|
|
115648
116365
|
} catch (err) {
|
|
115649
116366
|
networkError = err instanceof Error ? err.message : String(err);
|
|
115650
116367
|
}
|
|
115651
|
-
const durationMs =
|
|
116368
|
+
const durationMs = performance7.now() - start;
|
|
115652
116369
|
const aggregatedUsage = await aggregateTurnUsage(ctx, turnStartMs);
|
|
115653
116370
|
const usage = aggregatedUsage ?? buildUsage(turn, assistant);
|
|
115654
116371
|
const finalText = turn.finalText || extractTextFromParts(returnedParts) || "";
|
|
@@ -115802,7 +116519,7 @@ function startInnerActivityWatchdog(params) {
|
|
|
115802
116519
|
let fired = false;
|
|
115803
116520
|
const id = setInterval(() => {
|
|
115804
116521
|
if (fired) return;
|
|
115805
|
-
const idleMs =
|
|
116522
|
+
const idleMs = performance7.now() - params.ctx.lastEventAt;
|
|
115806
116523
|
const budgetMs = params.ctx.sawModelOutput ? params.timeoutMs : AGENT_FIRST_EVENT_TIMEOUT_MS;
|
|
115807
116524
|
if (idleMs <= budgetMs) return;
|
|
115808
116525
|
fired = true;
|
|
@@ -115841,12 +116558,12 @@ var opencode = agent({
|
|
|
115841
116558
|
const model = vertexModel ?? (isBedrockRoute ? `amazon-bedrock/${rawModel}` : rawModel);
|
|
115842
116559
|
const homeEnv = {
|
|
115843
116560
|
HOME: ctx.tmpdir,
|
|
115844
|
-
XDG_CONFIG_HOME:
|
|
116561
|
+
XDG_CONFIG_HOME: join8(ctx.tmpdir, ".config")
|
|
115845
116562
|
};
|
|
115846
|
-
const opencodePluginDir =
|
|
115847
|
-
|
|
115848
|
-
|
|
115849
|
-
|
|
116563
|
+
const opencodePluginDir = join8(homeEnv.XDG_CONFIG_HOME, "opencode", "plugin");
|
|
116564
|
+
mkdirSync7(opencodePluginDir, { recursive: true });
|
|
116565
|
+
writeFileSync7(
|
|
116566
|
+
join8(opencodePluginDir, PULLFROG_OPENCODE_GATE_PLUGIN_FILENAME),
|
|
115850
116567
|
buildOpencodeSubagentGateSource(ctx.subagentDeniedTools)
|
|
115851
116568
|
);
|
|
115852
116569
|
const agentBrowserVersion = getDevDependencyVersion("agent-browser");
|
|
@@ -115877,12 +116594,13 @@ var opencode = agent({
|
|
|
115877
116594
|
if (codexAuth) {
|
|
115878
116595
|
env2.XDG_DATA_HOME = codexAuth.xdgDataHome;
|
|
115879
116596
|
delete env2.OPENAI_API_KEY;
|
|
115880
|
-
|
|
116597
|
+
core3.saveState(
|
|
115881
116598
|
"codex_writeback",
|
|
115882
116599
|
JSON.stringify({
|
|
115883
116600
|
apiToken: ctx.apiToken,
|
|
115884
116601
|
authPath: codexAuth.authPath,
|
|
115885
|
-
originalRefresh: codexAuth.originalRefresh
|
|
116602
|
+
originalRefresh: codexAuth.originalRefresh,
|
|
116603
|
+
originalIdToken: codexAuth.originalIdToken
|
|
115886
116604
|
})
|
|
115887
116605
|
);
|
|
115888
116606
|
}
|
|
@@ -115936,7 +116654,7 @@ var opencode = agent({
|
|
|
115936
116654
|
onToolUse: ctx.onToolUse,
|
|
115937
116655
|
currentTurn: null,
|
|
115938
116656
|
eventCount: 0,
|
|
115939
|
-
lastEventAt:
|
|
116657
|
+
lastEventAt: performance7.now(),
|
|
115940
116658
|
sawModelOutput: false,
|
|
115941
116659
|
promptMessageID: void 0,
|
|
115942
116660
|
taskDispatchByCallID: /* @__PURE__ */ new Map(),
|
|
@@ -116046,7 +116764,7 @@ async function runTurnGuarded(ctx, fn2) {
|
|
|
116046
116764
|
}
|
|
116047
116765
|
|
|
116048
116766
|
// agents/index.ts
|
|
116049
|
-
var agents = { claude, opencode };
|
|
116767
|
+
var agents = { claude, codex, opencode };
|
|
116050
116768
|
|
|
116051
116769
|
// node_modules/.pnpm/@ark+util@0.56.0/node_modules/@ark/util/out/arrays.js
|
|
116052
116770
|
var liftArray = (data) => Array.isArray(data) ? data : [data];
|
|
@@ -136378,7 +137096,7 @@ var require_core$2 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
136378
137096
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
136379
137097
|
const id_1 = require_id2();
|
|
136380
137098
|
const ref_1 = require_ref2();
|
|
136381
|
-
const
|
|
137099
|
+
const core12 = [
|
|
136382
137100
|
"$schema",
|
|
136383
137101
|
"$id",
|
|
136384
137102
|
"$defs",
|
|
@@ -136388,7 +137106,7 @@ var require_core$2 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
136388
137106
|
id_1.default,
|
|
136389
137107
|
ref_1.default
|
|
136390
137108
|
];
|
|
136391
|
-
exports.default =
|
|
137109
|
+
exports.default = core12;
|
|
136392
137110
|
}));
|
|
136393
137111
|
var require_limitNumber2 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
136394
137112
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -138526,7 +139244,7 @@ var require_json_schema_2019_09 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
138526
139244
|
const metaSchema = require_schema$1();
|
|
138527
139245
|
const applicator = require_applicator$1();
|
|
138528
139246
|
const content = require_content$1();
|
|
138529
|
-
const
|
|
139247
|
+
const core12 = require_core$1();
|
|
138530
139248
|
const format2 = require_format3();
|
|
138531
139249
|
const metadata = require_meta_data$1();
|
|
138532
139250
|
const validation = require_validation$1();
|
|
@@ -138536,7 +139254,7 @@ var require_json_schema_2019_09 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
138536
139254
|
metaSchema,
|
|
138537
139255
|
applicator,
|
|
138538
139256
|
content,
|
|
138539
|
-
|
|
139257
|
+
core12,
|
|
138540
139258
|
with$data(this, format2),
|
|
138541
139259
|
metadata,
|
|
138542
139260
|
with$data(this, validation)
|
|
@@ -138976,7 +139694,7 @@ var require_json_schema_2020_12 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
138976
139694
|
const applicator = require_applicator2();
|
|
138977
139695
|
const unevaluated = require_unevaluated();
|
|
138978
139696
|
const content = require_content();
|
|
138979
|
-
const
|
|
139697
|
+
const core12 = require_core4();
|
|
138980
139698
|
const format2 = require_format_annotation();
|
|
138981
139699
|
const metadata = require_meta_data();
|
|
138982
139700
|
const validation = require_validation2();
|
|
@@ -138987,7 +139705,7 @@ var require_json_schema_2020_12 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
138987
139705
|
applicator,
|
|
138988
139706
|
unevaluated,
|
|
138989
139707
|
content,
|
|
138990
|
-
|
|
139708
|
+
core12,
|
|
138991
139709
|
with$data(this, format2),
|
|
138992
139710
|
metadata,
|
|
138993
139711
|
with$data(this, validation)
|
|
@@ -150429,7 +151147,7 @@ var require_core$22 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
150429
151147
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
150430
151148
|
const id_1 = require_id3();
|
|
150431
151149
|
const ref_1 = require_ref3();
|
|
150432
|
-
const
|
|
151150
|
+
const core12 = [
|
|
150433
151151
|
"$schema",
|
|
150434
151152
|
"$id",
|
|
150435
151153
|
"$defs",
|
|
@@ -150439,7 +151157,7 @@ var require_core$22 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
150439
151157
|
id_1.default,
|
|
150440
151158
|
ref_1.default
|
|
150441
151159
|
];
|
|
150442
|
-
exports.default =
|
|
151160
|
+
exports.default = core12;
|
|
150443
151161
|
}));
|
|
150444
151162
|
var require_limitNumber3 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
150445
151163
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -152577,7 +153295,7 @@ var require_json_schema_2019_092 = /* @__PURE__ */ __commonJSMin2(((exports) =>
|
|
|
152577
153295
|
const metaSchema = require_schema$12();
|
|
152578
153296
|
const applicator = require_applicator$12();
|
|
152579
153297
|
const content = require_content$12();
|
|
152580
|
-
const
|
|
153298
|
+
const core12 = require_core$12();
|
|
152581
153299
|
const format2 = require_format4();
|
|
152582
153300
|
const metadata = require_meta_data$12();
|
|
152583
153301
|
const validation = require_validation$12();
|
|
@@ -152587,7 +153305,7 @@ var require_json_schema_2019_092 = /* @__PURE__ */ __commonJSMin2(((exports) =>
|
|
|
152587
153305
|
metaSchema,
|
|
152588
153306
|
applicator,
|
|
152589
153307
|
content,
|
|
152590
|
-
|
|
153308
|
+
core12,
|
|
152591
153309
|
with$data(this, format2),
|
|
152592
153310
|
metadata,
|
|
152593
153311
|
with$data(this, validation)
|
|
@@ -153027,7 +153745,7 @@ var require_json_schema_2020_122 = /* @__PURE__ */ __commonJSMin2(((exports) =>
|
|
|
153027
153745
|
const applicator = require_applicator3();
|
|
153028
153746
|
const unevaluated = require_unevaluated2();
|
|
153029
153747
|
const content = require_content2();
|
|
153030
|
-
const
|
|
153748
|
+
const core12 = require_core5();
|
|
153031
153749
|
const format2 = require_format_annotation2();
|
|
153032
153750
|
const metadata = require_meta_data2();
|
|
153033
153751
|
const validation = require_validation3();
|
|
@@ -153038,7 +153756,7 @@ var require_json_schema_2020_122 = /* @__PURE__ */ __commonJSMin2(((exports) =>
|
|
|
153038
153756
|
applicator,
|
|
153039
153757
|
unevaluated,
|
|
153040
153758
|
content,
|
|
153041
|
-
|
|
153759
|
+
core12,
|
|
153042
153760
|
with$data(this, format2),
|
|
153043
153761
|
metadata,
|
|
153044
153762
|
with$data(this, validation)
|
|
@@ -172999,123 +173717,8 @@ var pbkdf2Async = promisify(pbkdf2);
|
|
|
172999
173717
|
|
|
173000
173718
|
// utils/browser.ts
|
|
173001
173719
|
import { execFileSync as execFileSync5, spawnSync as spawnSync4 } from "node:child_process";
|
|
173002
|
-
import { existsSync as
|
|
173720
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
173003
173721
|
import { dirname as dirname2 } from "node:path";
|
|
173004
|
-
|
|
173005
|
-
// utils/secrets.ts
|
|
173006
|
-
var SENSITIVE_PATTERNS = [
|
|
173007
|
-
/_KEY$/i,
|
|
173008
|
-
/_SECRET$/i,
|
|
173009
|
-
/_TOKEN$/i,
|
|
173010
|
-
/_PASSWORD$/i,
|
|
173011
|
-
/_CREDENTIAL$/i
|
|
173012
|
-
];
|
|
173013
|
-
function isSensitiveEnvName(key) {
|
|
173014
|
-
return SENSITIVE_PATTERNS.some((p) => p.test(key));
|
|
173015
|
-
}
|
|
173016
|
-
var SAFE_ENV_PREFIXES = ["GITHUB_", "RUNNER_", "JAVA_HOME_", "GOROOT_"];
|
|
173017
|
-
var SAFE_ENV_NAMES = /* @__PURE__ */ new Set([
|
|
173018
|
-
// system
|
|
173019
|
-
"CI",
|
|
173020
|
-
"HOME",
|
|
173021
|
-
"LANG",
|
|
173022
|
-
"LOGNAME",
|
|
173023
|
-
"PATH",
|
|
173024
|
-
"SHELL",
|
|
173025
|
-
"SHLVL",
|
|
173026
|
-
"TERM",
|
|
173027
|
-
"TMPDIR",
|
|
173028
|
-
"TZ",
|
|
173029
|
-
"USER",
|
|
173030
|
-
"XDG_CONFIG_HOME",
|
|
173031
|
-
"XDG_RUNTIME_DIR",
|
|
173032
|
-
"DEBIAN_FRONTEND",
|
|
173033
|
-
// runner image toolchain
|
|
173034
|
-
"ACCEPT_EULA",
|
|
173035
|
-
"AGENT_TOOLSDIRECTORY",
|
|
173036
|
-
"ANDROID_HOME",
|
|
173037
|
-
"ANDROID_NDK",
|
|
173038
|
-
"ANDROID_NDK_HOME",
|
|
173039
|
-
"ANDROID_NDK_LATEST_HOME",
|
|
173040
|
-
"ANDROID_NDK_ROOT",
|
|
173041
|
-
"ANDROID_SDK_ROOT",
|
|
173042
|
-
"ANT_HOME",
|
|
173043
|
-
"AZURE_EXTENSION_DIR",
|
|
173044
|
-
"BOOTSTRAP_HASKELL_NONINTERACTIVE",
|
|
173045
|
-
"CHROME_BIN",
|
|
173046
|
-
"CHROMEWEBDRIVER",
|
|
173047
|
-
"CONDA",
|
|
173048
|
-
"DOTNET_MULTILEVEL_LOOKUP",
|
|
173049
|
-
"DOTNET_NOLOGO",
|
|
173050
|
-
"DOTNET_SKIP_FIRST_TIME_EXPERIENCE",
|
|
173051
|
-
"EDGEWEBDRIVER",
|
|
173052
|
-
"GECKOWEBDRIVER",
|
|
173053
|
-
"GHCUP_INSTALL_BASE_PREFIX",
|
|
173054
|
-
"GRADLE_HOME",
|
|
173055
|
-
"JAVA_HOME",
|
|
173056
|
-
"HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS",
|
|
173057
|
-
"HOMEBREW_NO_AUTO_UPDATE",
|
|
173058
|
-
"ImageOS",
|
|
173059
|
-
"ImageVersion",
|
|
173060
|
-
"NVM_DIR",
|
|
173061
|
-
"PIPX_BIN_DIR",
|
|
173062
|
-
"PIPX_HOME",
|
|
173063
|
-
"PSModulePath",
|
|
173064
|
-
"SELENIUM_JAR_PATH",
|
|
173065
|
-
"SGX_AESM_ADDR",
|
|
173066
|
-
"SWIFT_PATH",
|
|
173067
|
-
"VCPKG_INSTALLATION_ROOT"
|
|
173068
|
-
]);
|
|
173069
|
-
var _userAllowlist = null;
|
|
173070
|
-
function setEnvAllowlist(raw2) {
|
|
173071
|
-
const names = raw2.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
173072
|
-
_userAllowlist = new Set(names);
|
|
173073
|
-
}
|
|
173074
|
-
function isSafeEnvVar(key) {
|
|
173075
|
-
if (SAFE_ENV_NAMES.has(key)) return true;
|
|
173076
|
-
return SAFE_ENV_PREFIXES.some((p) => key.startsWith(p));
|
|
173077
|
-
}
|
|
173078
|
-
var WORKFLOW_COMMAND_ENV_NAMES = [
|
|
173079
|
-
"GITHUB_ENV",
|
|
173080
|
-
"GITHUB_PATH",
|
|
173081
|
-
"GITHUB_OUTPUT",
|
|
173082
|
-
"GITHUB_STATE",
|
|
173083
|
-
"GITHUB_STEP_SUMMARY",
|
|
173084
|
-
// dropping the five paths above but keeping RUNNER_TEMP would be theatre:
|
|
173085
|
-
// the file-command files live in `$RUNNER_TEMP/_runner_file_commands/`, so the
|
|
173086
|
-
// directory is one `ls` away. nothing in the install path reads it (only our
|
|
173087
|
-
// own leak-surface wipe in `setup.ts`, which runs in the parent), and package
|
|
173088
|
-
// managers use TMPDIR.
|
|
173089
|
-
"RUNNER_TEMP"
|
|
173090
|
-
];
|
|
173091
|
-
function filterEnvForUntrustedCode() {
|
|
173092
|
-
const env2 = filterEnv();
|
|
173093
|
-
for (const name of WORKFLOW_COMMAND_ENV_NAMES) delete env2[name];
|
|
173094
|
-
return env2;
|
|
173095
|
-
}
|
|
173096
|
-
function filterEnv() {
|
|
173097
|
-
const filtered = {};
|
|
173098
|
-
for (const [key, value2] of Object.entries(process.env)) {
|
|
173099
|
-
if (value2 === void 0) continue;
|
|
173100
|
-
const userAllowed = _userAllowlist?.has(key) ?? false;
|
|
173101
|
-
if (isSensitiveEnvName(key) && !userAllowed) continue;
|
|
173102
|
-
if (isSafeEnvVar(key) || userAllowed) {
|
|
173103
|
-
filtered[key] = value2;
|
|
173104
|
-
}
|
|
173105
|
-
}
|
|
173106
|
-
return filtered;
|
|
173107
|
-
}
|
|
173108
|
-
function resolveEnv(mode) {
|
|
173109
|
-
if (mode === "inherit") {
|
|
173110
|
-
return process.env;
|
|
173111
|
-
}
|
|
173112
|
-
if (mode === "restricted" || mode === void 0) {
|
|
173113
|
-
return filterEnv();
|
|
173114
|
-
}
|
|
173115
|
-
return { ...filterEnv(), ...mode };
|
|
173116
|
-
}
|
|
173117
|
-
|
|
173118
|
-
// utils/browser.ts
|
|
173119
173722
|
var CHROME_PATHS = ["/usr/bin/google-chrome-stable"];
|
|
173120
173723
|
var systemChromePath;
|
|
173121
173724
|
function findSystemChromePath() {
|
|
@@ -173123,7 +173726,7 @@ function findSystemChromePath() {
|
|
|
173123
173726
|
return systemChromePath || void 0;
|
|
173124
173727
|
}
|
|
173125
173728
|
for (const p of CHROME_PATHS) {
|
|
173126
|
-
if (
|
|
173729
|
+
if (existsSync5(p)) {
|
|
173127
173730
|
systemChromePath = p;
|
|
173128
173731
|
log2.info(`found system chrome: ${p}`);
|
|
173129
173732
|
return p;
|
|
@@ -173207,8 +173810,8 @@ function closeBrowserDaemon(toolState) {
|
|
|
173207
173810
|
|
|
173208
173811
|
// mcp/checkout.ts
|
|
173209
173812
|
import { createHash as createHash2 } from "node:crypto";
|
|
173210
|
-
import { statSync, unlinkSync as unlinkSync3, writeFileSync as
|
|
173211
|
-
import { join as
|
|
173813
|
+
import { statSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "node:fs";
|
|
173814
|
+
import { join as join15 } from "node:path";
|
|
173212
173815
|
|
|
173213
173816
|
// node_modules/.pnpm/@ark+schema@0.56.0/node_modules/@ark/schema/out/shared/errors.js
|
|
173214
173817
|
var ArkError = class _ArkError extends CastableBase {
|
|
@@ -180680,8 +181283,8 @@ function ensureRepoState(toolState, init) {
|
|
|
180680
181283
|
|
|
180681
181284
|
// utils/changeImpact.ts
|
|
180682
181285
|
import { spawn as spawn4 } from "node:child_process";
|
|
180683
|
-
import { writeFileSync as
|
|
180684
|
-
import { join as
|
|
181286
|
+
import { writeFileSync as writeFileSync8 } from "node:fs";
|
|
181287
|
+
import { join as join9 } from "node:path";
|
|
180685
181288
|
var MAX_CANDIDATES = 24;
|
|
180686
181289
|
var MAX_ATOM_LENGTH = 128;
|
|
180687
181290
|
var MAX_ATOMS = 12;
|
|
@@ -181028,8 +181631,8 @@ async function createChangeImpactArtifact(ctx, params) {
|
|
|
181028
181631
|
headSha: params.headSha,
|
|
181029
181632
|
lookupError: lookup2.error
|
|
181030
181633
|
});
|
|
181031
|
-
const path4 =
|
|
181032
|
-
|
|
181634
|
+
const path4 = join9(ctx.tmpdir, `pr-${params.pullNumber}-${params.headSha.slice(0, 7)}-impact.md`);
|
|
181635
|
+
writeFileSync8(path4, artifact.content);
|
|
181033
181636
|
return {
|
|
181034
181637
|
path: path4,
|
|
181035
181638
|
candidateCount: candidates.selected.length,
|
|
@@ -181281,8 +181884,8 @@ function readNumber(params) {
|
|
|
181281
181884
|
// utils/gitAuth.ts
|
|
181282
181885
|
import { execSync } from "node:child_process";
|
|
181283
181886
|
import { createHash } from "node:crypto";
|
|
181284
|
-
import { readFileSync as
|
|
181285
|
-
import { join as
|
|
181887
|
+
import { readFileSync as readFileSync4, realpathSync, unlinkSync } from "node:fs";
|
|
181888
|
+
import { join as join10 } from "node:path";
|
|
181286
181889
|
|
|
181287
181890
|
// utils/shell.ts
|
|
181288
181891
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
@@ -181343,7 +181946,7 @@ var TRANSIENT_AUTH_PATTERNS = [
|
|
|
181343
181946
|
];
|
|
181344
181947
|
var gitBinary;
|
|
181345
181948
|
function hashFile(path4) {
|
|
181346
|
-
return createHash("sha256").update(
|
|
181949
|
+
return createHash("sha256").update(readFileSync4(path4)).digest("hex");
|
|
181347
181950
|
}
|
|
181348
181951
|
function resolveGit() {
|
|
181349
181952
|
const whichPath = execSync("which git", { encoding: "utf-8" }).trim();
|
|
@@ -181372,7 +181975,7 @@ function resolveHooksDir(cwd, gitPath) {
|
|
|
181372
181975
|
cwd,
|
|
181373
181976
|
log: false
|
|
181374
181977
|
}).trim();
|
|
181375
|
-
const hooksDir =
|
|
181978
|
+
const hooksDir = join10(commonDir, "hooks");
|
|
181376
181979
|
hooksDirCache.set(cwd, hooksDir);
|
|
181377
181980
|
return hooksDir;
|
|
181378
181981
|
}
|
|
@@ -181679,7 +182282,7 @@ function postProcessRangeDiff(raw2, contextLines = 3) {
|
|
|
181679
182282
|
}
|
|
181680
182283
|
|
|
181681
182284
|
// yes/index.ts
|
|
181682
|
-
import { performance as
|
|
182285
|
+
import { performance as performance8 } from "node:perf_hooks";
|
|
181683
182286
|
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
181684
182287
|
|
|
181685
182288
|
// node_modules/.pnpm/lru-cache@11.5.2/node_modules/lru-cache/dist/esm/node/index.min.js
|
|
@@ -182394,14 +182997,14 @@ function _op(fn2, options) {
|
|
|
182394
182997
|
`failed to create cache key${namePrefix ? ` for ${options.name}` : ""}: ${errorMessage}`
|
|
182395
182998
|
);
|
|
182396
182999
|
}
|
|
182397
|
-
const startTime =
|
|
183000
|
+
const startTime = performance8.now();
|
|
182398
183001
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
182399
183002
|
log3.debug(`${namePrefix}[${timestamp}] cache lookup started`, { key });
|
|
182400
183003
|
if (shouldCache && lruCache) {
|
|
182401
183004
|
const cached4 = lruCache.get(key);
|
|
182402
183005
|
if (cached4 !== void 0) {
|
|
182403
183006
|
if (keyMap?.get(key) === void 0) keyMap?.set(key, input);
|
|
182404
|
-
const runtime =
|
|
183007
|
+
const runtime = performance8.now() - startTime;
|
|
182405
183008
|
log3.debug(`${namePrefix}[${timestamp}] cache hit (from lru)`, {
|
|
182406
183009
|
key,
|
|
182407
183010
|
runtime: `${Math.round(runtime)}ms`
|
|
@@ -182420,12 +183023,12 @@ function _op(fn2, options) {
|
|
|
182420
183023
|
defaultCacheMiss(key);
|
|
182421
183024
|
const retries = options.retries ?? [];
|
|
182422
183025
|
let lastError;
|
|
182423
|
-
const execStartTime =
|
|
183026
|
+
const execStartTime = performance8.now();
|
|
182424
183027
|
const promise2 = (async () => {
|
|
182425
183028
|
for (let attempt = 0; attempt <= retries.length; attempt++) {
|
|
182426
183029
|
try {
|
|
182427
183030
|
const result = acceptsCtx ? await fn2(input, ctx) : await fn2(input);
|
|
182428
|
-
const execRuntime2 =
|
|
183031
|
+
const execRuntime2 = performance8.now() - execStartTime;
|
|
182429
183032
|
const skip = options.skipCache ? options.skipCache(result) : false;
|
|
182430
183033
|
if (shouldCache && lruCache && result !== null && result !== void 0 && !skip) {
|
|
182431
183034
|
lruCache.set(key, result);
|
|
@@ -182478,7 +183081,7 @@ function _op(fn2, options) {
|
|
|
182478
183081
|
}
|
|
182479
183082
|
}
|
|
182480
183083
|
}
|
|
182481
|
-
const execRuntime =
|
|
183084
|
+
const execRuntime = performance8.now() - execStartTime;
|
|
182482
183085
|
log3.debug(`${namePrefix}[${timestamp}] function failed after all retries`, {
|
|
182483
183086
|
key,
|
|
182484
183087
|
runtime: `${Math.round(execRuntime)}ms`,
|
|
@@ -182543,13 +183146,13 @@ function _op(fn2, options) {
|
|
|
182543
183146
|
|
|
182544
183147
|
// mcp/git.ts
|
|
182545
183148
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
182546
|
-
import { writeFileSync as
|
|
182547
|
-
import { join as
|
|
183149
|
+
import { writeFileSync as writeFileSync9 } from "node:fs";
|
|
183150
|
+
import { join as join13 } from "node:path";
|
|
182548
183151
|
|
|
182549
183152
|
// utils/apiCommit.ts
|
|
182550
183153
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
182551
183154
|
import { lstat, readlink } from "node:fs/promises";
|
|
182552
|
-
import { join as
|
|
183155
|
+
import { join as join11 } from "node:path";
|
|
182553
183156
|
var GITHUB_API = "https://api.github.com";
|
|
182554
183157
|
var MAX_BLOB_BYTES = 30 * 1024 * 1024;
|
|
182555
183158
|
var BLOB_UPLOAD_CONCURRENCY = 8;
|
|
@@ -182614,7 +183217,7 @@ async function assertApiCommittable(files) {
|
|
|
182614
183217
|
const root = getRepoRoot();
|
|
182615
183218
|
const attrs = $(
|
|
182616
183219
|
"git",
|
|
182617
|
-
["check-attr", "filter", "-z", "--", ...present.map((p) =>
|
|
183220
|
+
["check-attr", "filter", "-z", "--", ...present.map((p) => join11(root, p))],
|
|
182618
183221
|
{ log: false }
|
|
182619
183222
|
);
|
|
182620
183223
|
const parts = attrs.split("\0");
|
|
@@ -182626,7 +183229,7 @@ async function assertApiCommittable(files) {
|
|
|
182626
183229
|
}
|
|
182627
183230
|
}
|
|
182628
183231
|
for (const path4 of present) {
|
|
182629
|
-
const stat = await lstat(
|
|
183232
|
+
const stat = await lstat(join11(root, path4));
|
|
182630
183233
|
if (stat.isDirectory()) {
|
|
182631
183234
|
throw new Error(
|
|
182632
183235
|
`'${path4}' is a directory (nested repository or submodule?) \u2014 signed commits only support files and symlinks.`
|
|
@@ -182635,7 +183238,7 @@ async function assertApiCommittable(files) {
|
|
|
182635
183238
|
}
|
|
182636
183239
|
}
|
|
182637
183240
|
async function createBlobEntry(params) {
|
|
182638
|
-
const absPath =
|
|
183241
|
+
const absPath = join11(params.repoRoot, params.path);
|
|
182639
183242
|
const stat = await lstat(absPath);
|
|
182640
183243
|
if (stat.size > MAX_BLOB_BYTES) {
|
|
182641
183244
|
throw new Error(
|
|
@@ -182812,10 +183415,10 @@ this usually means your local branch has commits that were never pushed \u2014 s
|
|
|
182812
183415
|
}
|
|
182813
183416
|
|
|
182814
183417
|
// utils/github.ts
|
|
182815
|
-
var
|
|
183418
|
+
var core4 = __toESM(require_core(), 1);
|
|
182816
183419
|
import { createSign } from "node:crypto";
|
|
182817
183420
|
import { rename, writeFile } from "node:fs/promises";
|
|
182818
|
-
import { dirname as dirname3, join as
|
|
183421
|
+
import { dirname as dirname3, join as join12 } from "node:path";
|
|
182819
183422
|
|
|
182820
183423
|
// node_modules/.pnpm/@octokit+plugin-throttling@11.0.5_@octokit+core@7.0.7/node_modules/@octokit/plugin-throttling/dist-bundle/index.js
|
|
182821
183424
|
var import_light = __toESM(require_light(), 1);
|
|
@@ -187013,7 +187616,7 @@ async function fetchIdTokenFromStash(creds) {
|
|
|
187013
187616
|
throw new Error("ID token response has no value field");
|
|
187014
187617
|
}
|
|
187015
187618
|
if (isGitHubActions) {
|
|
187016
|
-
|
|
187619
|
+
core4.setSecret(body.value);
|
|
187017
187620
|
}
|
|
187018
187621
|
return body.value;
|
|
187019
187622
|
}
|
|
@@ -187026,7 +187629,7 @@ function translateIdTokenError(error52) {
|
|
|
187026
187629
|
var mintIdToken = op(
|
|
187027
187630
|
async () => {
|
|
187028
187631
|
try {
|
|
187029
|
-
return await
|
|
187632
|
+
return await core4.getIDToken(OIDC_AUDIENCE);
|
|
187030
187633
|
} catch (error52) {
|
|
187031
187634
|
throw translateIdTokenError(error52);
|
|
187032
187635
|
}
|
|
@@ -187235,7 +187838,7 @@ function getGitHubUsageSummary() {
|
|
|
187235
187838
|
}
|
|
187236
187839
|
async function writeGitHubUsageSummaryToFile(path4) {
|
|
187237
187840
|
const summary2 = getGitHubUsageSummary();
|
|
187238
|
-
const tmpPath =
|
|
187841
|
+
const tmpPath = join12(dirname3(path4), `.usage-summary-${process.pid}.tmp`);
|
|
187239
187842
|
await writeFile(tmpPath, JSON.stringify(summary2));
|
|
187240
187843
|
await rename(tmpPath, path4);
|
|
187241
187844
|
}
|
|
@@ -188387,8 +188990,8 @@ function countAhead(head, base, cwd) {
|
|
|
188387
188990
|
function spillGitOutput(params) {
|
|
188388
188991
|
const tempDir = process.env.PULLFROG_TEMP_DIR;
|
|
188389
188992
|
if (!tempDir) throw new Error("PULLFROG_TEMP_DIR not set");
|
|
188390
|
-
const outputPath =
|
|
188391
|
-
|
|
188993
|
+
const outputPath = join13(tempDir, `git-${params.command}-${randomUUID3().slice(0, 8)}.txt`);
|
|
188994
|
+
writeFileSync9(outputPath, params.output);
|
|
188392
188995
|
const previewByLines = params.output.split("\n").slice(0, OVERFLOW_PREVIEW_LINES).join("\n");
|
|
188393
188996
|
const preview = previewByLines.length <= OVERFLOW_PREVIEW_MAX_CHARS ? previewByLines : `${previewByLines.slice(0, OVERFLOW_PREVIEW_MAX_CHARS)}\u2026`;
|
|
188394
188997
|
log2.info(
|
|
@@ -189902,9 +190505,9 @@ async function reportReviewNodeId(ctx, params) {
|
|
|
189902
190505
|
import { execFileSync as execFileSync7, execSync as execSync2 } from "node:child_process";
|
|
189903
190506
|
import { mkdtempSync as mkdtempSync2, readdirSync, realpathSync as realpathSync2, unlinkSync as unlinkSync2 } from "node:fs";
|
|
189904
190507
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
189905
|
-
import { join as
|
|
190508
|
+
import { join as join14 } from "node:path";
|
|
189906
190509
|
function createTempDirectory() {
|
|
189907
|
-
const sharedTempDir = mkdtempSync2(
|
|
190510
|
+
const sharedTempDir = mkdtempSync2(join14(tmpdir3(), "pullfrog-"));
|
|
189908
190511
|
process.env.PULLFROG_TEMP_DIR = sharedTempDir;
|
|
189909
190512
|
log2.info(`\xBB created temp dir at ${sharedTempDir}`);
|
|
189910
190513
|
return sharedTempDir;
|
|
@@ -189949,13 +190552,13 @@ function wipeRunnerLeakSurface() {
|
|
|
189949
190552
|
return [];
|
|
189950
190553
|
}
|
|
189951
190554
|
};
|
|
189952
|
-
const fileCommandsDir =
|
|
190555
|
+
const fileCommandsDir = join14(runnerTemp, "_runner_file_commands");
|
|
189953
190556
|
for (const entry of listDir(fileCommandsDir)) {
|
|
189954
|
-
tryUnlink(
|
|
190557
|
+
tryUnlink(join14(fileCommandsDir, entry));
|
|
189955
190558
|
}
|
|
189956
190559
|
for (const entry of listDir(runnerTemp)) {
|
|
189957
190560
|
if (entry.endsWith(".sh") || /^git-credentials-.*\.config$/.test(entry)) {
|
|
189958
|
-
tryUnlink(
|
|
190561
|
+
tryUnlink(join14(runnerTemp, entry));
|
|
189959
190562
|
}
|
|
189960
190563
|
}
|
|
189961
190564
|
if (wiped.length > 0) {
|
|
@@ -190505,11 +191108,11 @@ function CheckoutPrTool(ctx) {
|
|
|
190505
191108
|
headSha: checkoutSha
|
|
190506
191109
|
});
|
|
190507
191110
|
if (incremental.status === "ok") {
|
|
190508
|
-
incrementalDiffPath =
|
|
191111
|
+
incrementalDiffPath = join15(
|
|
190509
191112
|
tempDir,
|
|
190510
191113
|
`pr-${pull_number}-${beforeShort}-${headShort}-incremental.diff`
|
|
190511
191114
|
);
|
|
190512
|
-
|
|
191115
|
+
writeFileSync10(incrementalDiffPath, incremental.diff);
|
|
190513
191116
|
log2.info(
|
|
190514
191117
|
`\xBB incremental diff computed (${incremental.diff.length} bytes) \u2192 ${incrementalDiffPath}`
|
|
190515
191118
|
);
|
|
@@ -190522,8 +191125,8 @@ function CheckoutPrTool(ctx) {
|
|
|
190522
191125
|
const diffPreview = formatResult.content.split("\n").slice(0, 100).join("\n");
|
|
190523
191126
|
log2.debug(`formatted diff preview (first 100 lines):
|
|
190524
191127
|
${diffPreview}`);
|
|
190525
|
-
const diffPath =
|
|
190526
|
-
|
|
191128
|
+
const diffPath = join15(tempDir, `pr-${pull_number}-${headShort}.diff`);
|
|
191129
|
+
writeFileSync10(diffPath, formatResult.content);
|
|
190527
191130
|
log2.debug(`wrote diff to ${diffPath} (${formatResult.content.length} bytes)`);
|
|
190528
191131
|
primary.diffCoverage = createDiffCoverageState({
|
|
190529
191132
|
diffPath,
|
|
@@ -190680,8 +191283,8 @@ ${dirty}`
|
|
|
190680
191283
|
}
|
|
190681
191284
|
|
|
190682
191285
|
// mcp/checkSuite.ts
|
|
190683
|
-
import { mkdirSync as
|
|
190684
|
-
import { join as
|
|
191286
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync11 } from "node:fs";
|
|
191287
|
+
import { join as join16 } from "node:path";
|
|
190685
191288
|
var GetCheckSuiteLogs = type({
|
|
190686
191289
|
check_suite_id: type.number.describe("the id from check_suite.id")
|
|
190687
191290
|
});
|
|
@@ -190777,8 +191380,8 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
190777
191380
|
if (!tempDir) {
|
|
190778
191381
|
throw new Error("PULLFROG_TEMP_DIR not set");
|
|
190779
191382
|
}
|
|
190780
|
-
const logsDir =
|
|
190781
|
-
|
|
191383
|
+
const logsDir = join16(tempDir, "ci-logs");
|
|
191384
|
+
mkdirSync8(logsDir, { recursive: true });
|
|
190782
191385
|
const jobResults = [];
|
|
190783
191386
|
for (const run4 of failedRuns) {
|
|
190784
191387
|
const jobs = await ctx.octokit.paginate(ctx.octokit.rest.actions.listJobsForWorkflowRun, {
|
|
@@ -190804,8 +191407,8 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
190804
191407
|
);
|
|
190805
191408
|
}
|
|
190806
191409
|
const logsText = await logsResult.text();
|
|
190807
|
-
const logPath =
|
|
190808
|
-
|
|
191410
|
+
const logPath = join16(logsDir, `job-${job.id}.log`);
|
|
191411
|
+
writeFileSync11(logPath, logsText);
|
|
190809
191412
|
const analysis = analyzeLog(logsText, 80);
|
|
190810
191413
|
const failedSteps = job.steps?.filter((s) => s.conclusion === "failure").map((s) => `Step ${s.number}: ${s.name}`) ?? [];
|
|
190811
191414
|
jobResults.push({
|
|
@@ -190853,8 +191456,8 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
190853
191456
|
}
|
|
190854
191457
|
|
|
190855
191458
|
// mcp/commitInfo.ts
|
|
190856
|
-
import { writeFileSync as
|
|
190857
|
-
import { join as
|
|
191459
|
+
import { writeFileSync as writeFileSync12 } from "node:fs";
|
|
191460
|
+
import { join as join17 } from "node:path";
|
|
190858
191461
|
var CommitInfo = type({
|
|
190859
191462
|
sha: type.string.describe("the commit SHA (full or abbreviated) to fetch")
|
|
190860
191463
|
});
|
|
@@ -190878,8 +191481,8 @@ function CommitInfoTool(ctx) {
|
|
|
190878
191481
|
"PULLFROG_TEMP_DIR not set - get_commit_info must run in pullfrog action context"
|
|
190879
191482
|
);
|
|
190880
191483
|
}
|
|
190881
|
-
const diffFile =
|
|
190882
|
-
|
|
191484
|
+
const diffFile = join17(tempDir, `commit-${sha.slice(0, 7)}.diff`);
|
|
191485
|
+
writeFileSync12(diffFile, formatResult.content);
|
|
190883
191486
|
log2.debug(`wrote commit diff to ${diffFile} (${formatResult.content.length} bytes)`);
|
|
190884
191487
|
return {
|
|
190885
191488
|
sha: data.sha,
|
|
@@ -191012,17 +191615,17 @@ function ReopenCurrentTool(ctx) {
|
|
|
191012
191615
|
}
|
|
191013
191616
|
|
|
191014
191617
|
// prep/index.ts
|
|
191015
|
-
import { performance as
|
|
191618
|
+
import { performance as performance9 } from "node:perf_hooks";
|
|
191016
191619
|
|
|
191017
191620
|
// prep/installNodeDependencies.ts
|
|
191018
|
-
import { existsSync as
|
|
191019
|
-
import { join as
|
|
191621
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
191622
|
+
import { join as join19 } from "node:path";
|
|
191020
191623
|
|
|
191021
191624
|
// utils/packageManager.ts
|
|
191022
191625
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
191023
|
-
import { existsSync as
|
|
191626
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
191024
191627
|
import { mkdir, readFile as readFile2 } from "node:fs/promises";
|
|
191025
|
-
import { delimiter, join as
|
|
191628
|
+
import { delimiter, join as join18 } from "node:path";
|
|
191026
191629
|
var SUPPORTED_NAMES = ["npm", "pnpm", "yarn", "bun"];
|
|
191027
191630
|
var COREPACK_MANAGED = ["pnpm", "yarn"];
|
|
191028
191631
|
function isSupported(name) {
|
|
@@ -191060,8 +191663,8 @@ function parseDevEnginesField(field) {
|
|
|
191060
191663
|
};
|
|
191061
191664
|
}
|
|
191062
191665
|
async function resolvePackageManagerSpec(cwd) {
|
|
191063
|
-
const pkgPath =
|
|
191064
|
-
if (!
|
|
191666
|
+
const pkgPath = join18(cwd, "package.json");
|
|
191667
|
+
if (!existsSync6(pkgPath)) return null;
|
|
191065
191668
|
let pkg;
|
|
191066
191669
|
try {
|
|
191067
191670
|
pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
|
|
@@ -191119,7 +191722,7 @@ async function currentVersion(name) {
|
|
|
191119
191722
|
return result.stdout.trim();
|
|
191120
191723
|
}
|
|
191121
191724
|
function packageManagerBinDir(tmpdir4) {
|
|
191122
|
-
return
|
|
191725
|
+
return join18(tmpdir4, "pm-bin");
|
|
191123
191726
|
}
|
|
191124
191727
|
async function ensurePackageManager(params) {
|
|
191125
191728
|
const spec = params.spec;
|
|
@@ -191182,7 +191785,7 @@ async function installFallback(name, installSpec) {
|
|
|
191182
191785
|
});
|
|
191183
191786
|
if (result.exitCode !== 0) return result.stderr || `failed to install ${name}`;
|
|
191184
191787
|
if (name === "deno") {
|
|
191185
|
-
const denoPath =
|
|
191788
|
+
const denoPath = join18(process.env.HOME || "", ".deno", "bin");
|
|
191186
191789
|
process.env.PATH = `${denoPath}:${process.env.PATH}`;
|
|
191187
191790
|
}
|
|
191188
191791
|
log2.info(`\xBB installed ${name}`);
|
|
@@ -191215,8 +191818,8 @@ async function isCommandAvailable2(command) {
|
|
|
191215
191818
|
var installNodeDependencies = {
|
|
191216
191819
|
name: "installNodeDependencies",
|
|
191217
191820
|
shouldRun: () => {
|
|
191218
|
-
const packageJsonPath =
|
|
191219
|
-
return
|
|
191821
|
+
const packageJsonPath = join19(process.cwd(), "package.json");
|
|
191822
|
+
return existsSync7(packageJsonPath);
|
|
191220
191823
|
},
|
|
191221
191824
|
run: async (options) => {
|
|
191222
191825
|
const declared = await resolvePackageManagerSpec(process.cwd());
|
|
@@ -191310,14 +191913,14 @@ ${errorMessage}`]
|
|
|
191310
191913
|
};
|
|
191311
191914
|
|
|
191312
191915
|
// prep/installPythonDependencies.ts
|
|
191313
|
-
import { existsSync as
|
|
191314
|
-
import { join as
|
|
191916
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "node:fs";
|
|
191917
|
+
import { join as join20 } from "node:path";
|
|
191315
191918
|
function declaresBuildSystem(path4) {
|
|
191316
|
-
return /^\s*\[\s*build-system\s*\]/m.test(
|
|
191919
|
+
return /^\s*\[\s*build-system\s*\]/m.test(readFileSync5(path4, "utf8"));
|
|
191317
191920
|
}
|
|
191318
191921
|
function configApplies(config3, cwd) {
|
|
191319
|
-
const path4 =
|
|
191320
|
-
return
|
|
191922
|
+
const path4 = join20(cwd, config3.file);
|
|
191923
|
+
return existsSync8(path4) && (config3.applies?.(path4) ?? true);
|
|
191321
191924
|
}
|
|
191322
191925
|
var PYTHON_CONFIGS = [
|
|
191323
191926
|
{
|
|
@@ -191471,7 +192074,7 @@ var installPythonDependencies = {
|
|
|
191471
192074
|
var prepSteps = [installNodeDependencies, installPythonDependencies];
|
|
191472
192075
|
async function runPrepPhase(options) {
|
|
191473
192076
|
log2.debug("\xBB starting prep phase...");
|
|
191474
|
-
const startTime =
|
|
192077
|
+
const startTime = performance9.now();
|
|
191475
192078
|
const results = [];
|
|
191476
192079
|
const preDirty = await dirtyTrackedPaths();
|
|
191477
192080
|
try {
|
|
@@ -191493,7 +192096,7 @@ async function runPrepPhase(options) {
|
|
|
191493
192096
|
} finally {
|
|
191494
192097
|
await restoreDirtiedSince({ before: preDirty, actor: "prep" });
|
|
191495
192098
|
}
|
|
191496
|
-
const totalDurationMs =
|
|
192099
|
+
const totalDurationMs = performance9.now() - startTime;
|
|
191497
192100
|
log2.debug(`\xBB prep phase completed (${Math.round(totalDurationMs)}ms)`);
|
|
191498
192101
|
return results;
|
|
191499
192102
|
}
|
|
@@ -191638,15 +192241,15 @@ function AwaitDependencyInstallationTool(ctx) {
|
|
|
191638
192241
|
}
|
|
191639
192242
|
|
|
191640
192243
|
// mcp/gh.ts
|
|
191641
|
-
import { mkdirSync as
|
|
191642
|
-
import { join as
|
|
192244
|
+
import { mkdirSync as mkdirSync9 } from "node:fs";
|
|
192245
|
+
import { join as join22 } from "node:path";
|
|
191643
192246
|
|
|
191644
192247
|
// mcp/shell.ts
|
|
191645
192248
|
import { spawn as spawn5, spawnSync as spawnSync6 } from "node:child_process";
|
|
191646
192249
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
191647
|
-
import { closeSync, openSync, writeFileSync as
|
|
192250
|
+
import { closeSync, openSync, writeFileSync as writeFileSync13 } from "node:fs";
|
|
191648
192251
|
import { userInfo as userInfo2 } from "node:os";
|
|
191649
|
-
import { join as
|
|
192252
|
+
import { join as join21 } from "node:path";
|
|
191650
192253
|
import { setTimeout as sleep3 } from "node:timers/promises";
|
|
191651
192254
|
var ShellParams = type({
|
|
191652
192255
|
command: "string",
|
|
@@ -191909,8 +192512,8 @@ ${spawnError}` : spawnError;
|
|
|
191909
192512
|
}
|
|
191910
192513
|
function capOutput(output) {
|
|
191911
192514
|
if (output.length <= MAX_OUTPUT_CHARS) return output;
|
|
191912
|
-
const fullPath =
|
|
191913
|
-
|
|
192515
|
+
const fullPath = join21(getTempDir(), `shell-${randomUUID4().slice(0, 8)}.log`);
|
|
192516
|
+
writeFileSync13(fullPath, output);
|
|
191914
192517
|
const elided = output.length - MAX_OUTPUT_CHARS;
|
|
191915
192518
|
return `... [${elided} chars truncated; full output saved to ${fullPath}] ...
|
|
191916
192519
|
${output.slice(-MAX_OUTPUT_CHARS)}`;
|
|
@@ -191964,8 +192567,8 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
|
|
|
191964
192567
|
if (params.background) {
|
|
191965
192568
|
const tempDir = getTempDir();
|
|
191966
192569
|
const handle = `bg-${randomUUID4().slice(0, 8)}`;
|
|
191967
|
-
const outputPath =
|
|
191968
|
-
const pidPath =
|
|
192570
|
+
const outputPath = join21(tempDir, `${handle}.log`);
|
|
192571
|
+
const pidPath = join21(tempDir, `${handle}.pid`);
|
|
191969
192572
|
const logFd = openSync(outputPath, "a");
|
|
191970
192573
|
let proc;
|
|
191971
192574
|
try {
|
|
@@ -191982,7 +192585,7 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
|
|
|
191982
192585
|
throw new Error("failed to start background process");
|
|
191983
192586
|
}
|
|
191984
192587
|
proc.unref();
|
|
191985
|
-
|
|
192588
|
+
writeFileSync13(pidPath, `${proc.pid}
|
|
191986
192589
|
`);
|
|
191987
192590
|
ctx.toolState.backgroundProcesses.set(handle, { pid: proc.pid, outputPath, pidPath });
|
|
191988
192591
|
return {
|
|
@@ -192062,8 +192665,8 @@ function GhTool(ctx) {
|
|
|
192062
192665
|
description: `Run the GitHub CLI against ${ctx.repo.owner}/${ctx.repo.name}. Pass argv as an array \u2014 there is no shell, so pipes, redirects and \`&&\` do not work; use gh's own \`--json\`/\`--jq\` flags instead. \`gh api graphql\` is available. Authenticated with ${permissions ? formatPermissions(permissions) : "no permissions"} on this repo only; anything else 403s. Pushing, merging and ref writes are not available \u2014 use the git tools.`,
|
|
192063
192666
|
parameters: GhParams,
|
|
192064
192667
|
execute: execute(async (params) => {
|
|
192065
|
-
const configDir =
|
|
192066
|
-
|
|
192668
|
+
const configDir = join22(ctx.tmpdir, "gh-config");
|
|
192669
|
+
mkdirSync9(configDir, { recursive: true });
|
|
192067
192670
|
const command = ["gh", ...params.args.map(shellQuote)].join(" ");
|
|
192068
192671
|
const result = await runSandboxed({
|
|
192069
192672
|
command,
|
|
@@ -192786,8 +193389,8 @@ function PullRequestInfoTool(ctx) {
|
|
|
192786
193389
|
}
|
|
192787
193390
|
|
|
192788
193391
|
// mcp/reviewComments.ts
|
|
192789
|
-
import { writeFileSync as
|
|
192790
|
-
import { join as
|
|
193392
|
+
import { writeFileSync as writeFileSync14 } from "node:fs";
|
|
193393
|
+
import { join as join23 } from "node:path";
|
|
192791
193394
|
var COMMENTS_PER_THREAD = 50;
|
|
192792
193395
|
var REVIEW_THREADS_QUERY = `
|
|
192793
193396
|
query ($owner: String!, $name: String!, $prNumber: Int!, $cursor: String) {
|
|
@@ -193260,8 +193863,8 @@ function GetReviewCommentsTool(ctx) {
|
|
|
193260
193863
|
throw new Error("PULLFROG_TEMP_DIR not set");
|
|
193261
193864
|
}
|
|
193262
193865
|
const filename = `review-${params.review_id}-threads.md`;
|
|
193263
|
-
const commentsPath =
|
|
193264
|
-
|
|
193866
|
+
const commentsPath = join23(tempDir, filename);
|
|
193867
|
+
writeFileSync14(commentsPath, formatted.content);
|
|
193265
193868
|
log2.debug(`wrote ${threadBlocks.length} threads to ${commentsPath}`);
|
|
193266
193869
|
return {
|
|
193267
193870
|
review_id: params.review_id,
|
|
@@ -193594,8 +194197,8 @@ function UploadFileTool(ctx) {
|
|
|
193594
194197
|
}
|
|
193595
194198
|
|
|
193596
194199
|
// mcp/xrepo.ts
|
|
193597
|
-
import { mkdirSync as
|
|
193598
|
-
import { join as
|
|
194200
|
+
import { mkdirSync as mkdirSync10, rmSync as rmSync3 } from "node:fs";
|
|
194201
|
+
import { join as join24 } from "node:path";
|
|
193599
194202
|
function assertValidRepoName(name) {
|
|
193600
194203
|
if (!/^[A-Za-z0-9._-]+$/.test(name) || name.startsWith("-") || name.includes("..")) {
|
|
193601
194204
|
throw new Error(
|
|
@@ -193675,8 +194278,8 @@ function CheckoutRepoTool(ctx) {
|
|
|
193675
194278
|
return { path: existing.dir, access: existing.access, note: "already checked out." };
|
|
193676
194279
|
}
|
|
193677
194280
|
const access = accessFor(ctx, repo);
|
|
193678
|
-
const dir =
|
|
193679
|
-
|
|
194281
|
+
const dir = join24(ctx.tmpdir, "xrepo", repo);
|
|
194282
|
+
mkdirSync10(dir, { recursive: true });
|
|
193680
194283
|
const state = ensureRepoState(ctx.toolState, { owner, name: repo, dir, access });
|
|
193681
194284
|
const rc = resolveRepoCtx(ctx, repo);
|
|
193682
194285
|
try {
|
|
@@ -193924,6 +194527,9 @@ function hasEnvVar2(name) {
|
|
|
193924
194527
|
function hasClaudeCodeAuth() {
|
|
193925
194528
|
return hasEnvVar2("CLAUDE_CODE_OAUTH_TOKEN") || hasEnvVar2("ANTHROPIC_API_KEY");
|
|
193926
194529
|
}
|
|
194530
|
+
function hasCodexAuth() {
|
|
194531
|
+
return hasEnvVar2("CODEX_AUTH_JSON") || hasEnvVar2("OPENAI_API_KEY");
|
|
194532
|
+
}
|
|
193927
194533
|
function hasBedrockAuth() {
|
|
193928
194534
|
return hasEnvVar2("AWS_BEARER_TOKEN_BEDROCK") || hasEnvVar2("AWS_ACCESS_KEY_ID") && hasEnvVar2("AWS_SECRET_ACCESS_KEY");
|
|
193929
194535
|
}
|
|
@@ -193950,6 +194556,15 @@ function resolveSlug(slug2) {
|
|
|
193950
194556
|
}
|
|
193951
194557
|
return vertexId;
|
|
193952
194558
|
}
|
|
194559
|
+
if (alias?.routing === "azure") {
|
|
194560
|
+
const deployment = process.env[AZURE_DEPLOYMENT_ENV]?.trim();
|
|
194561
|
+
if (!deployment) {
|
|
194562
|
+
throw new Error(
|
|
194563
|
+
`${AZURE_DEPLOYMENT_ENV} env var is required when the model is set to "${slug2}". set it to the name of your Azure OpenAI deployment (not the model it serves \u2014 Azure routes on the deployment name). see https://docs.pullfrog.com/azure for setup.`
|
|
194564
|
+
);
|
|
194565
|
+
}
|
|
194566
|
+
return `${AZURE_PROVIDER}/${deployment}`;
|
|
194567
|
+
}
|
|
193953
194568
|
if (alias?.routing === "openai-compatible") {
|
|
193954
194569
|
const modelId = process.env[OPENAI_COMPATIBLE_MODEL_ENV]?.trim();
|
|
193955
194570
|
if (!modelId) {
|
|
@@ -193988,6 +194603,7 @@ function resolveAgent(ctx) {
|
|
|
193988
194603
|
}
|
|
193989
194604
|
log2.warning(`\xBB unknown PULLFROG_AGENT="${envAgent}" \u2014 falling through to auto-select`);
|
|
193990
194605
|
}
|
|
194606
|
+
if (ctx.proxyModel) return agents.opencode;
|
|
193991
194607
|
if (ctx.model && hasBedrockAuth() && process.env[BEDROCK_MODEL_ID_ENV]?.trim() === ctx.model) {
|
|
193992
194608
|
return isBedrockAnthropicId(ctx.model) ? agents.claude : agents.opencode;
|
|
193993
194609
|
}
|
|
@@ -193997,12 +194613,14 @@ function resolveAgent(ctx) {
|
|
|
193997
194613
|
if (ctx.model) {
|
|
193998
194614
|
try {
|
|
193999
194615
|
const provider2 = getModelProvider(ctx.model);
|
|
194000
|
-
if (provider2 === "anthropic" && hasClaudeCodeAuth())
|
|
194001
|
-
|
|
194002
|
-
}
|
|
194616
|
+
if (provider2 === "anthropic" && hasClaudeCodeAuth()) return agents.claude;
|
|
194617
|
+
if (provider2 === "openai" && ctx.codexAgent && hasCodexAuth()) return agents.codex;
|
|
194003
194618
|
} catch {
|
|
194004
194619
|
}
|
|
194005
194620
|
}
|
|
194621
|
+
if (!ctx.model && ctx.codexAgent && hasCodexAuth() && !hasClaudeCodeAuth()) {
|
|
194622
|
+
return agents.codex;
|
|
194623
|
+
}
|
|
194006
194624
|
return agents.opencode;
|
|
194007
194625
|
}
|
|
194008
194626
|
|
|
@@ -194100,10 +194718,37 @@ auto-compaction is disabled, so long runs grow until your endpoint refuses them.
|
|
|
194100
194718
|
|
|
194101
194719
|
for full setup instructions, see https://docs.pullfrog.com/openai-compatible`;
|
|
194102
194720
|
}
|
|
194721
|
+
function buildAzureSetupError(params) {
|
|
194722
|
+
const githubSecretsUrl = `https://github.com/${params.owner}/${params.name}/settings/secrets/actions`;
|
|
194723
|
+
return `Azure OpenAI selected but required configuration is missing: ${params.missing.join(", ")}.
|
|
194724
|
+
|
|
194725
|
+
only the API key is sensitive \u2014 add it as a secret at ${githubSecretsUrl}. the rest is plain workflow \`env:\`:
|
|
194726
|
+
|
|
194727
|
+
${AZURE_RESOURCE_NAME_ENV}: <name>
|
|
194728
|
+
${AZURE_API_KEY_ENV}: \${{ secrets.${AZURE_API_KEY_ENV} }}
|
|
194729
|
+
${AZURE_DEPLOYMENT_ENV}: <deployment-name>
|
|
194730
|
+
${AZURE_CONTEXT_ENV}: "400000"
|
|
194731
|
+
${AZURE_MAX_OUTPUT_ENV}: "128000"
|
|
194732
|
+
|
|
194733
|
+
${AZURE_RESOURCE_NAME_ENV} is the \`<name>\` in your endpoint https://<name>.openai.azure.com.
|
|
194734
|
+
${AZURE_DEPLOYMENT_ENV} is the name of the deployment, which is not necessarily the name of
|
|
194735
|
+
the model it serves \u2014 Azure routes on the deployment name.
|
|
194736
|
+
|
|
194737
|
+
set the last two to the real limits of whichever model your deployment serves. Pullfrog can't
|
|
194738
|
+
discover them \u2014 a deployment name carries no catalog metadata \u2014 and without them completions
|
|
194739
|
+
are capped at 32000 tokens (rejected outright by models with a smaller cap) and auto-compaction
|
|
194740
|
+
is disabled, so long runs grow until Azure refuses them.
|
|
194741
|
+
|
|
194742
|
+
for full setup instructions, see https://docs.pullfrog.com/azure`;
|
|
194743
|
+
}
|
|
194103
194744
|
function hasEnvVar3(name) {
|
|
194104
194745
|
const value2 = process.env[name];
|
|
194105
194746
|
return typeof value2 === "string" && value2.length > 0;
|
|
194106
194747
|
}
|
|
194748
|
+
function modelHasRuntimeAuth(model) {
|
|
194749
|
+
const authVars = [...getModelEnvVars(model), ...getModelManagedCredentials(model)];
|
|
194750
|
+
return authVars.length === 0 || authVars.some(hasEnvVar3);
|
|
194751
|
+
}
|
|
194107
194752
|
function hasPositiveNumberEnvVar(name) {
|
|
194108
194753
|
return Number(process.env[name]) > 0;
|
|
194109
194754
|
}
|
|
@@ -194122,6 +194767,17 @@ function validateOpenAICompatibleSetup(params) {
|
|
|
194122
194767
|
);
|
|
194123
194768
|
}
|
|
194124
194769
|
}
|
|
194770
|
+
function validateAzureSetup(params) {
|
|
194771
|
+
const missing = [];
|
|
194772
|
+
if (!hasEnvVar3(AZURE_API_KEY_ENV)) missing.push(AZURE_API_KEY_ENV);
|
|
194773
|
+
if (!hasEnvVar3(AZURE_RESOURCE_NAME_ENV)) missing.push(AZURE_RESOURCE_NAME_ENV);
|
|
194774
|
+
if (!hasEnvVar3(AZURE_DEPLOYMENT_ENV)) missing.push(AZURE_DEPLOYMENT_ENV);
|
|
194775
|
+
if (!hasPositiveNumberEnvVar(AZURE_CONTEXT_ENV)) missing.push(AZURE_CONTEXT_ENV);
|
|
194776
|
+
if (!hasPositiveNumberEnvVar(AZURE_MAX_OUTPUT_ENV)) missing.push(AZURE_MAX_OUTPUT_ENV);
|
|
194777
|
+
if (missing.length > 0) {
|
|
194778
|
+
throw new Error(buildAzureSetupError({ owner: params.owner, name: params.name, missing }));
|
|
194779
|
+
}
|
|
194780
|
+
}
|
|
194125
194781
|
function validateBedrockSetup(params) {
|
|
194126
194782
|
const hasAuth = hasEnvVar3("AWS_BEARER_TOKEN_BEDROCK") || hasEnvVar3("AWS_ACCESS_KEY_ID") && hasEnvVar3("AWS_SECRET_ACCESS_KEY");
|
|
194127
194783
|
const missing = [];
|
|
@@ -194145,6 +194801,12 @@ function validateVertexSetup(params) {
|
|
|
194145
194801
|
throw new Error(buildVertexSetupError({ owner: params.owner, name: params.name, missing }));
|
|
194146
194802
|
}
|
|
194147
194803
|
}
|
|
194804
|
+
function hasSingleProviderAuth(agentName) {
|
|
194805
|
+
if (agentName === "codex") {
|
|
194806
|
+
return hasEnvVar3("OPENAI_API_KEY") || hasEnvVar3("CODEX_AUTH_JSON");
|
|
194807
|
+
}
|
|
194808
|
+
return hasEnvVar3("ANTHROPIC_API_KEY") || hasEnvVar3("CLAUDE_CODE_OAUTH_TOKEN");
|
|
194809
|
+
}
|
|
194148
194810
|
function validateAgentApiKey(params) {
|
|
194149
194811
|
if (params.model) {
|
|
194150
194812
|
const alias = resolveDisplayAlias(params.model);
|
|
@@ -194160,6 +194822,10 @@ function validateAgentApiKey(params) {
|
|
|
194160
194822
|
validateOpenAICompatibleSetup({ owner: params.owner, name: params.name });
|
|
194161
194823
|
return;
|
|
194162
194824
|
}
|
|
194825
|
+
if (params.model.startsWith(`${AZURE_PROVIDER}/`)) {
|
|
194826
|
+
validateAzureSetup({ owner: params.owner, name: params.name });
|
|
194827
|
+
return;
|
|
194828
|
+
}
|
|
194163
194829
|
if (!params.model.includes("/")) {
|
|
194164
194830
|
if (process.env[VERTEX_MODEL_ID_ENV]?.trim() === params.model) {
|
|
194165
194831
|
validateVertexSetup({ owner: params.owner, name: params.name });
|
|
@@ -194183,7 +194849,7 @@ function validateAgentApiKey(params) {
|
|
|
194183
194849
|
})
|
|
194184
194850
|
);
|
|
194185
194851
|
}
|
|
194186
|
-
if (
|
|
194852
|
+
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
194187
194853
|
throw new Error(
|
|
194188
194854
|
buildKeyError({
|
|
194189
194855
|
owner: params.owner,
|
|
@@ -194195,7 +194861,7 @@ function validateAgentApiKey(params) {
|
|
|
194195
194861
|
);
|
|
194196
194862
|
}
|
|
194197
194863
|
if (params.agent.name === "opencode") {
|
|
194198
|
-
if (params.authorized.
|
|
194864
|
+
if ([...params.authorized].some(modelHasRuntimeAuth)) return;
|
|
194199
194865
|
const reason = getModelsFailure();
|
|
194200
194866
|
if (reason) throw new Error(reason);
|
|
194201
194867
|
throw new Error(
|
|
@@ -194207,7 +194873,7 @@ function validateAgentApiKey(params) {
|
|
|
194207
194873
|
})
|
|
194208
194874
|
);
|
|
194209
194875
|
}
|
|
194210
|
-
if (
|
|
194876
|
+
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
194211
194877
|
throw new Error(
|
|
194212
194878
|
buildKeyError({
|
|
194213
194879
|
owner: params.owner,
|
|
@@ -194580,9 +195246,9 @@ async function checkConfiguredCredentials(params) {
|
|
|
194580
195246
|
|
|
194581
195247
|
// utils/gitAuthServer.ts
|
|
194582
195248
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
194583
|
-
import { writeFileSync as
|
|
195249
|
+
import { writeFileSync as writeFileSync15 } from "node:fs";
|
|
194584
195250
|
import { createServer as createServer3 } from "node:http";
|
|
194585
|
-
import { join as
|
|
195251
|
+
import { join as join25 } from "node:path";
|
|
194586
195252
|
var REVOKED_TRAP_MS = 6e4;
|
|
194587
195253
|
function revokeGitHubToken(token) {
|
|
194588
195254
|
fetch("https://api.github.com/installation/token", {
|
|
@@ -194651,7 +195317,7 @@ async function startGitAuthServer(tmpdir4) {
|
|
|
194651
195317
|
function writeAskpassScript(code) {
|
|
194652
195318
|
const scriptId = randomUUID5();
|
|
194653
195319
|
const scriptName = `askpass-${scriptId}.js`;
|
|
194654
|
-
const scriptPath =
|
|
195320
|
+
const scriptPath = join25(tmpdir4, scriptName);
|
|
194655
195321
|
const content = [
|
|
194656
195322
|
`#!/usr/bin/env node`,
|
|
194657
195323
|
`var a=process.argv[2]||"";`,
|
|
@@ -194664,7 +195330,7 @@ async function startGitAuthServer(tmpdir4) {
|
|
|
194664
195330
|
`r.on("end",function(){process.stdout.write(d+"\\n")})`,
|
|
194665
195331
|
`}).on("error",function(){process.exit(1)})}`
|
|
194666
195332
|
].join("\n");
|
|
194667
|
-
|
|
195333
|
+
writeFileSync15(scriptPath, content, { mode: 448 });
|
|
194668
195334
|
return scriptPath;
|
|
194669
195335
|
}
|
|
194670
195336
|
async function close() {
|
|
@@ -195103,7 +195769,7 @@ function resolveInstructions(ctx) {
|
|
|
195103
195769
|
|
|
195104
195770
|
// utils/learnings.ts
|
|
195105
195771
|
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
195106
|
-
import { dirname as dirname4, join as
|
|
195772
|
+
import { dirname as dirname4, join as join26 } from "node:path";
|
|
195107
195773
|
|
|
195108
195774
|
// utils/learningsTruncate.ts
|
|
195109
195775
|
var MAX_LEARNINGS_LENGTH = 1e5;
|
|
@@ -195121,10 +195787,10 @@ function truncateAtLineBoundary(body, cap) {
|
|
|
195121
195787
|
var LEARNINGS_FILE_NAME = "pullfrog-learnings.md";
|
|
195122
195788
|
var XREPO_LEARNINGS_FILE_NAME = "pullfrog-xrepo-learnings.md";
|
|
195123
195789
|
function learningsFilePath(tmpdir4) {
|
|
195124
|
-
return
|
|
195790
|
+
return join26(tmpdir4, LEARNINGS_FILE_NAME);
|
|
195125
195791
|
}
|
|
195126
195792
|
function xrepoLearningsFilePath(tmpdir4) {
|
|
195127
|
-
return
|
|
195793
|
+
return join26(tmpdir4, XREPO_LEARNINGS_FILE_NAME);
|
|
195128
195794
|
}
|
|
195129
195795
|
async function seedLearningsFile(params) {
|
|
195130
195796
|
const path4 = learningsFilePath(params.tmpdir);
|
|
@@ -195240,7 +195906,7 @@ async function persistXrepoLearnings(ctx) {
|
|
|
195240
195906
|
// utils/modelAccess.ts
|
|
195241
195907
|
function decideModelAccess(input) {
|
|
195242
195908
|
if (!input.modelExplicit || !input.model) return { kind: "ok" };
|
|
195243
|
-
const byokAuthorized = !!input.resolvedModel && (input.authorized.has(input.resolvedModel) || !input.resolvedModel.includes("/") || input.resolvedModel.startsWith(`${OPENAI_COMPATIBLE_PROVIDER}/`));
|
|
195909
|
+
const byokAuthorized = !!input.resolvedModel && (input.authorized.has(input.resolvedModel) || !input.resolvedModel.includes("/") || input.resolvedModel.startsWith(`${OPENAI_COMPATIBLE_PROVIDER}/`) || input.resolvedModel.startsWith(`${AZURE_PROVIDER}/`));
|
|
195244
195910
|
if (input.proxyActive) {
|
|
195245
195911
|
const target = resolveOpenRouterModel(input.model);
|
|
195246
195912
|
if (input.oss) {
|
|
@@ -195285,7 +195951,7 @@ function buildModelAccessError(input) {
|
|
|
195285
195951
|
}
|
|
195286
195952
|
|
|
195287
195953
|
// utils/normalizeEnv.ts
|
|
195288
|
-
var
|
|
195954
|
+
var core5 = __toESM(require_core(), 1);
|
|
195289
195955
|
function hasControlCharacter(value2) {
|
|
195290
195956
|
return [...value2].some((ch) => {
|
|
195291
195957
|
const code = ch.charCodeAt(0);
|
|
@@ -195311,7 +195977,7 @@ function sanitizeSecret(key, value2) {
|
|
|
195311
195977
|
`\xBB stripped whitespace from ${key} (whitespace in secret values breaks GitHub Actions log masking)`
|
|
195312
195978
|
);
|
|
195313
195979
|
}
|
|
195314
|
-
|
|
195980
|
+
core5.setSecret(trimmed);
|
|
195315
195981
|
return trimmed;
|
|
195316
195982
|
}
|
|
195317
195983
|
function normalizeEnv() {
|
|
@@ -195355,7 +196021,7 @@ function normalizeEnv() {
|
|
|
195355
196021
|
}
|
|
195356
196022
|
|
|
195357
196023
|
// utils/overrides.ts
|
|
195358
|
-
var
|
|
196024
|
+
var core6 = __toESM(require_core(), 1);
|
|
195359
196025
|
var DENIED_OVERRIDE_NAMES = /* @__PURE__ */ new Set([
|
|
195360
196026
|
"GITHUB_TOKEN",
|
|
195361
196027
|
"GH_TOKEN",
|
|
@@ -195401,7 +196067,7 @@ function applyOverrides(params) {
|
|
|
195401
196067
|
denied.push(key);
|
|
195402
196068
|
continue;
|
|
195403
196069
|
}
|
|
195404
|
-
if (value2.length > 0)
|
|
196070
|
+
if (value2.length > 0) core6.setSecret(value2);
|
|
195405
196071
|
params.env[key] = value2;
|
|
195406
196072
|
applied.push(key);
|
|
195407
196073
|
}
|
|
@@ -195410,8 +196076,8 @@ function applyOverrides(params) {
|
|
|
195410
196076
|
}
|
|
195411
196077
|
|
|
195412
196078
|
// utils/payload.ts
|
|
195413
|
-
var
|
|
195414
|
-
import { readFileSync as
|
|
196079
|
+
var core7 = __toESM(require_core(), 1);
|
|
196080
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
195415
196081
|
import { isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
|
|
195416
196082
|
|
|
195417
196083
|
// utils/versioning.ts
|
|
@@ -195498,8 +196164,8 @@ function resolveCwd(cwd) {
|
|
|
195498
196164
|
return workspace ? resolve2(workspace, cwd) : cwd;
|
|
195499
196165
|
}
|
|
195500
196166
|
function resolvePromptInput() {
|
|
195501
|
-
const promptInput =
|
|
195502
|
-
const promptFile =
|
|
196167
|
+
const promptInput = core7.getInput("prompt");
|
|
196168
|
+
const promptFile = core7.getInput("prompt_file");
|
|
195503
196169
|
if (promptInput && promptFile) {
|
|
195504
196170
|
throw new Error("set exactly one of 'prompt' or 'prompt_file' inputs, not both.");
|
|
195505
196171
|
}
|
|
@@ -195525,7 +196191,7 @@ function resolvePromptInput() {
|
|
|
195525
196191
|
function resolvePromptFile(input) {
|
|
195526
196192
|
const workspace = process.env.GITHUB_WORKSPACE;
|
|
195527
196193
|
const path4 = isAbsolute2(input) ? input : workspace ? resolve2(workspace, input) : resolve2(input);
|
|
195528
|
-
const content =
|
|
196194
|
+
const content = readFileSync7(path4, "utf-8");
|
|
195529
196195
|
if (!content.trim()) {
|
|
195530
196196
|
throw new Error(`prompt_file ${JSON.stringify(input)} is empty.`);
|
|
195531
196197
|
}
|
|
@@ -195533,7 +196199,7 @@ function resolvePromptFile(input) {
|
|
|
195533
196199
|
}
|
|
195534
196200
|
function warnIfDeprecatedStatusChecks(value2) {
|
|
195535
196201
|
if (value2 !== void 0) {
|
|
195536
|
-
|
|
196202
|
+
core7.warning(
|
|
195537
196203
|
"`status_checks` is deprecated. Both checks are now repository settings \u2014 open the Pullfrog console for this repo (Automations \u2192 Review PRs) and set them there, then remove `status_checks` from your workflow. It keeps working until you do."
|
|
195538
196204
|
);
|
|
195539
196205
|
}
|
|
@@ -195541,15 +196207,15 @@ function warnIfDeprecatedStatusChecks(value2) {
|
|
|
195541
196207
|
}
|
|
195542
196208
|
function resolveNonPromptInputs() {
|
|
195543
196209
|
return Inputs.omit("prompt", "prompt_file").assert({
|
|
195544
|
-
model:
|
|
195545
|
-
effort:
|
|
195546
|
-
debug:
|
|
195547
|
-
timeout:
|
|
195548
|
-
cwd:
|
|
195549
|
-
push:
|
|
195550
|
-
shell:
|
|
195551
|
-
status_checks: warnIfDeprecatedStatusChecks(
|
|
195552
|
-
progress_comments:
|
|
196210
|
+
model: core7.getInput("model") || void 0,
|
|
196211
|
+
effort: core7.getInput("effort") || void 0,
|
|
196212
|
+
debug: core7.getInput("debug") || void 0,
|
|
196213
|
+
timeout: core7.getInput("timeout") || void 0,
|
|
196214
|
+
cwd: core7.getInput("cwd") || void 0,
|
|
196215
|
+
push: core7.getInput("push") || void 0,
|
|
196216
|
+
shell: core7.getInput("shell") || void 0,
|
|
196217
|
+
status_checks: warnIfDeprecatedStatusChecks(core7.getInput("status_checks") || void 0),
|
|
196218
|
+
progress_comments: core7.getInput("progress_comments") || void 0
|
|
195553
196219
|
});
|
|
195554
196220
|
}
|
|
195555
196221
|
function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
@@ -195617,7 +196283,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
195617
196283
|
};
|
|
195618
196284
|
}
|
|
195619
196285
|
function resolveOutputSchema() {
|
|
195620
|
-
const raw2 =
|
|
196286
|
+
const raw2 = core7.getInput("output_schema");
|
|
195621
196287
|
if (!raw2) return void 0;
|
|
195622
196288
|
let parsed2;
|
|
195623
196289
|
try {
|
|
@@ -195633,10 +196299,10 @@ function resolveOutputSchema() {
|
|
|
195633
196299
|
}
|
|
195634
196300
|
|
|
195635
196301
|
// utils/proxy.ts
|
|
195636
|
-
var
|
|
196302
|
+
var core9 = __toESM(require_core(), 1);
|
|
195637
196303
|
|
|
195638
196304
|
// utils/token.ts
|
|
195639
|
-
var
|
|
196305
|
+
var core8 = __toESM(require_core(), 1);
|
|
195640
196306
|
import assert2 from "node:assert/strict";
|
|
195641
196307
|
var mcpTokenValue;
|
|
195642
196308
|
var refreshMcpTokenFn;
|
|
@@ -195644,7 +196310,7 @@ function getMcpTokenRefresh() {
|
|
|
195644
196310
|
return refreshMcpTokenFn;
|
|
195645
196311
|
}
|
|
195646
196312
|
function getJobToken() {
|
|
195647
|
-
const inputToken =
|
|
196313
|
+
const inputToken = core8.getInput("token");
|
|
195648
196314
|
if (inputToken) {
|
|
195649
196315
|
return inputToken;
|
|
195650
196316
|
}
|
|
@@ -195660,7 +196326,7 @@ async function resolveTokens(params) {
|
|
|
195660
196326
|
if (externalToken) {
|
|
195661
196327
|
mcpTokenValue = externalToken;
|
|
195662
196328
|
if (isGitHubActions) {
|
|
195663
|
-
|
|
196329
|
+
core8.setSecret(externalToken);
|
|
195664
196330
|
}
|
|
195665
196331
|
log2.info("\xBB using external GH_TOKEN for both git and MCP");
|
|
195666
196332
|
return {
|
|
@@ -195680,7 +196346,7 @@ async function resolveTokens(params) {
|
|
|
195680
196346
|
const gitPermissions = params.push === "disabled" ? { contents: "read" } : { contents: "write", workflows: "write" };
|
|
195681
196347
|
const gitToken = await acquireNewToken({ repos: writeRepos, permissions: gitPermissions });
|
|
195682
196348
|
if (isGitHubActions) {
|
|
195683
|
-
|
|
196349
|
+
core8.setSecret(gitToken);
|
|
195684
196350
|
}
|
|
195685
196351
|
log2.info(
|
|
195686
196352
|
`\xBB acquired git token (${Object.entries(gitPermissions).map((e) => e.join(":")).join(", ")})`
|
|
@@ -195697,7 +196363,7 @@ async function resolveTokens(params) {
|
|
|
195697
196363
|
};
|
|
195698
196364
|
const mcpToken = await acquireNewToken({ repos: writeRepos, permissions: mcpPermissions });
|
|
195699
196365
|
if (isGitHubActions) {
|
|
195700
|
-
|
|
196366
|
+
core8.setSecret(mcpToken);
|
|
195701
196367
|
}
|
|
195702
196368
|
log2.info(
|
|
195703
196369
|
`\xBB acquired scoped MCP token (${Object.entries(mcpPermissions).map((e) => e.join(":")).join(", ")})`
|
|
@@ -195706,7 +196372,7 @@ async function resolveTokens(params) {
|
|
|
195706
196372
|
let ghToken;
|
|
195707
196373
|
if (ghPermissions) {
|
|
195708
196374
|
ghToken = await acquireNewToken({ permissions: ghPermissions });
|
|
195709
|
-
if (isGitHubActions)
|
|
196375
|
+
if (isGitHubActions) core8.setSecret(ghToken);
|
|
195710
196376
|
log2.info(
|
|
195711
196377
|
`\xBB acquired gh token mirroring ${params.authorPermission} (${formatPermissions(ghPermissions)})`
|
|
195712
196378
|
);
|
|
@@ -195717,7 +196383,7 @@ async function resolveTokens(params) {
|
|
|
195717
196383
|
repos: params.xrepo.read,
|
|
195718
196384
|
permissions: { contents: "read" }
|
|
195719
196385
|
});
|
|
195720
|
-
if (isGitHubActions)
|
|
196386
|
+
if (isGitHubActions) core8.setSecret(readToken);
|
|
195721
196387
|
log2.info(`\xBB acquired cross-repo read token (contents:read, ${params.xrepo.read.length} repos)`);
|
|
195722
196388
|
}
|
|
195723
196389
|
mcpTokenValue = mcpToken;
|
|
@@ -195736,7 +196402,7 @@ async function resolveTokens(params) {
|
|
|
195736
196402
|
oidc: params.oidc ?? void 0
|
|
195737
196403
|
}).then((fresh) => {
|
|
195738
196404
|
if (isGitHubActions) {
|
|
195739
|
-
|
|
196405
|
+
core8.setSecret(fresh);
|
|
195740
196406
|
}
|
|
195741
196407
|
mcpTokenValue = fresh;
|
|
195742
196408
|
currentMcpToken = fresh;
|
|
@@ -195757,7 +196423,7 @@ async function resolveTokens(params) {
|
|
|
195757
196423
|
permissions: gitPermissions,
|
|
195758
196424
|
oidc: params.oidc ?? void 0
|
|
195759
196425
|
}).then((fresh) => {
|
|
195760
|
-
if (isGitHubActions)
|
|
196426
|
+
if (isGitHubActions) core8.setSecret(fresh);
|
|
195761
196427
|
void revokeGitHubInstallationToken(currentGitToken);
|
|
195762
196428
|
currentGitToken = fresh;
|
|
195763
196429
|
log2.warning("\xBB GitHub rejected the git token; re-acquired a fresh git token");
|
|
@@ -195774,7 +196440,7 @@ async function resolveTokens(params) {
|
|
|
195774
196440
|
permissions: { contents: "read" },
|
|
195775
196441
|
oidc: params.oidc ?? void 0
|
|
195776
196442
|
}).then((fresh) => {
|
|
195777
|
-
if (isGitHubActions)
|
|
196443
|
+
if (isGitHubActions) core8.setSecret(fresh);
|
|
195778
196444
|
void revokeGitHubInstallationToken(read2);
|
|
195779
196445
|
currentReadToken = fresh;
|
|
195780
196446
|
log2.warning("\xBB GitHub rejected the read token; re-acquired a fresh read token");
|
|
@@ -195988,7 +196654,7 @@ async function resolveProxyModel(ctx) {
|
|
|
195988
196654
|
});
|
|
195989
196655
|
if (!key) return;
|
|
195990
196656
|
process.env.OPENROUTER_API_KEY = key;
|
|
195991
|
-
|
|
196657
|
+
core9.setSecret(key);
|
|
195992
196658
|
ctx.payload.proxyModel = ctx.proxyModel;
|
|
195993
196659
|
ctx.toolState.model = ctx.proxyModel;
|
|
195994
196660
|
const label = ctx.oss ? "oss" : "router";
|
|
@@ -196059,7 +196725,7 @@ async function runProxyResolution(ctx) {
|
|
|
196059
196725
|
|
|
196060
196726
|
// utils/prSummary.ts
|
|
196061
196727
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
|
|
196062
|
-
import { dirname as dirname5, join as
|
|
196728
|
+
import { dirname as dirname5, join as join27 } from "node:path";
|
|
196063
196729
|
var SUMMARY_FILE_NAME = "pullfrog-summary.md";
|
|
196064
196730
|
var SUMMARY_SCAFFOLD = `# PR summary
|
|
196065
196731
|
|
|
@@ -196069,7 +196735,7 @@ var SUMMARY_SCAFFOLD = `# PR summary
|
|
|
196069
196735
|
var MIN_SNAPSHOT_LENGTH = 60;
|
|
196070
196736
|
var MAX_SNAPSHOT_LENGTH = 32768;
|
|
196071
196737
|
function summaryFilePath(tmpdir4) {
|
|
196072
|
-
return
|
|
196738
|
+
return join27(tmpdir4, SUMMARY_FILE_NAME);
|
|
196073
196739
|
}
|
|
196074
196740
|
async function seedSummaryFile(params) {
|
|
196075
196741
|
const path4 = summaryFilePath(params.tmpdir);
|
|
@@ -196198,6 +196864,7 @@ var defaultSettings = {
|
|
|
196198
196864
|
shell: "restricted",
|
|
196199
196865
|
prApproveEnabled: false,
|
|
196200
196866
|
autoMergeEnabled: false,
|
|
196867
|
+
codexAgent: false,
|
|
196201
196868
|
signedCommits: false,
|
|
196202
196869
|
repoIntelligence: false,
|
|
196203
196870
|
progressComments: true,
|
|
@@ -196686,7 +197353,7 @@ ${genericBody}`,
|
|
|
196686
197353
|
}
|
|
196687
197354
|
|
|
196688
197355
|
// utils/runLifecycle.ts
|
|
196689
|
-
var
|
|
197356
|
+
var core10 = __toESM(require_core(), 1);
|
|
196690
197357
|
|
|
196691
197358
|
// utils/autoMerge.ts
|
|
196692
197359
|
function hasBlockingHumanReview(reviews) {
|
|
@@ -197072,7 +197739,7 @@ async function finalizeSuccessRun(input) {
|
|
|
197072
197739
|
}
|
|
197073
197740
|
if (input.toolState.output) {
|
|
197074
197741
|
log2.info(`::pullfrog-output::${Buffer.from(input.toolState.output).toString("base64")}`);
|
|
197075
|
-
|
|
197742
|
+
core10.setOutput("result", input.toolState.output);
|
|
197076
197743
|
}
|
|
197077
197744
|
if (input.result.success) {
|
|
197078
197745
|
await approveAfterFix(input.toolContext).catch((error52) => {
|
|
@@ -197536,7 +198203,11 @@ async function main() {
|
|
|
197536
198203
|
}
|
|
197537
198204
|
const resolvedModel = credentials.kind === "fellBack" ? credentials.replacement : configuredModel;
|
|
197538
198205
|
vertexCredentials = materializeVertexCredentials({ model: resolvedModel });
|
|
197539
|
-
const agent2 = resolveAgent({
|
|
198206
|
+
const agent2 = resolveAgent({
|
|
198207
|
+
model: resolvedModel,
|
|
198208
|
+
proxyModel: payload.proxyModel,
|
|
198209
|
+
codexAgent: runContext.repoSettings.codexAgent
|
|
198210
|
+
});
|
|
197540
198211
|
const effectiveModel = payload.proxyModel ?? resolvedModel ?? payload.model;
|
|
197541
198212
|
toolState.model = effectiveModel;
|
|
197542
198213
|
if (!payload.proxyModel) {
|
|
@@ -197720,8 +198391,8 @@ ${instructions.user}` : null,
|
|
|
197720
198391
|
log2.info(instructions.full);
|
|
197721
198392
|
});
|
|
197722
198393
|
if (agentId === "opencode") {
|
|
197723
|
-
const pluginDir =
|
|
197724
|
-
const hasPlugins =
|
|
198394
|
+
const pluginDir = join28(process.cwd(), ".opencode", "plugin");
|
|
198395
|
+
const hasPlugins = existsSync9(pluginDir) && readdirSync2(pluginDir).some((f) => /\.[jt]sx?$/.test(f));
|
|
197725
198396
|
if (hasPlugins && toolState.dependencyInstallation?.promise) {
|
|
197726
198397
|
log2.info(
|
|
197727
198398
|
"\xBB .opencode/plugin/ detected \u2014 awaiting dependency installation before agent start"
|
|
@@ -197913,27 +198584,27 @@ async function runMain() {
|
|
|
197913
198584
|
}
|
|
197914
198585
|
} catch (error52) {
|
|
197915
198586
|
const errorMessage = error52 instanceof Error ? error52.message : "unknown error occurred";
|
|
197916
|
-
|
|
198587
|
+
core11.setFailed(`action failed: ${errorMessage}`);
|
|
197917
198588
|
}
|
|
197918
198589
|
}
|
|
197919
198590
|
async function tokenMain() {
|
|
197920
|
-
const reposInput =
|
|
198591
|
+
const reposInput = core11.getInput("repos");
|
|
197921
198592
|
const additionalRepos = reposInput ? reposInput.split(",").map((r2) => r2.trim()).filter(Boolean) : [];
|
|
197922
198593
|
const token = await acquireNewToken({ repos: additionalRepos });
|
|
197923
|
-
|
|
197924
|
-
|
|
197925
|
-
|
|
198594
|
+
core11.setSecret(token);
|
|
198595
|
+
core11.saveState(STATE_TOKEN, token);
|
|
198596
|
+
core11.setOutput("token", token);
|
|
197926
198597
|
const scope2 = additionalRepos.length ? `current repo + ${additionalRepos.join(", ")}` : "current repo only";
|
|
197927
|
-
|
|
198598
|
+
core11.info(`\xBB installation token acquired (${scope2})`);
|
|
197928
198599
|
}
|
|
197929
198600
|
async function tokenPost() {
|
|
197930
|
-
const token =
|
|
198601
|
+
const token = core11.getState(STATE_TOKEN);
|
|
197931
198602
|
if (!token) {
|
|
197932
|
-
|
|
198603
|
+
core11.debug("no token found in state, skipping revocation");
|
|
197933
198604
|
return;
|
|
197934
198605
|
}
|
|
197935
198606
|
await revokeGitHubInstallationToken(token);
|
|
197936
|
-
|
|
198607
|
+
core11.info("\xBB installation token revoked");
|
|
197937
198608
|
}
|
|
197938
198609
|
function printGhaUsage(params) {
|
|
197939
198610
|
params.stream(`usage: ${params.prog} gha [subcommand]
|
|
@@ -198049,7 +198720,7 @@ async function run(args2) {
|
|
|
198049
198720
|
}
|
|
198050
198721
|
} catch (error52) {
|
|
198051
198722
|
const message = error52 instanceof Error ? error52.message : String(error52);
|
|
198052
|
-
|
|
198723
|
+
core11.setFailed(message);
|
|
198053
198724
|
}
|
|
198054
198725
|
}
|
|
198055
198726
|
|
|
@@ -198896,7 +199567,7 @@ async function runCli4(input) {
|
|
|
198896
199567
|
}
|
|
198897
199568
|
|
|
198898
199569
|
// cli.ts
|
|
198899
|
-
var VERSION10 = "0.1.
|
|
199570
|
+
var VERSION10 = "0.1.59";
|
|
198900
199571
|
var bin = basename2(process.argv[1] || "");
|
|
198901
199572
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
198902
199573
|
var rawArgs = process.argv.slice(2);
|