pullfrog 0.1.57 → 0.1.60
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/agents/shared.d.ts +7 -0
- package/dist/cli.mjs +1216 -928
- package/dist/external.d.ts +2 -1
- package/dist/index.js +1197 -454
- package/dist/internal.js +31 -3
- package/dist/models.d.ts +42 -1
- package/dist/utils/activity.d.ts +12 -0
- package/dist/utils/agent.d.ts +10 -0
- package/dist/utils/codexHome.d.ts +27 -0
- package/dist/utils/credentialCheck.d.ts +7 -1
- 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:
|
|
@@ -106557,6 +106587,11 @@ var DEFAULT_ACTIVITY_TIMEOUT_MS = 3e5;
|
|
|
106557
106587
|
var AGENT_ACTIVITY_TIMEOUT_MS = 9e5;
|
|
106558
106588
|
var AGENT_FIRST_EVENT_TIMEOUT_MS = 12e4;
|
|
106559
106589
|
var DEFAULT_ACTIVITY_CHECK_INTERVAL_MS = 5e3;
|
|
106590
|
+
function watchdogBudgetMs(compiled, envVar) {
|
|
106591
|
+
const raw2 = Number(process.env[envVar]);
|
|
106592
|
+
if (!Number.isFinite(raw2) || raw2 <= 0) return compiled;
|
|
106593
|
+
return Math.min(compiled, raw2);
|
|
106594
|
+
}
|
|
106560
106595
|
var DEBUG_TS_PREFIX = /^(?:\[\d{4}-\d{2}-\d{2}T[^\]]+\]\s+)?/.source;
|
|
106561
106596
|
var ACTIVITY_NOISE_PATTERNS = [
|
|
106562
106597
|
new RegExp(`${DEBUG_TS_PREFIX}\\[mcp-proxy\\]`),
|
|
@@ -107028,7 +107063,8 @@ import { pipeline } from "node:stream/promises";
|
|
|
107028
107063
|
async function installFromNpmTarball(params) {
|
|
107029
107064
|
const tempDir = process.env.PULLFROG_TEMP_DIR;
|
|
107030
107065
|
if (!tempDir) throw new Error("PULLFROG_TEMP_DIR is not set");
|
|
107031
|
-
const
|
|
107066
|
+
const packageRoot = join2(tempDir, `npm-${params.packageName.replace(/[^a-z0-9]+/gi, "-")}`);
|
|
107067
|
+
const extractedDir = join2(packageRoot, "package");
|
|
107032
107068
|
const cliPath = join2(extractedDir, params.executablePath);
|
|
107033
107069
|
if (existsSync2(cliPath)) {
|
|
107034
107070
|
log2.debug(`\xBB using cached binary at ${cliPath}`);
|
|
@@ -107054,7 +107090,8 @@ async function installFromNpmTarball(params) {
|
|
|
107054
107090
|
}
|
|
107055
107091
|
}
|
|
107056
107092
|
log2.debug(`\xBB installing ${params.packageName}@${resolvedVersion}...`);
|
|
107057
|
-
|
|
107093
|
+
mkdirSync(packageRoot, { recursive: true });
|
|
107094
|
+
const tarballPath = join2(packageRoot, "package.tgz");
|
|
107058
107095
|
const npmRegistry = process.env.NPM_REGISTRY || "https://registry.npmjs.org";
|
|
107059
107096
|
let tarballUrl;
|
|
107060
107097
|
if (params.packageName.startsWith("@")) {
|
|
@@ -107074,7 +107111,7 @@ async function installFromNpmTarball(params) {
|
|
|
107074
107111
|
await pipeline(response.body, fileStream);
|
|
107075
107112
|
log2.debug(`\xBB downloaded tarball to ${tarballPath}`);
|
|
107076
107113
|
log2.debug(`\xBB extracting tarball...`);
|
|
107077
|
-
const extractResult = spawnSync("tar", ["-xzf", tarballPath, "-C",
|
|
107114
|
+
const extractResult = spawnSync("tar", ["-xzf", tarballPath, "-C", packageRoot], {
|
|
107078
107115
|
stdio: "pipe",
|
|
107079
107116
|
encoding: "utf-8"
|
|
107080
107117
|
});
|
|
@@ -107083,9 +107120,6 @@ async function installFromNpmTarball(params) {
|
|
|
107083
107120
|
`Failed to extract tarball: ${extractResult.stderr || extractResult.stdout || "Unknown error"}`
|
|
107084
107121
|
);
|
|
107085
107122
|
}
|
|
107086
|
-
if (!existsSync2(cliPath)) {
|
|
107087
|
-
throw new Error(`Executable not found in extracted package at ${cliPath}`);
|
|
107088
|
-
}
|
|
107089
107123
|
if (params.installDependencies) {
|
|
107090
107124
|
log2.debug(`\xBB installing dependencies for ${params.packageName}...`);
|
|
107091
107125
|
const installResult = spawnSync("npm", ["install", "--production"], {
|
|
@@ -107106,6 +107140,9 @@ async function installFromNpmTarball(params) {
|
|
|
107106
107140
|
}
|
|
107107
107141
|
log2.debug(`\xBB dependencies installed`);
|
|
107108
107142
|
}
|
|
107143
|
+
if (!existsSync2(cliPath)) {
|
|
107144
|
+
throw new Error(`Executable not found in extracted package at ${cliPath}`);
|
|
107145
|
+
}
|
|
107109
107146
|
chmodSync(cliPath, 493);
|
|
107110
107147
|
log2.debug(`\xBB ${params.packageName} installed at ${cliPath}`);
|
|
107111
107148
|
return cliPath;
|
|
@@ -107279,6 +107316,7 @@ function resolveRunAlias(ctx) {
|
|
|
107279
107316
|
}
|
|
107280
107317
|
const model = ctx.resolvedModel;
|
|
107281
107318
|
if (!model) return void 0;
|
|
107319
|
+
if (model.startsWith(`${AZURE_PROVIDER}/`)) return void 0;
|
|
107282
107320
|
return modelAliases.find((a2) => !a2.fallback && a2.resolve === model) ?? matchHostedAnthropicAlias(model);
|
|
107283
107321
|
}
|
|
107284
107322
|
function ossEffortFloor(ctx) {
|
|
@@ -107317,7 +107355,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
107317
107355
|
// package.json
|
|
107318
107356
|
var package_default = {
|
|
107319
107357
|
name: "pullfrog",
|
|
107320
|
-
version: "0.1.
|
|
107358
|
+
version: "0.1.60",
|
|
107321
107359
|
type: "module",
|
|
107322
107360
|
bin: {
|
|
107323
107361
|
pullfrog: "dist/cli.mjs",
|
|
@@ -107349,6 +107387,8 @@ var package_default = {
|
|
|
107349
107387
|
"@clack/prompts": "^1.2.0",
|
|
107350
107388
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
107351
107389
|
"@opencode-ai/sdk": "1.18.5",
|
|
107390
|
+
"@openai/codex": "0.147.0",
|
|
107391
|
+
"@openai/codex-sdk": "0.147.0",
|
|
107352
107392
|
"@octokit/plugin-throttling": "^11.0.3",
|
|
107353
107393
|
"@octokit/rest": "^22.0.0",
|
|
107354
107394
|
"@octokit/webhooks-types": "^7.6.1",
|
|
@@ -109424,7 +109464,7 @@ var claude = agent({
|
|
|
109424
109464
|
if ((isBedrockRoute || isVertexRoute2) && specifier && effort.alias?.effort) {
|
|
109425
109465
|
applyHostedEffortCapabilities({ env: env2, modelId: specifier, levels: effort.alias.effort });
|
|
109426
109466
|
}
|
|
109427
|
-
if (env2.CLAUDE_CODE_OAUTH_TOKEN && !isBedrockRoute && env2.ANTHROPIC_API_KEY) {
|
|
109467
|
+
if (env2.CLAUDE_CODE_OAUTH_TOKEN && !isBedrockRoute && !isVertexRoute2 && !env2.ANTHROPIC_BASE_URL && !env2.ANTHROPIC_AUTH_TOKEN && env2.ANTHROPIC_API_KEY) {
|
|
109428
109468
|
const preflight = await preflightClaudeSubscription({
|
|
109429
109469
|
token: env2.CLAUDE_CODE_OAUTH_TOKEN,
|
|
109430
109470
|
model
|
|
@@ -109470,13 +109510,735 @@ var claude = agent({
|
|
|
109470
109510
|
}
|
|
109471
109511
|
});
|
|
109472
109512
|
|
|
109473
|
-
// agents/
|
|
109513
|
+
// agents/codex.ts
|
|
109474
109514
|
var core2 = __toESM(require_core(), 1);
|
|
109475
|
-
import {
|
|
109476
|
-
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
109515
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
109477
109516
|
import { join as join7 } from "node:path";
|
|
109478
109517
|
import { performance as performance6 } from "node:perf_hooks";
|
|
109479
109518
|
|
|
109519
|
+
// utils/codexHome.ts
|
|
109520
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
109521
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
109522
|
+
import { homedir as homedir2, userInfo } from "node:os";
|
|
109523
|
+
import { join as join6 } from "node:path";
|
|
109524
|
+
var CODEX_AUTH_ENV = "CODEX_AUTH_JSON";
|
|
109525
|
+
var PULLFROG_DATA_DIR = "/var/lib/pullfrog";
|
|
109526
|
+
function isRejectedChain(body) {
|
|
109527
|
+
if (!body.refresh_rejected_at) return false;
|
|
109528
|
+
log2.warning(
|
|
109529
|
+
`\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.`
|
|
109530
|
+
);
|
|
109531
|
+
return true;
|
|
109532
|
+
}
|
|
109533
|
+
function installCodexAuth() {
|
|
109534
|
+
const raw2 = process.env[CODEX_AUTH_ENV];
|
|
109535
|
+
if (!raw2) return null;
|
|
109536
|
+
const body = parseCodexAuthBody(raw2);
|
|
109537
|
+
if (!body) {
|
|
109538
|
+
log2.warning(`\xBB ${CODEX_AUTH_ENV} present but malformed; ignoring`);
|
|
109539
|
+
return null;
|
|
109540
|
+
}
|
|
109541
|
+
if (isRejectedChain(body)) return null;
|
|
109542
|
+
const expiresMs = decodeJwtExpMs(body.tokens.access_token) ?? 0;
|
|
109543
|
+
const xdgDataHome = resolveDataHome();
|
|
109544
|
+
const opencodeDir = join6(xdgDataHome, "opencode");
|
|
109545
|
+
const authPath = join6(opencodeDir, "auth.json");
|
|
109546
|
+
const opencodeAuth = {
|
|
109547
|
+
openai: {
|
|
109548
|
+
type: "oauth",
|
|
109549
|
+
refresh: body.tokens.refresh_token,
|
|
109550
|
+
access: body.tokens.access_token,
|
|
109551
|
+
expires: expiresMs,
|
|
109552
|
+
...body.tokens.account_id ? { accountId: body.tokens.account_id } : {}
|
|
109553
|
+
}
|
|
109554
|
+
};
|
|
109555
|
+
mkdirSync5(opencodeDir, { recursive: true });
|
|
109556
|
+
writeFileSync5(authPath, `${JSON.stringify(opencodeAuth, null, 2)}
|
|
109557
|
+
`, { mode: 384 });
|
|
109558
|
+
process.env.XDG_DATA_HOME = xdgDataHome;
|
|
109559
|
+
log2.info(`\xBB installed Codex auth at ${authPath}`);
|
|
109560
|
+
return {
|
|
109561
|
+
authPath,
|
|
109562
|
+
xdgDataHome,
|
|
109563
|
+
originalRefresh: body.tokens.refresh_token,
|
|
109564
|
+
originalIdToken: body.tokens.id_token
|
|
109565
|
+
};
|
|
109566
|
+
}
|
|
109567
|
+
function installCodexHome() {
|
|
109568
|
+
const raw2 = process.env[CODEX_AUTH_ENV];
|
|
109569
|
+
if (!raw2) return null;
|
|
109570
|
+
const body = parseCodexAuthBody(raw2);
|
|
109571
|
+
if (!body) {
|
|
109572
|
+
log2.warning(`\xBB ${CODEX_AUTH_ENV} present but malformed; ignoring`);
|
|
109573
|
+
return null;
|
|
109574
|
+
}
|
|
109575
|
+
if (isRejectedChain(body)) return null;
|
|
109576
|
+
if (!body.tokens.id_token) {
|
|
109577
|
+
log2.warning(
|
|
109578
|
+
`\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.`
|
|
109579
|
+
);
|
|
109580
|
+
return null;
|
|
109581
|
+
}
|
|
109582
|
+
const codexHome = join6(resolveDataHome(), "codex");
|
|
109583
|
+
const authPath = join6(codexHome, "auth.json");
|
|
109584
|
+
mkdirSync5(codexHome, { recursive: true });
|
|
109585
|
+
writeFileSync5(authPath, stringifyCodexAuthBody(body), { mode: 384 });
|
|
109586
|
+
log2.info(`\xBB installed Codex auth at ${authPath}`);
|
|
109587
|
+
return { codexHome, authPath, originalRefresh: body.tokens.refresh_token };
|
|
109588
|
+
}
|
|
109589
|
+
function resolveDataHome() {
|
|
109590
|
+
if (process.env.CI !== "true") return join6(homedir2(), ".local", "share");
|
|
109591
|
+
bootstrapPullfrogDataDir();
|
|
109592
|
+
return PULLFROG_DATA_DIR;
|
|
109593
|
+
}
|
|
109594
|
+
function bootstrapPullfrogDataDir() {
|
|
109595
|
+
const user = userInfo().username;
|
|
109596
|
+
let primaryGroup;
|
|
109597
|
+
try {
|
|
109598
|
+
primaryGroup = execFileSync4("id", ["-gn", user], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
109599
|
+
} catch {
|
|
109600
|
+
primaryGroup = user;
|
|
109601
|
+
}
|
|
109602
|
+
try {
|
|
109603
|
+
execFileSync4("sudo", ["-n", "mkdir", "-p", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
109604
|
+
execFileSync4("sudo", ["-n", "chown", `${user}:${primaryGroup}`, PULLFROG_DATA_DIR], {
|
|
109605
|
+
stdio: "pipe"
|
|
109606
|
+
});
|
|
109607
|
+
execFileSync4("sudo", ["-n", "chmod", "700", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
109608
|
+
} catch (err) {
|
|
109609
|
+
throw new Error(
|
|
109610
|
+
`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.`
|
|
109611
|
+
);
|
|
109612
|
+
}
|
|
109613
|
+
}
|
|
109614
|
+
|
|
109615
|
+
// utils/secrets.ts
|
|
109616
|
+
var SENSITIVE_PATTERNS = [
|
|
109617
|
+
/_KEY$/i,
|
|
109618
|
+
/_SECRET$/i,
|
|
109619
|
+
/_TOKEN$/i,
|
|
109620
|
+
/_PASSWORD$/i,
|
|
109621
|
+
/_CREDENTIAL$/i
|
|
109622
|
+
];
|
|
109623
|
+
function isSensitiveEnvName(key) {
|
|
109624
|
+
return SENSITIVE_PATTERNS.some((p) => p.test(key));
|
|
109625
|
+
}
|
|
109626
|
+
var SAFE_ENV_PREFIXES = ["GITHUB_", "RUNNER_", "JAVA_HOME_", "GOROOT_"];
|
|
109627
|
+
var SAFE_ENV_NAMES = /* @__PURE__ */ new Set([
|
|
109628
|
+
// system
|
|
109629
|
+
"CI",
|
|
109630
|
+
"HOME",
|
|
109631
|
+
"LANG",
|
|
109632
|
+
"LOGNAME",
|
|
109633
|
+
"PATH",
|
|
109634
|
+
"SHELL",
|
|
109635
|
+
"SHLVL",
|
|
109636
|
+
"TERM",
|
|
109637
|
+
"TMPDIR",
|
|
109638
|
+
"TZ",
|
|
109639
|
+
"USER",
|
|
109640
|
+
"XDG_CONFIG_HOME",
|
|
109641
|
+
"XDG_RUNTIME_DIR",
|
|
109642
|
+
"DEBIAN_FRONTEND",
|
|
109643
|
+
// runner image toolchain
|
|
109644
|
+
"ACCEPT_EULA",
|
|
109645
|
+
"AGENT_TOOLSDIRECTORY",
|
|
109646
|
+
"ANDROID_HOME",
|
|
109647
|
+
"ANDROID_NDK",
|
|
109648
|
+
"ANDROID_NDK_HOME",
|
|
109649
|
+
"ANDROID_NDK_LATEST_HOME",
|
|
109650
|
+
"ANDROID_NDK_ROOT",
|
|
109651
|
+
"ANDROID_SDK_ROOT",
|
|
109652
|
+
"ANT_HOME",
|
|
109653
|
+
"AZURE_EXTENSION_DIR",
|
|
109654
|
+
"BOOTSTRAP_HASKELL_NONINTERACTIVE",
|
|
109655
|
+
"CHROME_BIN",
|
|
109656
|
+
"CHROMEWEBDRIVER",
|
|
109657
|
+
"CONDA",
|
|
109658
|
+
"DOTNET_MULTILEVEL_LOOKUP",
|
|
109659
|
+
"DOTNET_NOLOGO",
|
|
109660
|
+
"DOTNET_SKIP_FIRST_TIME_EXPERIENCE",
|
|
109661
|
+
"EDGEWEBDRIVER",
|
|
109662
|
+
"GECKOWEBDRIVER",
|
|
109663
|
+
"GHCUP_INSTALL_BASE_PREFIX",
|
|
109664
|
+
"GRADLE_HOME",
|
|
109665
|
+
"JAVA_HOME",
|
|
109666
|
+
"HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS",
|
|
109667
|
+
"HOMEBREW_NO_AUTO_UPDATE",
|
|
109668
|
+
"ImageOS",
|
|
109669
|
+
"ImageVersion",
|
|
109670
|
+
"NVM_DIR",
|
|
109671
|
+
"PIPX_BIN_DIR",
|
|
109672
|
+
"PIPX_HOME",
|
|
109673
|
+
"PSModulePath",
|
|
109674
|
+
"SELENIUM_JAR_PATH",
|
|
109675
|
+
"SGX_AESM_ADDR",
|
|
109676
|
+
"SWIFT_PATH",
|
|
109677
|
+
"VCPKG_INSTALLATION_ROOT"
|
|
109678
|
+
]);
|
|
109679
|
+
var _userAllowlist = null;
|
|
109680
|
+
function setEnvAllowlist(raw2) {
|
|
109681
|
+
const names = raw2.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
109682
|
+
_userAllowlist = new Set(names);
|
|
109683
|
+
}
|
|
109684
|
+
function isSafeEnvVar(key) {
|
|
109685
|
+
if (SAFE_ENV_NAMES.has(key)) return true;
|
|
109686
|
+
return SAFE_ENV_PREFIXES.some((p) => key.startsWith(p));
|
|
109687
|
+
}
|
|
109688
|
+
var WORKFLOW_COMMAND_ENV_NAMES = [
|
|
109689
|
+
"GITHUB_ENV",
|
|
109690
|
+
"GITHUB_PATH",
|
|
109691
|
+
"GITHUB_OUTPUT",
|
|
109692
|
+
"GITHUB_STATE",
|
|
109693
|
+
"GITHUB_STEP_SUMMARY",
|
|
109694
|
+
// dropping the five paths above but keeping RUNNER_TEMP would be theatre:
|
|
109695
|
+
// the file-command files live in `$RUNNER_TEMP/_runner_file_commands/`, so the
|
|
109696
|
+
// directory is one `ls` away. nothing in the install path reads it (only our
|
|
109697
|
+
// own leak-surface wipe in `setup.ts`, which runs in the parent), and package
|
|
109698
|
+
// managers use TMPDIR.
|
|
109699
|
+
"RUNNER_TEMP"
|
|
109700
|
+
];
|
|
109701
|
+
function filterEnvForUntrustedCode() {
|
|
109702
|
+
const env2 = filterEnv();
|
|
109703
|
+
for (const name of WORKFLOW_COMMAND_ENV_NAMES) delete env2[name];
|
|
109704
|
+
return env2;
|
|
109705
|
+
}
|
|
109706
|
+
function filterEnv() {
|
|
109707
|
+
const filtered = {};
|
|
109708
|
+
for (const [key, value2] of Object.entries(process.env)) {
|
|
109709
|
+
if (value2 === void 0) continue;
|
|
109710
|
+
const userAllowed = _userAllowlist?.has(key) ?? false;
|
|
109711
|
+
if (isSensitiveEnvName(key) && !userAllowed) continue;
|
|
109712
|
+
if (isSafeEnvVar(key) || userAllowed) {
|
|
109713
|
+
filtered[key] = value2;
|
|
109714
|
+
}
|
|
109715
|
+
}
|
|
109716
|
+
return filtered;
|
|
109717
|
+
}
|
|
109718
|
+
function resolveEnv(mode) {
|
|
109719
|
+
if (mode === "inherit") {
|
|
109720
|
+
return process.env;
|
|
109721
|
+
}
|
|
109722
|
+
if (mode === "restricted" || mode === void 0) {
|
|
109723
|
+
return filterEnv();
|
|
109724
|
+
}
|
|
109725
|
+
return { ...filterEnv(), ...mode };
|
|
109726
|
+
}
|
|
109727
|
+
|
|
109728
|
+
// agents/codex.ts
|
|
109729
|
+
var CODEX_TARGETS = {
|
|
109730
|
+
"linux-x64": "x86_64-unknown-linux-musl",
|
|
109731
|
+
"linux-arm64": "aarch64-unknown-linux-musl",
|
|
109732
|
+
"darwin-x64": "x86_64-apple-darwin",
|
|
109733
|
+
"darwin-arm64": "aarch64-apple-darwin",
|
|
109734
|
+
"win32-x64": "x86_64-pc-windows-msvc",
|
|
109735
|
+
"win32-arm64": "aarch64-pc-windows-msvc"
|
|
109736
|
+
};
|
|
109737
|
+
async function installCodexCli() {
|
|
109738
|
+
const target = CODEX_TARGETS[`${process.platform}-${process.arch}`];
|
|
109739
|
+
if (!target) {
|
|
109740
|
+
throw new Error(`the codex CLI ships no binary for ${process.platform}-${process.arch}`);
|
|
109741
|
+
}
|
|
109742
|
+
const binary = process.platform === "win32" ? "codex.exe" : "codex";
|
|
109743
|
+
return await installFromNpmTarball({
|
|
109744
|
+
packageName: "@openai/codex",
|
|
109745
|
+
version: getDevDependencyVersion("@openai/codex"),
|
|
109746
|
+
executablePath: `node_modules/@openai/codex-${process.platform}-${process.arch}/vendor/${target}/bin/${binary}`,
|
|
109747
|
+
installDependencies: true
|
|
109748
|
+
});
|
|
109749
|
+
}
|
|
109750
|
+
var CODEX_DISABLED_FEATURES = [
|
|
109751
|
+
// browser / desktop control — network reach and arbitrary JS
|
|
109752
|
+
"browser_use",
|
|
109753
|
+
"browser_use_external",
|
|
109754
|
+
"browser_use_full_cdp_access",
|
|
109755
|
+
"computer_use",
|
|
109756
|
+
"in_app_browser",
|
|
109757
|
+
// third-party code loaded into the agent process
|
|
109758
|
+
"plugins",
|
|
109759
|
+
"remote_plugin",
|
|
109760
|
+
"plugin_sharing",
|
|
109761
|
+
"skill_mcp_dependency_install",
|
|
109762
|
+
// lifecycle hooks run commands sourced from repo config, which a PR can edit
|
|
109763
|
+
"hooks",
|
|
109764
|
+
// connectors
|
|
109765
|
+
"apps",
|
|
109766
|
+
// ungated subagent fan-out (see the file header)
|
|
109767
|
+
"multi_agent",
|
|
109768
|
+
"multi_agent_v2"
|
|
109769
|
+
];
|
|
109770
|
+
var CODEX_SHELL_FEATURES = ["shell_tool", "unified_exec"];
|
|
109771
|
+
function tomlBool(entries, value2) {
|
|
109772
|
+
return entries.map((name) => `${name} = ${value2}`).join("\n");
|
|
109773
|
+
}
|
|
109774
|
+
function securityOverrideFlags(params) {
|
|
109775
|
+
const shellEnabled = params.ctx.payload.shell === "enabled";
|
|
109776
|
+
const features = [
|
|
109777
|
+
...CODEX_DISABLED_FEATURES.map((name) => `${name}=false`),
|
|
109778
|
+
...CODEX_SHELL_FEATURES.map((name) => `${name}=${shellEnabled}`)
|
|
109779
|
+
];
|
|
109780
|
+
return [
|
|
109781
|
+
"-c",
|
|
109782
|
+
`approval_policy=${JSON.stringify("never")}`,
|
|
109783
|
+
"-c",
|
|
109784
|
+
`sandbox_mode=${JSON.stringify(params.sandboxMode)}`,
|
|
109785
|
+
// the sandbox's EXTENT has to be locked too, not just its mode: a repo
|
|
109786
|
+
// setting `writable_roots = ["/"]` walked straight out of the checkout with
|
|
109787
|
+
// `sandbox_mode` already flag-locked (measured — apply_patch wrote a file
|
|
109788
|
+
// under $HOME).
|
|
109789
|
+
"-c",
|
|
109790
|
+
`sandbox_workspace_write.writable_roots=[${JSON.stringify(params.repoDir)}]`,
|
|
109791
|
+
"-c",
|
|
109792
|
+
"sandbox_workspace_write.network_access=true",
|
|
109793
|
+
// our own MCP server, for a third time in the same class: a repo pointing
|
|
109794
|
+
// `mcp_servers.pullfrog.url` at its own endpoint (measured — `codex mcp get`
|
|
109795
|
+
// reported the repo's URL) turns every pullfrog tool call into an
|
|
109796
|
+
// exfiltration channel, carrying diffs, file contents and cross-repo
|
|
109797
|
+
// learnings to whoever it names.
|
|
109798
|
+
"-c",
|
|
109799
|
+
`mcp_servers.${pullfrogMcpName}.url=${JSON.stringify(params.mcpServerUrl)}`,
|
|
109800
|
+
"-c",
|
|
109801
|
+
`mcp_servers.${pullfrogMcpName}.${APPROVAL_MODE_KEY}=${JSON.stringify("approve")}`,
|
|
109802
|
+
"-c",
|
|
109803
|
+
`mcp_servers.${pullfrogMcpName}.required=true`,
|
|
109804
|
+
"-c",
|
|
109805
|
+
`mcp_servers.${pullfrogMcpName}.tool_timeout_sec=660`,
|
|
109806
|
+
// `enabled` closes the silent-DoS variant: a repo setting it false would
|
|
109807
|
+
// otherwise strip every GitHub tool and leave the agent narrating failure.
|
|
109808
|
+
"-c",
|
|
109809
|
+
`mcp_servers.${pullfrogMcpName}.enabled=true`,
|
|
109810
|
+
// not a boundary, but the same override: a repo silently re-pointing the
|
|
109811
|
+
// model spends the account's money on a pick it never made, and makes the
|
|
109812
|
+
// "Using `…`" run footer a lie about what actually ran.
|
|
109813
|
+
...params.model ? ["-c", `model=${JSON.stringify(params.model)}`] : [],
|
|
109814
|
+
...params.effortRung ? ["-c", `model_reasoning_effort=${JSON.stringify(params.effortRung)}`] : [],
|
|
109815
|
+
...features.flatMap((entry) => ["-c", `features.${entry}`])
|
|
109816
|
+
];
|
|
109817
|
+
}
|
|
109818
|
+
var CODEX_EFFORTS = ["minimal", "low", "medium", "high", "xhigh"];
|
|
109819
|
+
function resolveCodexModel(ctx) {
|
|
109820
|
+
const specifier = ctx.payload.proxyModel ?? ctx.resolvedModel;
|
|
109821
|
+
if (!specifier) return void 0;
|
|
109822
|
+
try {
|
|
109823
|
+
if (getModelProvider(specifier) === "openai") return stripProviderPrefix(specifier);
|
|
109824
|
+
} catch {
|
|
109825
|
+
}
|
|
109826
|
+
log2.warning(`\xBB ${specifier} isn't an OpenAI model \u2014 running codex on its own default instead`);
|
|
109827
|
+
return void 0;
|
|
109828
|
+
}
|
|
109829
|
+
var APPROVAL_MODE_KEY = "default_tools_approval_mode";
|
|
109830
|
+
var APPROVE_TOOLS = `${APPROVAL_MODE_KEY} = "approve"`;
|
|
109831
|
+
function repoMcpApprovals(repoDir) {
|
|
109832
|
+
const path4 = join7(repoDir, ".codex", "config.toml");
|
|
109833
|
+
if (!existsSync4(path4)) return [];
|
|
109834
|
+
const out = [];
|
|
109835
|
+
let section = [];
|
|
109836
|
+
let isServerTable = false;
|
|
109837
|
+
function flush() {
|
|
109838
|
+
if (section.length === 0) return;
|
|
109839
|
+
const declared = section.some((line) => line.trimStart().startsWith(APPROVAL_MODE_KEY));
|
|
109840
|
+
if (isServerTable && !declared) section.splice(1, 0, APPROVE_TOOLS);
|
|
109841
|
+
out.push(...section, "");
|
|
109842
|
+
section = [];
|
|
109843
|
+
}
|
|
109844
|
+
for (const line of readFileSync3(path4, "utf8").split("\n")) {
|
|
109845
|
+
const header = line.trim().match(/^\[(?<key>[^\]]+)\]$/);
|
|
109846
|
+
if (!header?.groups) {
|
|
109847
|
+
if (section.length > 0) section.push(line);
|
|
109848
|
+
continue;
|
|
109849
|
+
}
|
|
109850
|
+
flush();
|
|
109851
|
+
const key = header.groups.key.trim();
|
|
109852
|
+
if (!key.startsWith("mcp_servers.")) continue;
|
|
109853
|
+
const name = key.slice("mcp_servers.".length).replace(/^"([^"]*)"/, "$1");
|
|
109854
|
+
if (name === pullfrogMcpName || name.startsWith(`${pullfrogMcpName}.`)) continue;
|
|
109855
|
+
isServerTable = !name.includes(".");
|
|
109856
|
+
section = [line.trim()];
|
|
109857
|
+
}
|
|
109858
|
+
flush();
|
|
109859
|
+
return out;
|
|
109860
|
+
}
|
|
109861
|
+
function warnIfNativeEditsUnavailable(ctx) {
|
|
109862
|
+
if (process.platform !== "linux" || ctx.payload.shell !== "disabled") return;
|
|
109863
|
+
log2.warning(
|
|
109864
|
+
"\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."
|
|
109865
|
+
);
|
|
109866
|
+
}
|
|
109867
|
+
function writeCodexConfig(params) {
|
|
109868
|
+
const shellEnabled = params.ctx.payload.shell === "enabled";
|
|
109869
|
+
const sandboxMode = params.ctx.payload.push === "disabled" ? "read-only" : "workspace-write";
|
|
109870
|
+
const repoDir = process.cwd();
|
|
109871
|
+
const config3 = [
|
|
109872
|
+
"# written by pullfrog",
|
|
109873
|
+
// "never" keeps the run non-interactive WITHOUT
|
|
109874
|
+
// --dangerously-bypass-approvals-and-sandbox, which would also switch the
|
|
109875
|
+
// sandbox off and let the native apply_patch tool write anywhere.
|
|
109876
|
+
'approval_policy = "never"',
|
|
109877
|
+
`sandbox_mode = ${JSON.stringify(sandboxMode)}`,
|
|
109878
|
+
// matches opencode's `webfetch: "allow"` — research is part of the job and
|
|
109879
|
+
// neither harness gates it on a permission.
|
|
109880
|
+
'web_search = "live"',
|
|
109881
|
+
...params.model ? [`model = ${JSON.stringify(params.model)}`] : [],
|
|
109882
|
+
...params.effortRung ? [`model_reasoning_effort = ${JSON.stringify(params.effortRung)}`] : [],
|
|
109883
|
+
"",
|
|
109884
|
+
"[features]",
|
|
109885
|
+
tomlBool(CODEX_DISABLED_FEATURES, false),
|
|
109886
|
+
tomlBool(CODEX_SHELL_FEATURES, shellEnabled),
|
|
109887
|
+
"",
|
|
109888
|
+
"[sandbox_workspace_write]",
|
|
109889
|
+
"network_access = true",
|
|
109890
|
+
// the checkout, named explicitly rather than left to `workspace-write` to
|
|
109891
|
+
// imply. does NOT fix the Linux native-write failure — nothing here does;
|
|
109892
|
+
// see wiki/codex-agent.md "The Linux native-write blocker".
|
|
109893
|
+
`writable_roots = [${JSON.stringify(repoDir)}]`,
|
|
109894
|
+
"",
|
|
109895
|
+
`[mcp_servers.${pullfrogMcpName}]`,
|
|
109896
|
+
`url = ${JSON.stringify(params.ctx.mcpServerUrl)}`,
|
|
109897
|
+
// codex's default MCP approval mode PROMPTS for anything it can't read as
|
|
109898
|
+
// read-only, and a `codex exec` run has nobody to answer — the call comes
|
|
109899
|
+
// back "user cancelled MCP tool call" and the agent silently accomplishes
|
|
109900
|
+
// nothing. our own server is the trusted one; the boundary is what we
|
|
109901
|
+
// register, not a second confirmation.
|
|
109902
|
+
APPROVE_TOOLS,
|
|
109903
|
+
// a run whose GitHub tools never registered can't do its job, so fail loudly
|
|
109904
|
+
// rather than let the agent improvise without them.
|
|
109905
|
+
"required = true",
|
|
109906
|
+
// mirrors the opencode harness's 660s: `checkout_pr` runs a multi-minute
|
|
109907
|
+
// fetch on large repos and enforces its own 600s deadline, so a shorter
|
|
109908
|
+
// client abort turns a working checkout into a spurious tool error.
|
|
109909
|
+
"tool_timeout_sec = 660",
|
|
109910
|
+
"",
|
|
109911
|
+
...repoMcpApprovals(repoDir),
|
|
109912
|
+
// UNTRUSTED, deliberately, and this one line is the whole config-precedence
|
|
109913
|
+
// boundary. Codex loads `<repo>/.codex/config.toml` as a layer that
|
|
109914
|
+
// OUTRANKS ours (project 25 vs user 20), and its denylist strips none of
|
|
109915
|
+
// `sandbox_mode`, `approval_policy`, `features` or `mcp_servers` — so a
|
|
109916
|
+
// fork PR could ship a config re-enabling the native shell. Marking the
|
|
109917
|
+
// checkout untrusted makes that layer load `disabled`, closing the class
|
|
109918
|
+
// outright rather than key by key: `RawMcpServerConfig` alone has ~26
|
|
109919
|
+
// fields and enumeration can never finish.
|
|
109920
|
+
//
|
|
109921
|
+
// It costs nothing. `codex exec`'s only startup gate is a GIT-REPO check
|
|
109922
|
+
// (`exec/src/lib.rs:796` — `get_git_repo_root(...).is_none()`, whose error
|
|
109923
|
+
// text unhelpfully says "Not inside a trusted directory"), so an untrusted
|
|
109924
|
+
// checkout still runs. And the repo's own MCP servers survive, because
|
|
109925
|
+
// `repoMcpApprovals` above copies them into OUR layer — which is why that
|
|
109926
|
+
// copying exists at all.
|
|
109927
|
+
//
|
|
109928
|
+
// Measured both ways at 0.147.0: `trusted` → the repo's `model` won;
|
|
109929
|
+
// `untrusted` → it did not, and the run proceeded normally.
|
|
109930
|
+
`[projects.${JSON.stringify(repoDir)}]`,
|
|
109931
|
+
'trust_level = "untrusted"',
|
|
109932
|
+
""
|
|
109933
|
+
].join("\n");
|
|
109934
|
+
writeFileSync6(join7(params.codexHome, "config.toml"), config3, { mode: 384 });
|
|
109935
|
+
log2.info(`\xBB codex config: sandbox=${sandboxMode}, nativeShell=${shellEnabled}`);
|
|
109936
|
+
}
|
|
109937
|
+
function toTodoWriteInput(item) {
|
|
109938
|
+
return {
|
|
109939
|
+
todos: item.items.map((todo, index) => ({
|
|
109940
|
+
id: String(index),
|
|
109941
|
+
content: todo.text,
|
|
109942
|
+
status: todo.completed ? "completed" : "pending"
|
|
109943
|
+
}))
|
|
109944
|
+
};
|
|
109945
|
+
}
|
|
109946
|
+
async function runCodex2(params) {
|
|
109947
|
+
const startTime = performance6.now();
|
|
109948
|
+
const thinkingTimer = new ThinkingTimer();
|
|
109949
|
+
const output = new TailBuffer(DEFAULT_MAX_RETAINED_BYTES);
|
|
109950
|
+
const recentStderr = [];
|
|
109951
|
+
let eventCount = 0;
|
|
109952
|
+
let finalOutput = "";
|
|
109953
|
+
let threadId;
|
|
109954
|
+
let turnError = null;
|
|
109955
|
+
let lastProviderError = null;
|
|
109956
|
+
let stdoutBuffer = "";
|
|
109957
|
+
const tokens = { input: 0, cacheRead: 0, output: 0 };
|
|
109958
|
+
function buildUsage2() {
|
|
109959
|
+
if (tokens.input === 0 && tokens.output === 0) return void 0;
|
|
109960
|
+
return {
|
|
109961
|
+
agent: "codex",
|
|
109962
|
+
inputTokens: tokens.input,
|
|
109963
|
+
outputTokens: tokens.output,
|
|
109964
|
+
cacheReadTokens: tokens.cacheRead || void 0
|
|
109965
|
+
};
|
|
109966
|
+
}
|
|
109967
|
+
function onItem(item, phase) {
|
|
109968
|
+
switch (item.type) {
|
|
109969
|
+
case "agent_message":
|
|
109970
|
+
if (phase === "completed" && item.text.trim()) {
|
|
109971
|
+
finalOutput = item.text.trim();
|
|
109972
|
+
log2.box(finalOutput, { title: "Pullfrog" });
|
|
109973
|
+
}
|
|
109974
|
+
return;
|
|
109975
|
+
case "reasoning":
|
|
109976
|
+
if (phase === "completed" && item.text.trim()) {
|
|
109977
|
+
log2.box(item.text.trim(), { title: "Pullfrog" });
|
|
109978
|
+
}
|
|
109979
|
+
return;
|
|
109980
|
+
case "command_execution":
|
|
109981
|
+
if (phase === "started") {
|
|
109982
|
+
thinkingTimer.markToolCall();
|
|
109983
|
+
log2.toolCall({ toolName: "shell", input: { command: item.command } });
|
|
109984
|
+
return;
|
|
109985
|
+
}
|
|
109986
|
+
thinkingTimer.markToolResult();
|
|
109987
|
+
log2.startGroup("shell output");
|
|
109988
|
+
log2.info(item.aggregated_output || "");
|
|
109989
|
+
log2.endGroup();
|
|
109990
|
+
return;
|
|
109991
|
+
case "mcp_tool_call":
|
|
109992
|
+
if (phase === "started") {
|
|
109993
|
+
thinkingTimer.markToolCall();
|
|
109994
|
+
params.onToolUse?.({ toolName: item.tool, input: item.arguments });
|
|
109995
|
+
log2.toolCall({ toolName: `${item.server}__${item.tool}`, input: item.arguments });
|
|
109996
|
+
if (item.tool.includes("report_progress")) params.todoTracker?.cancel();
|
|
109997
|
+
return;
|
|
109998
|
+
}
|
|
109999
|
+
thinkingTimer.markToolResult();
|
|
110000
|
+
if (item.error) log2.info(`\xBB tool error: ${item.error.message}`);
|
|
110001
|
+
return;
|
|
110002
|
+
case "file_change":
|
|
110003
|
+
if (phase === "completed") {
|
|
110004
|
+
const paths = item.changes.map((c2) => `${c2.kind} ${c2.path}`).join(", ");
|
|
110005
|
+
log2.info(`\xBB apply_patch (${item.status}): ${paths}`);
|
|
110006
|
+
}
|
|
110007
|
+
return;
|
|
110008
|
+
case "web_search":
|
|
110009
|
+
if (phase === "started") log2.toolCall({ toolName: "web_search", input: item.query });
|
|
110010
|
+
return;
|
|
110011
|
+
case "todo_list":
|
|
110012
|
+
if (params.todoTracker?.enabled) params.todoTracker.update(toTodoWriteInput(item));
|
|
110013
|
+
return;
|
|
110014
|
+
case "error":
|
|
110015
|
+
log2.info(`\xBB ${item.message}`);
|
|
110016
|
+
return;
|
|
110017
|
+
default:
|
|
110018
|
+
item;
|
|
110019
|
+
}
|
|
110020
|
+
}
|
|
110021
|
+
function onEvent(event) {
|
|
110022
|
+
switch (event.type) {
|
|
110023
|
+
case "thread.started":
|
|
110024
|
+
threadId = event.thread_id;
|
|
110025
|
+
return;
|
|
110026
|
+
case "turn.completed":
|
|
110027
|
+
tokens.input += event.usage.input_tokens ?? 0;
|
|
110028
|
+
tokens.cacheRead += event.usage.cached_input_tokens ?? 0;
|
|
110029
|
+
tokens.output += event.usage.output_tokens ?? 0;
|
|
110030
|
+
return;
|
|
110031
|
+
case "turn.failed":
|
|
110032
|
+
turnError = event.error.message;
|
|
110033
|
+
log2.info(`\xBB turn failed: ${turnError}`);
|
|
110034
|
+
return;
|
|
110035
|
+
case "error":
|
|
110036
|
+
turnError = event.message;
|
|
110037
|
+
log2.info(`\xBB codex error: ${event.message}`);
|
|
110038
|
+
return;
|
|
110039
|
+
case "item.started":
|
|
110040
|
+
onItem(event.item, "started");
|
|
110041
|
+
return;
|
|
110042
|
+
case "item.completed":
|
|
110043
|
+
onItem(event.item, "completed");
|
|
110044
|
+
return;
|
|
110045
|
+
case "item.updated":
|
|
110046
|
+
if (event.item.type === "todo_list") onItem(event.item, "started");
|
|
110047
|
+
return;
|
|
110048
|
+
case "turn.started":
|
|
110049
|
+
return;
|
|
110050
|
+
default:
|
|
110051
|
+
event;
|
|
110052
|
+
}
|
|
110053
|
+
}
|
|
110054
|
+
try {
|
|
110055
|
+
const result = await spawn3({
|
|
110056
|
+
cmd: params.cliPath,
|
|
110057
|
+
args: params.args,
|
|
110058
|
+
cwd: params.cwd,
|
|
110059
|
+
env: params.env,
|
|
110060
|
+
activityTimeout: AGENT_ACTIVITY_TIMEOUT_MS,
|
|
110061
|
+
onActivityTimeout: params.onActivityTimeout,
|
|
110062
|
+
// stdin MUST be `ignore`: codex reads a piped stdin as an extra `<stdin>`
|
|
110063
|
+
// prompt block and blocks on EOF, so an inherited pipe hangs the run
|
|
110064
|
+
// before the first model call.
|
|
110065
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
110066
|
+
killGroup: true,
|
|
110067
|
+
retain: "none",
|
|
110068
|
+
onStdout: (chunk) => {
|
|
110069
|
+
output.append(chunk);
|
|
110070
|
+
markActivity();
|
|
110071
|
+
stdoutBuffer += chunk;
|
|
110072
|
+
const lines = stdoutBuffer.split("\n");
|
|
110073
|
+
stdoutBuffer = lines.pop() || "";
|
|
110074
|
+
for (const line of lines) {
|
|
110075
|
+
const trimmed = line.trim();
|
|
110076
|
+
if (!trimmed) continue;
|
|
110077
|
+
let event;
|
|
110078
|
+
try {
|
|
110079
|
+
event = JSON.parse(trimmed);
|
|
110080
|
+
} catch {
|
|
110081
|
+
log2.debug(`\xBB non-JSON stdout line: ${trimmed.substring(0, 200)}`);
|
|
110082
|
+
continue;
|
|
110083
|
+
}
|
|
110084
|
+
eventCount++;
|
|
110085
|
+
log2.debug(JSON.stringify(event, null, 2));
|
|
110086
|
+
const idleMs = getIdleMs();
|
|
110087
|
+
if (idleMs > 1e4) {
|
|
110088
|
+
log2.info(
|
|
110089
|
+
`\xBB no activity for ${(idleMs / 1e3).toFixed(1)}s (${eventCount} events processed so far)`
|
|
110090
|
+
);
|
|
110091
|
+
}
|
|
110092
|
+
markActivity();
|
|
110093
|
+
onEvent(event);
|
|
110094
|
+
}
|
|
110095
|
+
},
|
|
110096
|
+
onStderr: (chunk) => {
|
|
110097
|
+
const trimmed = chunk.trim();
|
|
110098
|
+
if (!trimmed) return;
|
|
110099
|
+
recentStderr.push(trimmed);
|
|
110100
|
+
if (recentStderr.length > MAX_STDERR_LINES) recentStderr.shift();
|
|
110101
|
+
const match3 = findProviderErrorMatch(trimmed);
|
|
110102
|
+
if (match3) {
|
|
110103
|
+
lastProviderError = match3.label;
|
|
110104
|
+
log2.info(`\xBB provider error detected (${match3.label}): ${match3.excerpt}`);
|
|
110105
|
+
} else {
|
|
110106
|
+
log2.debug(trimmed);
|
|
110107
|
+
}
|
|
110108
|
+
}
|
|
110109
|
+
});
|
|
110110
|
+
const duration4 = performance6.now() - startTime;
|
|
110111
|
+
log2.info(`\xBB codex completed in ${Math.round(duration4)}ms with exit code ${result.exitCode}`);
|
|
110112
|
+
const usage = buildUsage2();
|
|
110113
|
+
if (usage) {
|
|
110114
|
+
logTokenTable({
|
|
110115
|
+
input: tokens.input - tokens.cacheRead,
|
|
110116
|
+
cacheRead: tokens.cacheRead,
|
|
110117
|
+
cacheWrite: 0,
|
|
110118
|
+
output: tokens.output
|
|
110119
|
+
});
|
|
110120
|
+
}
|
|
110121
|
+
if (result.exitCode !== 0 || turnError) {
|
|
110122
|
+
const stderrSnapshot = recentStderr.join("\n");
|
|
110123
|
+
const error52 = turnError || stderrSnapshot || lastProviderError && `provider error: ${lastProviderError}` || `unknown error - no output from Codex CLI (exit ${result.exitCode})`;
|
|
110124
|
+
log2.error(`codex exited with code ${result.exitCode}: ${error52}`);
|
|
110125
|
+
return { success: false, output: finalOutput || output.toString(), error: error52, usage, threadId };
|
|
110126
|
+
}
|
|
110127
|
+
return { success: true, output: finalOutput || output.toString(), usage, threadId };
|
|
110128
|
+
} catch (error52) {
|
|
110129
|
+
const duration4 = performance6.now() - startTime;
|
|
110130
|
+
const message = error52 instanceof Error ? error52.message : String(error52);
|
|
110131
|
+
const isActivityTimeout = error52 instanceof SpawnTimeoutError && error52.code === SPAWN_ACTIVITY_TIMEOUT_CODE;
|
|
110132
|
+
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`;
|
|
110133
|
+
log2.info(
|
|
110134
|
+
`\xBB codex ${isActivityTimeout ? "hung" : "failed"} after ${(duration4 / 1e3).toFixed(1)}s: ${message}`
|
|
110135
|
+
);
|
|
110136
|
+
log2.info(`\xBB diagnosis: ${diagnosis}`);
|
|
110137
|
+
if (recentStderr.length > 0) log2.info(`\xBB recent stderr:
|
|
110138
|
+
${recentStderr.join("\n")}`);
|
|
110139
|
+
return {
|
|
110140
|
+
success: false,
|
|
110141
|
+
output: finalOutput || output.toString(),
|
|
110142
|
+
error: `${message} [${diagnosis}]`,
|
|
110143
|
+
usage: buildUsage2(),
|
|
110144
|
+
threadId
|
|
110145
|
+
};
|
|
110146
|
+
}
|
|
110147
|
+
}
|
|
110148
|
+
var codex = agent({
|
|
110149
|
+
name: "codex",
|
|
110150
|
+
install: installCodexCli,
|
|
110151
|
+
run: async (ctx) => {
|
|
110152
|
+
const cliPath = await installCodexCli();
|
|
110153
|
+
warnIfNativeEditsUnavailable(ctx);
|
|
110154
|
+
const codexHomeAuth = installCodexHome();
|
|
110155
|
+
const codexHome = codexHomeAuth?.codexHome ?? join7(ctx.tmpdir, ".codex");
|
|
110156
|
+
mkdirSync6(codexHome, { recursive: true });
|
|
110157
|
+
const effort = resolveRunEffort(ctx);
|
|
110158
|
+
if (effort.rung && !CODEX_EFFORTS.includes(effort.rung)) {
|
|
110159
|
+
log2.warning(`\xBB effort ${effort.rung} not sent \u2014 codex doesn't accept that level`);
|
|
110160
|
+
}
|
|
110161
|
+
writeCodexConfig({
|
|
110162
|
+
ctx,
|
|
110163
|
+
codexHome,
|
|
110164
|
+
model: resolveCodexModel(ctx),
|
|
110165
|
+
effortRung: effort.rung && CODEX_EFFORTS.includes(effort.rung) ? effort.rung : void 0
|
|
110166
|
+
});
|
|
110167
|
+
if (codexHomeAuth) {
|
|
110168
|
+
core2.saveState(
|
|
110169
|
+
"codex_writeback",
|
|
110170
|
+
JSON.stringify({
|
|
110171
|
+
apiToken: ctx.apiToken,
|
|
110172
|
+
authPath: codexHomeAuth.authPath,
|
|
110173
|
+
originalRefresh: codexHomeAuth.originalRefresh
|
|
110174
|
+
})
|
|
110175
|
+
);
|
|
110176
|
+
}
|
|
110177
|
+
const baseEnv = ctx.payload.shell === "enabled" ? process.env : filterEnv();
|
|
110178
|
+
const env2 = {
|
|
110179
|
+
...baseEnv,
|
|
110180
|
+
CODEX_HOME: codexHome,
|
|
110181
|
+
PWD: process.cwd()
|
|
110182
|
+
};
|
|
110183
|
+
delete env2.CODEX_API_KEY;
|
|
110184
|
+
if (codexHomeAuth) {
|
|
110185
|
+
delete env2.OPENAI_API_KEY;
|
|
110186
|
+
} else if (process.env.OPENAI_API_KEY) {
|
|
110187
|
+
env2.CODEX_API_KEY = process.env.OPENAI_API_KEY;
|
|
110188
|
+
}
|
|
110189
|
+
const securityFlags = securityOverrideFlags({
|
|
110190
|
+
ctx,
|
|
110191
|
+
sandboxMode: ctx.payload.push === "disabled" ? "read-only" : "workspace-write",
|
|
110192
|
+
repoDir: process.cwd(),
|
|
110193
|
+
mcpServerUrl: ctx.mcpServerUrl,
|
|
110194
|
+
model: resolveCodexModel(ctx),
|
|
110195
|
+
effortRung: effort.rung && CODEX_EFFORTS.includes(effort.rung) ? effort.rung : void 0
|
|
110196
|
+
});
|
|
110197
|
+
const runnerArgs = { cliPath, cwd: process.cwd(), env: env2, todoTracker: ctx.todoTracker };
|
|
110198
|
+
const initial = await runCodex2({
|
|
110199
|
+
...runnerArgs,
|
|
110200
|
+
args: [...securityFlags, "exec", "--json", ctx.instructions.full],
|
|
110201
|
+
onActivityTimeout: ctx.onActivityTimeout,
|
|
110202
|
+
onToolUse: ctx.onToolUse
|
|
110203
|
+
});
|
|
110204
|
+
const result = await runPostRunRetryLoop({
|
|
110205
|
+
ctx,
|
|
110206
|
+
initialResult: initial,
|
|
110207
|
+
initialUsage: initial.usage,
|
|
110208
|
+
reflectionPrompt: buildReflectionPrompt(ctx.toolState),
|
|
110209
|
+
// a resume needs the thread codex recorded. without one there is nothing
|
|
110210
|
+
// to continue, and `resume --last` would be worse than not resuming: it
|
|
110211
|
+
// picks the newest recorded session in this cwd, which on a self-hosted
|
|
110212
|
+
// runner with a shared CODEX_HOME is somebody else's run.
|
|
110213
|
+
canResume: (r2) => r2.threadId !== void 0,
|
|
110214
|
+
resume: async (c2) => runCodex2({
|
|
110215
|
+
...runnerArgs,
|
|
110216
|
+
args: [
|
|
110217
|
+
...securityFlags,
|
|
110218
|
+
"exec",
|
|
110219
|
+
"resume",
|
|
110220
|
+
"--json",
|
|
110221
|
+
c2.previousResult.threadId ?? "",
|
|
110222
|
+
c2.prompt
|
|
110223
|
+
]
|
|
110224
|
+
})
|
|
110225
|
+
});
|
|
110226
|
+
if (result.success) {
|
|
110227
|
+
await ctx.todoTracker?.flush();
|
|
110228
|
+
} else {
|
|
110229
|
+
ctx.todoTracker?.cancel();
|
|
110230
|
+
}
|
|
110231
|
+
return result;
|
|
110232
|
+
}
|
|
110233
|
+
});
|
|
110234
|
+
|
|
110235
|
+
// agents/opencode.ts
|
|
110236
|
+
var core3 = __toESM(require_core(), 1);
|
|
110237
|
+
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
110238
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
110239
|
+
import { join as join8 } from "node:path";
|
|
110240
|
+
import { performance as performance7 } from "node:perf_hooks";
|
|
110241
|
+
|
|
109480
110242
|
// node_modules/.pnpm/@opencode-ai+sdk@1.18.5/node_modules/@opencode-ai/sdk/dist/v2/gen/core/serverSentEvents.gen.js
|
|
109481
110243
|
var createSseClient = ({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url: url4, ...options }) => {
|
|
109482
110244
|
let lastEventId;
|
|
@@ -114883,71 +115645,6 @@ var import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
|
114883
115645
|
// agents/opencode.ts
|
|
114884
115646
|
var import_undici = __toESM(require_undici2(), 1);
|
|
114885
115647
|
|
|
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
115648
|
// utils/worktree.ts
|
|
114952
115649
|
async function dirtyTrackedPaths(params = {}) {
|
|
114953
115650
|
const result = await spawn3({
|
|
@@ -115215,6 +115912,30 @@ function openAICompatibleProvider(model) {
|
|
|
115215
115912
|
}
|
|
115216
115913
|
};
|
|
115217
115914
|
}
|
|
115915
|
+
function azureProvider(model) {
|
|
115916
|
+
const prefix = `${AZURE_PROVIDER}/`;
|
|
115917
|
+
if (!model?.startsWith(prefix)) return {};
|
|
115918
|
+
const deployment = model.slice(prefix.length);
|
|
115919
|
+
return {
|
|
115920
|
+
[AZURE_PROVIDER]: {
|
|
115921
|
+
// always sent: opencode reads it as `Boolean(options?.useCompletionUrls)`,
|
|
115922
|
+
// so `false` and absent are the same, and the deep merge keeps the native
|
|
115923
|
+
// loader's `resourceName` either way.
|
|
115924
|
+
options: {
|
|
115925
|
+
useCompletionUrls: process.env[AZURE_USE_CHAT_COMPLETIONS_ENV]?.trim() === "true"
|
|
115926
|
+
},
|
|
115927
|
+
models: {
|
|
115928
|
+
[deployment]: {
|
|
115929
|
+
name: deployment,
|
|
115930
|
+
limit: {
|
|
115931
|
+
context: Number(process.env[AZURE_CONTEXT_ENV]),
|
|
115932
|
+
output: Number(process.env[AZURE_MAX_OUTPUT_ENV])
|
|
115933
|
+
}
|
|
115934
|
+
}
|
|
115935
|
+
}
|
|
115936
|
+
}
|
|
115937
|
+
};
|
|
115938
|
+
}
|
|
115218
115939
|
var KIMI_ENFORCERLESS_PROVIDERS = ["siliconflow", "together"];
|
|
115219
115940
|
function kimiOpenRouterProviderOverrides() {
|
|
115220
115941
|
return Object.fromEntries(
|
|
@@ -115306,7 +116027,8 @@ function buildSecurityConfig(ctx, model) {
|
|
|
115306
116027
|
// see opencodeShared.ts.
|
|
115307
116028
|
provider: {
|
|
115308
116029
|
openrouter: { models: kimiOpenRouterProviderOverrides() },
|
|
115309
|
-
...openAICompatibleProvider(model)
|
|
116030
|
+
...openAICompatibleProvider(model),
|
|
116031
|
+
...azureProvider(model)
|
|
115310
116032
|
}
|
|
115311
116033
|
};
|
|
115312
116034
|
if (model) {
|
|
@@ -115474,7 +116196,7 @@ function isModelOutput(ctx, part) {
|
|
|
115474
116196
|
}
|
|
115475
116197
|
async function dispatchEvent(ctx, event) {
|
|
115476
116198
|
if (event.type === "message.part.updated") {
|
|
115477
|
-
ctx.lastEventAt =
|
|
116199
|
+
ctx.lastEventAt = performance7.now();
|
|
115478
116200
|
if (isModelOutput(ctx, event.properties.part)) ctx.sawModelOutput = true;
|
|
115479
116201
|
await onPartUpdated(ctx, event.properties.part);
|
|
115480
116202
|
return;
|
|
@@ -115541,7 +116263,7 @@ async function onToolPart(ctx, part, label, isOrchestrator) {
|
|
|
115541
116263
|
if (toolName === "task" && status === "running" && isOrchestrator && !ctx.taskDispatchByCallID.has(toolId)) {
|
|
115542
116264
|
const input = part.state.input ?? {};
|
|
115543
116265
|
const dispatched = ctx.labeler.recordTaskDispatch(input);
|
|
115544
|
-
ctx.taskDispatchByCallID.set(toolId, { label: dispatched, startedAt:
|
|
116266
|
+
ctx.taskDispatchByCallID.set(toolId, { label: dispatched, startedAt: performance7.now() });
|
|
115545
116267
|
log2.info(
|
|
115546
116268
|
`\xBB dispatching subagent: ${dispatched}` + (input.subagent_type ? ` (subagent_type=${input.subagent_type})` : "")
|
|
115547
116269
|
);
|
|
@@ -115560,6 +116282,7 @@ function processTerminalToolPart(ctx, part, label, isOrchestrator) {
|
|
|
115560
116282
|
const callLine = inputFormatted !== "{}" ? `\xBB ${toolName}(${inputFormatted})` : `\xBB ${toolName}()`;
|
|
115561
116283
|
log2.info(withLabel(label, callLine));
|
|
115562
116284
|
if (isOrchestrator) ctx.loggedToolCallIDs.add(toolId);
|
|
116285
|
+
if (isOrchestrator && toolName.startsWith("pullfrog_")) ctx.mcpToolCalls++;
|
|
115563
116286
|
if (state.status === "completed") {
|
|
115564
116287
|
log2.debug(withLabel(label, ` output: ${state.output}`));
|
|
115565
116288
|
} else {
|
|
@@ -115571,7 +116294,7 @@ function processTerminalToolPart(ctx, part, label, isOrchestrator) {
|
|
|
115571
116294
|
if (toolName === "task") {
|
|
115572
116295
|
const dispatch = ctx.taskDispatchByCallID.get(toolId);
|
|
115573
116296
|
if (dispatch) {
|
|
115574
|
-
const dur = ((
|
|
116297
|
+
const dur = ((performance7.now() - dispatch.startedAt) / 1e3).toFixed(1);
|
|
115575
116298
|
const outputStr = state.status === "completed" ? state.output : "";
|
|
115576
116299
|
const preview = typeof outputStr === "string" && outputStr.length > 120 ? `${outputStr.slice(0, 120)}\u2026` : outputStr;
|
|
115577
116300
|
log2.info(
|
|
@@ -115614,7 +116337,7 @@ function withLabel(label, message) {
|
|
|
115614
116337
|
return label === ORCHESTRATOR_LABEL ? message : formatWithLabel(label, message);
|
|
115615
116338
|
}
|
|
115616
116339
|
async function runPromptTurn(ctx, params) {
|
|
115617
|
-
const start =
|
|
116340
|
+
const start = performance7.now();
|
|
115618
116341
|
const turnStartMs = Date.now();
|
|
115619
116342
|
ctx.currentTurn = newTurn();
|
|
115620
116343
|
const turn = ctx.currentTurn;
|
|
@@ -115648,7 +116371,7 @@ async function runPromptTurn(ctx, params) {
|
|
|
115648
116371
|
} catch (err) {
|
|
115649
116372
|
networkError = err instanceof Error ? err.message : String(err);
|
|
115650
116373
|
}
|
|
115651
|
-
const durationMs =
|
|
116374
|
+
const durationMs = performance7.now() - start;
|
|
115652
116375
|
const aggregatedUsage = await aggregateTurnUsage(ctx, turnStartMs);
|
|
115653
116376
|
const usage = aggregatedUsage ?? buildUsage(turn, assistant);
|
|
115654
116377
|
const finalText = turn.finalText || extractTextFromParts(returnedParts) || "";
|
|
@@ -115798,21 +116521,28 @@ function formatConfigError(name, data) {
|
|
|
115798
116521
|
).join("");
|
|
115799
116522
|
return `${name}${detail}${bullets}`;
|
|
115800
116523
|
}
|
|
116524
|
+
var WATCHDOG_SALVAGE_PROMPT = "Your previous turn was cut off mid-response by a provider stall. Nothing you had not already submitted through a tool was saved. Continue from where you stopped and submit your work now \u2014 do not restart your analysis.";
|
|
115801
116525
|
function startInnerActivityWatchdog(params) {
|
|
115802
116526
|
let fired = false;
|
|
116527
|
+
let everFired = false;
|
|
115803
116528
|
const id = setInterval(() => {
|
|
115804
116529
|
if (fired) return;
|
|
115805
|
-
const idleMs =
|
|
115806
|
-
const
|
|
116530
|
+
const idleMs = performance7.now() - params.ctx.lastEventAt;
|
|
116531
|
+
const compiledMs = params.ctx.sawModelOutput ? params.timeoutMs : AGENT_FIRST_EVENT_TIMEOUT_MS;
|
|
116532
|
+
const budgetMs = everFired ? compiledMs : watchdogBudgetMs(
|
|
116533
|
+
compiledMs,
|
|
116534
|
+
params.ctx.sawModelOutput ? "PULLFROG_E2E_ACTIVITY_TIMEOUT_MS" : "PULLFROG_E2E_FIRST_EVENT_TIMEOUT_MS"
|
|
116535
|
+
);
|
|
115807
116536
|
if (idleMs <= budgetMs) return;
|
|
115808
116537
|
fired = true;
|
|
116538
|
+
everFired = true;
|
|
115809
116539
|
const idleSec = Math.round(idleMs / 1e3);
|
|
115810
116540
|
params.ctx.diagnostic.idleSec = idleSec;
|
|
115811
116541
|
params.ctx.diagnostic.sawModelOutput = params.ctx.sawModelOutput;
|
|
115812
116542
|
log2.info(
|
|
115813
116543
|
params.ctx.sawModelOutput ? `\xBB no opencode events for ${idleSec}s \u2014 aborting in-flight prompt and notifying harness` : `\xBB no opencode events for ${idleSec}s \u2014 the provider never returned a first token; aborting in-flight prompt and notifying harness`
|
|
115814
116544
|
);
|
|
115815
|
-
params.
|
|
116545
|
+
params.abortTurn();
|
|
115816
116546
|
try {
|
|
115817
116547
|
params.ctx.onActivityTimeout?.();
|
|
115818
116548
|
} catch (err) {
|
|
@@ -115822,7 +116552,22 @@ function startInnerActivityWatchdog(params) {
|
|
|
115822
116552
|
}
|
|
115823
116553
|
}, 5e3);
|
|
115824
116554
|
id.unref?.();
|
|
115825
|
-
return {
|
|
116555
|
+
return {
|
|
116556
|
+
stop: () => clearInterval(id),
|
|
116557
|
+
/**
|
|
116558
|
+
* Start a turn's idle budget from now. The clock must be reset with the
|
|
116559
|
+
* latch: `lastEventAt` only advances on model output, so a turn following a
|
|
116560
|
+
* stall would inherit the full stalled interval and be aborted on the very
|
|
116561
|
+
* next 5s tick — killing the salvage before the provider could answer. It
|
|
116562
|
+
* is the right semantics for an ordinary resume too, whose budget should
|
|
116563
|
+
* not be pre-spent by the post-run gate checks that ran between turns.
|
|
116564
|
+
*/
|
|
116565
|
+
armForTurn: () => {
|
|
116566
|
+
fired = false;
|
|
116567
|
+
params.ctx.lastEventAt = performance7.now();
|
|
116568
|
+
},
|
|
116569
|
+
firedThisTurn: () => fired
|
|
116570
|
+
};
|
|
115826
116571
|
}
|
|
115827
116572
|
var opencode = agent({
|
|
115828
116573
|
name: "opencode",
|
|
@@ -115841,12 +116586,12 @@ var opencode = agent({
|
|
|
115841
116586
|
const model = vertexModel ?? (isBedrockRoute ? `amazon-bedrock/${rawModel}` : rawModel);
|
|
115842
116587
|
const homeEnv = {
|
|
115843
116588
|
HOME: ctx.tmpdir,
|
|
115844
|
-
XDG_CONFIG_HOME:
|
|
116589
|
+
XDG_CONFIG_HOME: join8(ctx.tmpdir, ".config")
|
|
115845
116590
|
};
|
|
115846
|
-
const opencodePluginDir =
|
|
115847
|
-
|
|
115848
|
-
|
|
115849
|
-
|
|
116591
|
+
const opencodePluginDir = join8(homeEnv.XDG_CONFIG_HOME, "opencode", "plugin");
|
|
116592
|
+
mkdirSync7(opencodePluginDir, { recursive: true });
|
|
116593
|
+
writeFileSync7(
|
|
116594
|
+
join8(opencodePluginDir, PULLFROG_OPENCODE_GATE_PLUGIN_FILENAME),
|
|
115850
116595
|
buildOpencodeSubagentGateSource(ctx.subagentDeniedTools)
|
|
115851
116596
|
);
|
|
115852
116597
|
const agentBrowserVersion = getDevDependencyVersion("agent-browser");
|
|
@@ -115877,12 +116622,13 @@ var opencode = agent({
|
|
|
115877
116622
|
if (codexAuth) {
|
|
115878
116623
|
env2.XDG_DATA_HOME = codexAuth.xdgDataHome;
|
|
115879
116624
|
delete env2.OPENAI_API_KEY;
|
|
115880
|
-
|
|
116625
|
+
core3.saveState(
|
|
115881
116626
|
"codex_writeback",
|
|
115882
116627
|
JSON.stringify({
|
|
115883
116628
|
apiToken: ctx.apiToken,
|
|
115884
116629
|
authPath: codexAuth.authPath,
|
|
115885
|
-
originalRefresh: codexAuth.originalRefresh
|
|
116630
|
+
originalRefresh: codexAuth.originalRefresh,
|
|
116631
|
+
originalIdToken: codexAuth.originalIdToken
|
|
115886
116632
|
})
|
|
115887
116633
|
);
|
|
115888
116634
|
}
|
|
@@ -115933,14 +116679,16 @@ var opencode = agent({
|
|
|
115933
116679
|
variant: effort.rung,
|
|
115934
116680
|
todoTracker: ctx.todoTracker,
|
|
115935
116681
|
onActivityTimeout: ctx.onActivityTimeout,
|
|
116682
|
+
onTurnRecovered: ctx.onTurnRecovered,
|
|
115936
116683
|
onToolUse: ctx.onToolUse,
|
|
115937
116684
|
currentTurn: null,
|
|
115938
116685
|
eventCount: 0,
|
|
115939
|
-
lastEventAt:
|
|
116686
|
+
lastEventAt: performance7.now(),
|
|
115940
116687
|
sawModelOutput: false,
|
|
115941
116688
|
promptMessageID: void 0,
|
|
115942
116689
|
taskDispatchByCallID: /* @__PURE__ */ new Map(),
|
|
115943
116690
|
loggedToolCallIDs: /* @__PURE__ */ new Set(),
|
|
116691
|
+
mcpToolCalls: 0,
|
|
115944
116692
|
recentStderr: server.recentStderr,
|
|
115945
116693
|
diagnostic: {
|
|
115946
116694
|
label: "Pullfrog",
|
|
@@ -115964,9 +116712,14 @@ var opencode = agent({
|
|
|
115964
116712
|
}
|
|
115965
116713
|
}
|
|
115966
116714
|
});
|
|
115967
|
-
const
|
|
115968
|
-
|
|
115969
|
-
|
|
116715
|
+
const runController = new AbortController();
|
|
116716
|
+
let turnController = new AbortController();
|
|
116717
|
+
const nextTurnSignal = () => {
|
|
116718
|
+
turnController = new AbortController();
|
|
116719
|
+
return AbortSignal.any([runController.signal, turnController.signal]);
|
|
116720
|
+
};
|
|
116721
|
+
const eventLoopPromise = consumeEvents(runnerCtx, runController.signal).catch((err) => {
|
|
116722
|
+
if (!runController.signal.aborted) {
|
|
115970
116723
|
log2.warning(
|
|
115971
116724
|
`\xBB opencode event subscription ended: ${err instanceof Error ? err.message : String(err)}`
|
|
115972
116725
|
);
|
|
@@ -115982,31 +116735,48 @@ var opencode = agent({
|
|
|
115982
116735
|
// a long synchronous tool call (no part.updated while it runs) can't
|
|
115983
116736
|
// false-positive it.
|
|
115984
116737
|
timeoutMs: AGENT_ACTIVITY_TIMEOUT_MS,
|
|
115985
|
-
|
|
116738
|
+
abortTurn: () => turnController.abort()
|
|
115986
116739
|
});
|
|
115987
116740
|
const sdkModel = parseModel2(model);
|
|
116741
|
+
let salvagesLeft = 1;
|
|
116742
|
+
const runTurn = async (text) => {
|
|
116743
|
+
const attempt = (prompt) => {
|
|
116744
|
+
watchdog.armForTurn();
|
|
116745
|
+
return runTurnGuarded(
|
|
116746
|
+
runnerCtx,
|
|
116747
|
+
() => runPromptTurn(runnerCtx, { text: prompt, model: sdkModel, signal: nextTurnSignal() })
|
|
116748
|
+
);
|
|
116749
|
+
};
|
|
116750
|
+
const standDownIfRecovered = (turn) => {
|
|
116751
|
+
if (watchdog.firedThisTurn() && turn.success) ctx.onTurnRecovered?.();
|
|
116752
|
+
return turn;
|
|
116753
|
+
};
|
|
116754
|
+
const result = await attempt(text);
|
|
116755
|
+
if (!watchdog.firedThisTurn()) return result;
|
|
116756
|
+
if (result.success) return standDownIfRecovered(result);
|
|
116757
|
+
if (salvagesLeft <= 0) return result;
|
|
116758
|
+
salvagesLeft--;
|
|
116759
|
+
ctx.onTurnRecovered?.();
|
|
116760
|
+
log2.info("\xBB activity watchdog cut the turn off \u2014 re-prompting once on the same session");
|
|
116761
|
+
const mcpCallsBefore = runnerCtx.mcpToolCalls;
|
|
116762
|
+
const salvaged = await attempt(WATCHDOG_SALVAGE_PROMPT);
|
|
116763
|
+
const usage = mergeAgentUsage(result.usage, salvaged.usage);
|
|
116764
|
+
if (runnerCtx.mcpToolCalls === mcpCallsBefore) {
|
|
116765
|
+
log2.info(
|
|
116766
|
+
"\xBB salvage turn reached no Pullfrog tool \u2014 keeping the activity-timeout failure"
|
|
116767
|
+
);
|
|
116768
|
+
return { ...result, usage };
|
|
116769
|
+
}
|
|
116770
|
+
return standDownIfRecovered({ ...salvaged, usage });
|
|
116771
|
+
};
|
|
115988
116772
|
try {
|
|
115989
|
-
const initial = await
|
|
115990
|
-
runnerCtx,
|
|
115991
|
-
() => runPromptTurn(runnerCtx, {
|
|
115992
|
-
text: ctx.instructions.full,
|
|
115993
|
-
model: sdkModel,
|
|
115994
|
-
signal: abortController.signal
|
|
115995
|
-
})
|
|
115996
|
-
);
|
|
116773
|
+
const initial = await runTurn(ctx.instructions.full);
|
|
115997
116774
|
const result = await runPostRunRetryLoop({
|
|
115998
116775
|
ctx,
|
|
115999
116776
|
initialResult: initial,
|
|
116000
116777
|
initialUsage: initial.usage,
|
|
116001
116778
|
reflectionPrompt: buildReflectionPrompt(ctx.toolState),
|
|
116002
|
-
resume: async (c2) =>
|
|
116003
|
-
runnerCtx,
|
|
116004
|
-
() => runPromptTurn(runnerCtx, {
|
|
116005
|
-
text: c2.prompt,
|
|
116006
|
-
model: sdkModel,
|
|
116007
|
-
signal: abortController.signal
|
|
116008
|
-
})
|
|
116009
|
-
)
|
|
116779
|
+
resume: async (c2) => runTurn(c2.prompt)
|
|
116010
116780
|
});
|
|
116011
116781
|
if (result.success) {
|
|
116012
116782
|
await ctx.todoTracker?.flush();
|
|
@@ -116016,7 +116786,7 @@ var opencode = agent({
|
|
|
116016
116786
|
return result;
|
|
116017
116787
|
} finally {
|
|
116018
116788
|
watchdog.stop();
|
|
116019
|
-
|
|
116789
|
+
runController.abort();
|
|
116020
116790
|
await eventLoopPromise.catch(() => {
|
|
116021
116791
|
});
|
|
116022
116792
|
}
|
|
@@ -116046,7 +116816,7 @@ async function runTurnGuarded(ctx, fn2) {
|
|
|
116046
116816
|
}
|
|
116047
116817
|
|
|
116048
116818
|
// agents/index.ts
|
|
116049
|
-
var agents = { claude, opencode };
|
|
116819
|
+
var agents = { claude, codex, opencode };
|
|
116050
116820
|
|
|
116051
116821
|
// node_modules/.pnpm/@ark+util@0.56.0/node_modules/@ark/util/out/arrays.js
|
|
116052
116822
|
var liftArray = (data) => Array.isArray(data) ? data : [data];
|
|
@@ -136378,7 +137148,7 @@ var require_core$2 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
136378
137148
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
136379
137149
|
const id_1 = require_id2();
|
|
136380
137150
|
const ref_1 = require_ref2();
|
|
136381
|
-
const
|
|
137151
|
+
const core12 = [
|
|
136382
137152
|
"$schema",
|
|
136383
137153
|
"$id",
|
|
136384
137154
|
"$defs",
|
|
@@ -136388,7 +137158,7 @@ var require_core$2 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
136388
137158
|
id_1.default,
|
|
136389
137159
|
ref_1.default
|
|
136390
137160
|
];
|
|
136391
|
-
exports.default =
|
|
137161
|
+
exports.default = core12;
|
|
136392
137162
|
}));
|
|
136393
137163
|
var require_limitNumber2 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
136394
137164
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -138526,7 +139296,7 @@ var require_json_schema_2019_09 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
138526
139296
|
const metaSchema = require_schema$1();
|
|
138527
139297
|
const applicator = require_applicator$1();
|
|
138528
139298
|
const content = require_content$1();
|
|
138529
|
-
const
|
|
139299
|
+
const core12 = require_core$1();
|
|
138530
139300
|
const format2 = require_format3();
|
|
138531
139301
|
const metadata = require_meta_data$1();
|
|
138532
139302
|
const validation = require_validation$1();
|
|
@@ -138536,7 +139306,7 @@ var require_json_schema_2019_09 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
138536
139306
|
metaSchema,
|
|
138537
139307
|
applicator,
|
|
138538
139308
|
content,
|
|
138539
|
-
|
|
139309
|
+
core12,
|
|
138540
139310
|
with$data(this, format2),
|
|
138541
139311
|
metadata,
|
|
138542
139312
|
with$data(this, validation)
|
|
@@ -138976,7 +139746,7 @@ var require_json_schema_2020_12 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
138976
139746
|
const applicator = require_applicator2();
|
|
138977
139747
|
const unevaluated = require_unevaluated();
|
|
138978
139748
|
const content = require_content();
|
|
138979
|
-
const
|
|
139749
|
+
const core12 = require_core4();
|
|
138980
139750
|
const format2 = require_format_annotation();
|
|
138981
139751
|
const metadata = require_meta_data();
|
|
138982
139752
|
const validation = require_validation2();
|
|
@@ -138987,7 +139757,7 @@ var require_json_schema_2020_12 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
138987
139757
|
applicator,
|
|
138988
139758
|
unevaluated,
|
|
138989
139759
|
content,
|
|
138990
|
-
|
|
139760
|
+
core12,
|
|
138991
139761
|
with$data(this, format2),
|
|
138992
139762
|
metadata,
|
|
138993
139763
|
with$data(this, validation)
|
|
@@ -150429,7 +151199,7 @@ var require_core$22 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
150429
151199
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
150430
151200
|
const id_1 = require_id3();
|
|
150431
151201
|
const ref_1 = require_ref3();
|
|
150432
|
-
const
|
|
151202
|
+
const core12 = [
|
|
150433
151203
|
"$schema",
|
|
150434
151204
|
"$id",
|
|
150435
151205
|
"$defs",
|
|
@@ -150439,7 +151209,7 @@ var require_core$22 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
150439
151209
|
id_1.default,
|
|
150440
151210
|
ref_1.default
|
|
150441
151211
|
];
|
|
150442
|
-
exports.default =
|
|
151212
|
+
exports.default = core12;
|
|
150443
151213
|
}));
|
|
150444
151214
|
var require_limitNumber3 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
150445
151215
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -152577,7 +153347,7 @@ var require_json_schema_2019_092 = /* @__PURE__ */ __commonJSMin2(((exports) =>
|
|
|
152577
153347
|
const metaSchema = require_schema$12();
|
|
152578
153348
|
const applicator = require_applicator$12();
|
|
152579
153349
|
const content = require_content$12();
|
|
152580
|
-
const
|
|
153350
|
+
const core12 = require_core$12();
|
|
152581
153351
|
const format2 = require_format4();
|
|
152582
153352
|
const metadata = require_meta_data$12();
|
|
152583
153353
|
const validation = require_validation$12();
|
|
@@ -152587,7 +153357,7 @@ var require_json_schema_2019_092 = /* @__PURE__ */ __commonJSMin2(((exports) =>
|
|
|
152587
153357
|
metaSchema,
|
|
152588
153358
|
applicator,
|
|
152589
153359
|
content,
|
|
152590
|
-
|
|
153360
|
+
core12,
|
|
152591
153361
|
with$data(this, format2),
|
|
152592
153362
|
metadata,
|
|
152593
153363
|
with$data(this, validation)
|
|
@@ -153027,7 +153797,7 @@ var require_json_schema_2020_122 = /* @__PURE__ */ __commonJSMin2(((exports) =>
|
|
|
153027
153797
|
const applicator = require_applicator3();
|
|
153028
153798
|
const unevaluated = require_unevaluated2();
|
|
153029
153799
|
const content = require_content2();
|
|
153030
|
-
const
|
|
153800
|
+
const core12 = require_core5();
|
|
153031
153801
|
const format2 = require_format_annotation2();
|
|
153032
153802
|
const metadata = require_meta_data2();
|
|
153033
153803
|
const validation = require_validation3();
|
|
@@ -153038,7 +153808,7 @@ var require_json_schema_2020_122 = /* @__PURE__ */ __commonJSMin2(((exports) =>
|
|
|
153038
153808
|
applicator,
|
|
153039
153809
|
unevaluated,
|
|
153040
153810
|
content,
|
|
153041
|
-
|
|
153811
|
+
core12,
|
|
153042
153812
|
with$data(this, format2),
|
|
153043
153813
|
metadata,
|
|
153044
153814
|
with$data(this, validation)
|
|
@@ -172999,123 +173769,8 @@ var pbkdf2Async = promisify(pbkdf2);
|
|
|
172999
173769
|
|
|
173000
173770
|
// utils/browser.ts
|
|
173001
173771
|
import { execFileSync as execFileSync5, spawnSync as spawnSync4 } from "node:child_process";
|
|
173002
|
-
import { existsSync as
|
|
173772
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
173003
173773
|
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
173774
|
var CHROME_PATHS = ["/usr/bin/google-chrome-stable"];
|
|
173120
173775
|
var systemChromePath;
|
|
173121
173776
|
function findSystemChromePath() {
|
|
@@ -173123,7 +173778,7 @@ function findSystemChromePath() {
|
|
|
173123
173778
|
return systemChromePath || void 0;
|
|
173124
173779
|
}
|
|
173125
173780
|
for (const p of CHROME_PATHS) {
|
|
173126
|
-
if (
|
|
173781
|
+
if (existsSync5(p)) {
|
|
173127
173782
|
systemChromePath = p;
|
|
173128
173783
|
log2.info(`found system chrome: ${p}`);
|
|
173129
173784
|
return p;
|
|
@@ -173207,8 +173862,8 @@ function closeBrowserDaemon(toolState) {
|
|
|
173207
173862
|
|
|
173208
173863
|
// mcp/checkout.ts
|
|
173209
173864
|
import { createHash as createHash2 } from "node:crypto";
|
|
173210
|
-
import { statSync, unlinkSync as unlinkSync3, writeFileSync as
|
|
173211
|
-
import { join as
|
|
173865
|
+
import { statSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "node:fs";
|
|
173866
|
+
import { join as join15 } from "node:path";
|
|
173212
173867
|
|
|
173213
173868
|
// node_modules/.pnpm/@ark+schema@0.56.0/node_modules/@ark/schema/out/shared/errors.js
|
|
173214
173869
|
var ArkError = class _ArkError extends CastableBase {
|
|
@@ -180680,8 +181335,8 @@ function ensureRepoState(toolState, init) {
|
|
|
180680
181335
|
|
|
180681
181336
|
// utils/changeImpact.ts
|
|
180682
181337
|
import { spawn as spawn4 } from "node:child_process";
|
|
180683
|
-
import { writeFileSync as
|
|
180684
|
-
import { join as
|
|
181338
|
+
import { writeFileSync as writeFileSync8 } from "node:fs";
|
|
181339
|
+
import { join as join9 } from "node:path";
|
|
180685
181340
|
var MAX_CANDIDATES = 24;
|
|
180686
181341
|
var MAX_ATOM_LENGTH = 128;
|
|
180687
181342
|
var MAX_ATOMS = 12;
|
|
@@ -181028,8 +181683,8 @@ async function createChangeImpactArtifact(ctx, params) {
|
|
|
181028
181683
|
headSha: params.headSha,
|
|
181029
181684
|
lookupError: lookup2.error
|
|
181030
181685
|
});
|
|
181031
|
-
const path4 =
|
|
181032
|
-
|
|
181686
|
+
const path4 = join9(ctx.tmpdir, `pr-${params.pullNumber}-${params.headSha.slice(0, 7)}-impact.md`);
|
|
181687
|
+
writeFileSync8(path4, artifact.content);
|
|
181033
181688
|
return {
|
|
181034
181689
|
path: path4,
|
|
181035
181690
|
candidateCount: candidates.selected.length,
|
|
@@ -181281,8 +181936,8 @@ function readNumber(params) {
|
|
|
181281
181936
|
// utils/gitAuth.ts
|
|
181282
181937
|
import { execSync } from "node:child_process";
|
|
181283
181938
|
import { createHash } from "node:crypto";
|
|
181284
|
-
import { readFileSync as
|
|
181285
|
-
import { join as
|
|
181939
|
+
import { readFileSync as readFileSync4, realpathSync, unlinkSync } from "node:fs";
|
|
181940
|
+
import { join as join10 } from "node:path";
|
|
181286
181941
|
|
|
181287
181942
|
// utils/shell.ts
|
|
181288
181943
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
@@ -181343,7 +181998,7 @@ var TRANSIENT_AUTH_PATTERNS = [
|
|
|
181343
181998
|
];
|
|
181344
181999
|
var gitBinary;
|
|
181345
182000
|
function hashFile(path4) {
|
|
181346
|
-
return createHash("sha256").update(
|
|
182001
|
+
return createHash("sha256").update(readFileSync4(path4)).digest("hex");
|
|
181347
182002
|
}
|
|
181348
182003
|
function resolveGit() {
|
|
181349
182004
|
const whichPath = execSync("which git", { encoding: "utf-8" }).trim();
|
|
@@ -181372,7 +182027,7 @@ function resolveHooksDir(cwd, gitPath) {
|
|
|
181372
182027
|
cwd,
|
|
181373
182028
|
log: false
|
|
181374
182029
|
}).trim();
|
|
181375
|
-
const hooksDir =
|
|
182030
|
+
const hooksDir = join10(commonDir, "hooks");
|
|
181376
182031
|
hooksDirCache.set(cwd, hooksDir);
|
|
181377
182032
|
return hooksDir;
|
|
181378
182033
|
}
|
|
@@ -181679,7 +182334,7 @@ function postProcessRangeDiff(raw2, contextLines = 3) {
|
|
|
181679
182334
|
}
|
|
181680
182335
|
|
|
181681
182336
|
// yes/index.ts
|
|
181682
|
-
import { performance as
|
|
182337
|
+
import { performance as performance8 } from "node:perf_hooks";
|
|
181683
182338
|
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
181684
182339
|
|
|
181685
182340
|
// node_modules/.pnpm/lru-cache@11.5.2/node_modules/lru-cache/dist/esm/node/index.min.js
|
|
@@ -182394,14 +183049,14 @@ function _op(fn2, options) {
|
|
|
182394
183049
|
`failed to create cache key${namePrefix ? ` for ${options.name}` : ""}: ${errorMessage}`
|
|
182395
183050
|
);
|
|
182396
183051
|
}
|
|
182397
|
-
const startTime =
|
|
183052
|
+
const startTime = performance8.now();
|
|
182398
183053
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
182399
183054
|
log3.debug(`${namePrefix}[${timestamp}] cache lookup started`, { key });
|
|
182400
183055
|
if (shouldCache && lruCache) {
|
|
182401
183056
|
const cached4 = lruCache.get(key);
|
|
182402
183057
|
if (cached4 !== void 0) {
|
|
182403
183058
|
if (keyMap?.get(key) === void 0) keyMap?.set(key, input);
|
|
182404
|
-
const runtime =
|
|
183059
|
+
const runtime = performance8.now() - startTime;
|
|
182405
183060
|
log3.debug(`${namePrefix}[${timestamp}] cache hit (from lru)`, {
|
|
182406
183061
|
key,
|
|
182407
183062
|
runtime: `${Math.round(runtime)}ms`
|
|
@@ -182420,12 +183075,12 @@ function _op(fn2, options) {
|
|
|
182420
183075
|
defaultCacheMiss(key);
|
|
182421
183076
|
const retries = options.retries ?? [];
|
|
182422
183077
|
let lastError;
|
|
182423
|
-
const execStartTime =
|
|
183078
|
+
const execStartTime = performance8.now();
|
|
182424
183079
|
const promise2 = (async () => {
|
|
182425
183080
|
for (let attempt = 0; attempt <= retries.length; attempt++) {
|
|
182426
183081
|
try {
|
|
182427
183082
|
const result = acceptsCtx ? await fn2(input, ctx) : await fn2(input);
|
|
182428
|
-
const execRuntime2 =
|
|
183083
|
+
const execRuntime2 = performance8.now() - execStartTime;
|
|
182429
183084
|
const skip = options.skipCache ? options.skipCache(result) : false;
|
|
182430
183085
|
if (shouldCache && lruCache && result !== null && result !== void 0 && !skip) {
|
|
182431
183086
|
lruCache.set(key, result);
|
|
@@ -182478,7 +183133,7 @@ function _op(fn2, options) {
|
|
|
182478
183133
|
}
|
|
182479
183134
|
}
|
|
182480
183135
|
}
|
|
182481
|
-
const execRuntime =
|
|
183136
|
+
const execRuntime = performance8.now() - execStartTime;
|
|
182482
183137
|
log3.debug(`${namePrefix}[${timestamp}] function failed after all retries`, {
|
|
182483
183138
|
key,
|
|
182484
183139
|
runtime: `${Math.round(execRuntime)}ms`,
|
|
@@ -182543,13 +183198,13 @@ function _op(fn2, options) {
|
|
|
182543
183198
|
|
|
182544
183199
|
// mcp/git.ts
|
|
182545
183200
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
182546
|
-
import { writeFileSync as
|
|
182547
|
-
import { join as
|
|
183201
|
+
import { writeFileSync as writeFileSync9 } from "node:fs";
|
|
183202
|
+
import { join as join13 } from "node:path";
|
|
182548
183203
|
|
|
182549
183204
|
// utils/apiCommit.ts
|
|
182550
183205
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
182551
183206
|
import { lstat, readlink } from "node:fs/promises";
|
|
182552
|
-
import { join as
|
|
183207
|
+
import { join as join11 } from "node:path";
|
|
182553
183208
|
var GITHUB_API = "https://api.github.com";
|
|
182554
183209
|
var MAX_BLOB_BYTES = 30 * 1024 * 1024;
|
|
182555
183210
|
var BLOB_UPLOAD_CONCURRENCY = 8;
|
|
@@ -182614,7 +183269,7 @@ async function assertApiCommittable(files) {
|
|
|
182614
183269
|
const root = getRepoRoot();
|
|
182615
183270
|
const attrs = $(
|
|
182616
183271
|
"git",
|
|
182617
|
-
["check-attr", "filter", "-z", "--", ...present.map((p) =>
|
|
183272
|
+
["check-attr", "filter", "-z", "--", ...present.map((p) => join11(root, p))],
|
|
182618
183273
|
{ log: false }
|
|
182619
183274
|
);
|
|
182620
183275
|
const parts = attrs.split("\0");
|
|
@@ -182626,7 +183281,7 @@ async function assertApiCommittable(files) {
|
|
|
182626
183281
|
}
|
|
182627
183282
|
}
|
|
182628
183283
|
for (const path4 of present) {
|
|
182629
|
-
const stat = await lstat(
|
|
183284
|
+
const stat = await lstat(join11(root, path4));
|
|
182630
183285
|
if (stat.isDirectory()) {
|
|
182631
183286
|
throw new Error(
|
|
182632
183287
|
`'${path4}' is a directory (nested repository or submodule?) \u2014 signed commits only support files and symlinks.`
|
|
@@ -182635,7 +183290,7 @@ async function assertApiCommittable(files) {
|
|
|
182635
183290
|
}
|
|
182636
183291
|
}
|
|
182637
183292
|
async function createBlobEntry(params) {
|
|
182638
|
-
const absPath =
|
|
183293
|
+
const absPath = join11(params.repoRoot, params.path);
|
|
182639
183294
|
const stat = await lstat(absPath);
|
|
182640
183295
|
if (stat.size > MAX_BLOB_BYTES) {
|
|
182641
183296
|
throw new Error(
|
|
@@ -182812,10 +183467,10 @@ this usually means your local branch has commits that were never pushed \u2014 s
|
|
|
182812
183467
|
}
|
|
182813
183468
|
|
|
182814
183469
|
// utils/github.ts
|
|
182815
|
-
var
|
|
183470
|
+
var core4 = __toESM(require_core(), 1);
|
|
182816
183471
|
import { createSign } from "node:crypto";
|
|
182817
183472
|
import { rename, writeFile } from "node:fs/promises";
|
|
182818
|
-
import { dirname as dirname3, join as
|
|
183473
|
+
import { dirname as dirname3, join as join12 } from "node:path";
|
|
182819
183474
|
|
|
182820
183475
|
// node_modules/.pnpm/@octokit+plugin-throttling@11.0.5_@octokit+core@7.0.7/node_modules/@octokit/plugin-throttling/dist-bundle/index.js
|
|
182821
183476
|
var import_light = __toESM(require_light(), 1);
|
|
@@ -187013,7 +187668,7 @@ async function fetchIdTokenFromStash(creds) {
|
|
|
187013
187668
|
throw new Error("ID token response has no value field");
|
|
187014
187669
|
}
|
|
187015
187670
|
if (isGitHubActions) {
|
|
187016
|
-
|
|
187671
|
+
core4.setSecret(body.value);
|
|
187017
187672
|
}
|
|
187018
187673
|
return body.value;
|
|
187019
187674
|
}
|
|
@@ -187026,7 +187681,7 @@ function translateIdTokenError(error52) {
|
|
|
187026
187681
|
var mintIdToken = op(
|
|
187027
187682
|
async () => {
|
|
187028
187683
|
try {
|
|
187029
|
-
return await
|
|
187684
|
+
return await core4.getIDToken(OIDC_AUDIENCE);
|
|
187030
187685
|
} catch (error52) {
|
|
187031
187686
|
throw translateIdTokenError(error52);
|
|
187032
187687
|
}
|
|
@@ -187235,7 +187890,7 @@ function getGitHubUsageSummary() {
|
|
|
187235
187890
|
}
|
|
187236
187891
|
async function writeGitHubUsageSummaryToFile(path4) {
|
|
187237
187892
|
const summary2 = getGitHubUsageSummary();
|
|
187238
|
-
const tmpPath =
|
|
187893
|
+
const tmpPath = join12(dirname3(path4), `.usage-summary-${process.pid}.tmp`);
|
|
187239
187894
|
await writeFile(tmpPath, JSON.stringify(summary2));
|
|
187240
187895
|
await rename(tmpPath, path4);
|
|
187241
187896
|
}
|
|
@@ -188387,8 +189042,8 @@ function countAhead(head, base, cwd) {
|
|
|
188387
189042
|
function spillGitOutput(params) {
|
|
188388
189043
|
const tempDir = process.env.PULLFROG_TEMP_DIR;
|
|
188389
189044
|
if (!tempDir) throw new Error("PULLFROG_TEMP_DIR not set");
|
|
188390
|
-
const outputPath =
|
|
188391
|
-
|
|
189045
|
+
const outputPath = join13(tempDir, `git-${params.command}-${randomUUID3().slice(0, 8)}.txt`);
|
|
189046
|
+
writeFileSync9(outputPath, params.output);
|
|
188392
189047
|
const previewByLines = params.output.split("\n").slice(0, OVERFLOW_PREVIEW_LINES).join("\n");
|
|
188393
189048
|
const preview = previewByLines.length <= OVERFLOW_PREVIEW_MAX_CHARS ? previewByLines : `${previewByLines.slice(0, OVERFLOW_PREVIEW_MAX_CHARS)}\u2026`;
|
|
188394
189049
|
log2.info(
|
|
@@ -189902,9 +190557,9 @@ async function reportReviewNodeId(ctx, params) {
|
|
|
189902
190557
|
import { execFileSync as execFileSync7, execSync as execSync2 } from "node:child_process";
|
|
189903
190558
|
import { mkdtempSync as mkdtempSync2, readdirSync, realpathSync as realpathSync2, unlinkSync as unlinkSync2 } from "node:fs";
|
|
189904
190559
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
189905
|
-
import { join as
|
|
190560
|
+
import { join as join14 } from "node:path";
|
|
189906
190561
|
function createTempDirectory() {
|
|
189907
|
-
const sharedTempDir = mkdtempSync2(
|
|
190562
|
+
const sharedTempDir = mkdtempSync2(join14(tmpdir3(), "pullfrog-"));
|
|
189908
190563
|
process.env.PULLFROG_TEMP_DIR = sharedTempDir;
|
|
189909
190564
|
log2.info(`\xBB created temp dir at ${sharedTempDir}`);
|
|
189910
190565
|
return sharedTempDir;
|
|
@@ -189949,13 +190604,13 @@ function wipeRunnerLeakSurface() {
|
|
|
189949
190604
|
return [];
|
|
189950
190605
|
}
|
|
189951
190606
|
};
|
|
189952
|
-
const fileCommandsDir =
|
|
190607
|
+
const fileCommandsDir = join14(runnerTemp, "_runner_file_commands");
|
|
189953
190608
|
for (const entry of listDir(fileCommandsDir)) {
|
|
189954
|
-
tryUnlink(
|
|
190609
|
+
tryUnlink(join14(fileCommandsDir, entry));
|
|
189955
190610
|
}
|
|
189956
190611
|
for (const entry of listDir(runnerTemp)) {
|
|
189957
190612
|
if (entry.endsWith(".sh") || /^git-credentials-.*\.config$/.test(entry)) {
|
|
189958
|
-
tryUnlink(
|
|
190613
|
+
tryUnlink(join14(runnerTemp, entry));
|
|
189959
190614
|
}
|
|
189960
190615
|
}
|
|
189961
190616
|
if (wiped.length > 0) {
|
|
@@ -190505,11 +191160,11 @@ function CheckoutPrTool(ctx) {
|
|
|
190505
191160
|
headSha: checkoutSha
|
|
190506
191161
|
});
|
|
190507
191162
|
if (incremental.status === "ok") {
|
|
190508
|
-
incrementalDiffPath =
|
|
191163
|
+
incrementalDiffPath = join15(
|
|
190509
191164
|
tempDir,
|
|
190510
191165
|
`pr-${pull_number}-${beforeShort}-${headShort}-incremental.diff`
|
|
190511
191166
|
);
|
|
190512
|
-
|
|
191167
|
+
writeFileSync10(incrementalDiffPath, incremental.diff);
|
|
190513
191168
|
log2.info(
|
|
190514
191169
|
`\xBB incremental diff computed (${incremental.diff.length} bytes) \u2192 ${incrementalDiffPath}`
|
|
190515
191170
|
);
|
|
@@ -190522,8 +191177,8 @@ function CheckoutPrTool(ctx) {
|
|
|
190522
191177
|
const diffPreview = formatResult.content.split("\n").slice(0, 100).join("\n");
|
|
190523
191178
|
log2.debug(`formatted diff preview (first 100 lines):
|
|
190524
191179
|
${diffPreview}`);
|
|
190525
|
-
const diffPath =
|
|
190526
|
-
|
|
191180
|
+
const diffPath = join15(tempDir, `pr-${pull_number}-${headShort}.diff`);
|
|
191181
|
+
writeFileSync10(diffPath, formatResult.content);
|
|
190527
191182
|
log2.debug(`wrote diff to ${diffPath} (${formatResult.content.length} bytes)`);
|
|
190528
191183
|
primary.diffCoverage = createDiffCoverageState({
|
|
190529
191184
|
diffPath,
|
|
@@ -190680,8 +191335,8 @@ ${dirty}`
|
|
|
190680
191335
|
}
|
|
190681
191336
|
|
|
190682
191337
|
// mcp/checkSuite.ts
|
|
190683
|
-
import { mkdirSync as
|
|
190684
|
-
import { join as
|
|
191338
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync11 } from "node:fs";
|
|
191339
|
+
import { join as join16 } from "node:path";
|
|
190685
191340
|
var GetCheckSuiteLogs = type({
|
|
190686
191341
|
check_suite_id: type.number.describe("the id from check_suite.id")
|
|
190687
191342
|
});
|
|
@@ -190777,8 +191432,8 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
190777
191432
|
if (!tempDir) {
|
|
190778
191433
|
throw new Error("PULLFROG_TEMP_DIR not set");
|
|
190779
191434
|
}
|
|
190780
|
-
const logsDir =
|
|
190781
|
-
|
|
191435
|
+
const logsDir = join16(tempDir, "ci-logs");
|
|
191436
|
+
mkdirSync8(logsDir, { recursive: true });
|
|
190782
191437
|
const jobResults = [];
|
|
190783
191438
|
for (const run4 of failedRuns) {
|
|
190784
191439
|
const jobs = await ctx.octokit.paginate(ctx.octokit.rest.actions.listJobsForWorkflowRun, {
|
|
@@ -190804,8 +191459,8 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
190804
191459
|
);
|
|
190805
191460
|
}
|
|
190806
191461
|
const logsText = await logsResult.text();
|
|
190807
|
-
const logPath =
|
|
190808
|
-
|
|
191462
|
+
const logPath = join16(logsDir, `job-${job.id}.log`);
|
|
191463
|
+
writeFileSync11(logPath, logsText);
|
|
190809
191464
|
const analysis = analyzeLog(logsText, 80);
|
|
190810
191465
|
const failedSteps = job.steps?.filter((s) => s.conclusion === "failure").map((s) => `Step ${s.number}: ${s.name}`) ?? [];
|
|
190811
191466
|
jobResults.push({
|
|
@@ -190853,8 +191508,8 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
190853
191508
|
}
|
|
190854
191509
|
|
|
190855
191510
|
// mcp/commitInfo.ts
|
|
190856
|
-
import { writeFileSync as
|
|
190857
|
-
import { join as
|
|
191511
|
+
import { writeFileSync as writeFileSync12 } from "node:fs";
|
|
191512
|
+
import { join as join17 } from "node:path";
|
|
190858
191513
|
var CommitInfo = type({
|
|
190859
191514
|
sha: type.string.describe("the commit SHA (full or abbreviated) to fetch")
|
|
190860
191515
|
});
|
|
@@ -190878,8 +191533,8 @@ function CommitInfoTool(ctx) {
|
|
|
190878
191533
|
"PULLFROG_TEMP_DIR not set - get_commit_info must run in pullfrog action context"
|
|
190879
191534
|
);
|
|
190880
191535
|
}
|
|
190881
|
-
const diffFile =
|
|
190882
|
-
|
|
191536
|
+
const diffFile = join17(tempDir, `commit-${sha.slice(0, 7)}.diff`);
|
|
191537
|
+
writeFileSync12(diffFile, formatResult.content);
|
|
190883
191538
|
log2.debug(`wrote commit diff to ${diffFile} (${formatResult.content.length} bytes)`);
|
|
190884
191539
|
return {
|
|
190885
191540
|
sha: data.sha,
|
|
@@ -191012,17 +191667,17 @@ function ReopenCurrentTool(ctx) {
|
|
|
191012
191667
|
}
|
|
191013
191668
|
|
|
191014
191669
|
// prep/index.ts
|
|
191015
|
-
import { performance as
|
|
191670
|
+
import { performance as performance9 } from "node:perf_hooks";
|
|
191016
191671
|
|
|
191017
191672
|
// prep/installNodeDependencies.ts
|
|
191018
|
-
import { existsSync as
|
|
191019
|
-
import { join as
|
|
191673
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
191674
|
+
import { join as join19 } from "node:path";
|
|
191020
191675
|
|
|
191021
191676
|
// utils/packageManager.ts
|
|
191022
191677
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
191023
|
-
import { existsSync as
|
|
191678
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
191024
191679
|
import { mkdir, readFile as readFile2 } from "node:fs/promises";
|
|
191025
|
-
import { delimiter, join as
|
|
191680
|
+
import { delimiter, join as join18 } from "node:path";
|
|
191026
191681
|
var SUPPORTED_NAMES = ["npm", "pnpm", "yarn", "bun"];
|
|
191027
191682
|
var COREPACK_MANAGED = ["pnpm", "yarn"];
|
|
191028
191683
|
function isSupported(name) {
|
|
@@ -191060,8 +191715,8 @@ function parseDevEnginesField(field) {
|
|
|
191060
191715
|
};
|
|
191061
191716
|
}
|
|
191062
191717
|
async function resolvePackageManagerSpec(cwd) {
|
|
191063
|
-
const pkgPath =
|
|
191064
|
-
if (!
|
|
191718
|
+
const pkgPath = join18(cwd, "package.json");
|
|
191719
|
+
if (!existsSync6(pkgPath)) return null;
|
|
191065
191720
|
let pkg;
|
|
191066
191721
|
try {
|
|
191067
191722
|
pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
|
|
@@ -191119,7 +191774,7 @@ async function currentVersion(name) {
|
|
|
191119
191774
|
return result.stdout.trim();
|
|
191120
191775
|
}
|
|
191121
191776
|
function packageManagerBinDir(tmpdir4) {
|
|
191122
|
-
return
|
|
191777
|
+
return join18(tmpdir4, "pm-bin");
|
|
191123
191778
|
}
|
|
191124
191779
|
async function ensurePackageManager(params) {
|
|
191125
191780
|
const spec = params.spec;
|
|
@@ -191182,7 +191837,7 @@ async function installFallback(name, installSpec) {
|
|
|
191182
191837
|
});
|
|
191183
191838
|
if (result.exitCode !== 0) return result.stderr || `failed to install ${name}`;
|
|
191184
191839
|
if (name === "deno") {
|
|
191185
|
-
const denoPath =
|
|
191840
|
+
const denoPath = join18(process.env.HOME || "", ".deno", "bin");
|
|
191186
191841
|
process.env.PATH = `${denoPath}:${process.env.PATH}`;
|
|
191187
191842
|
}
|
|
191188
191843
|
log2.info(`\xBB installed ${name}`);
|
|
@@ -191215,8 +191870,8 @@ async function isCommandAvailable2(command) {
|
|
|
191215
191870
|
var installNodeDependencies = {
|
|
191216
191871
|
name: "installNodeDependencies",
|
|
191217
191872
|
shouldRun: () => {
|
|
191218
|
-
const packageJsonPath =
|
|
191219
|
-
return
|
|
191873
|
+
const packageJsonPath = join19(process.cwd(), "package.json");
|
|
191874
|
+
return existsSync7(packageJsonPath);
|
|
191220
191875
|
},
|
|
191221
191876
|
run: async (options) => {
|
|
191222
191877
|
const declared = await resolvePackageManagerSpec(process.cwd());
|
|
@@ -191310,14 +191965,14 @@ ${errorMessage}`]
|
|
|
191310
191965
|
};
|
|
191311
191966
|
|
|
191312
191967
|
// prep/installPythonDependencies.ts
|
|
191313
|
-
import { existsSync as
|
|
191314
|
-
import { join as
|
|
191968
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "node:fs";
|
|
191969
|
+
import { join as join20 } from "node:path";
|
|
191315
191970
|
function declaresBuildSystem(path4) {
|
|
191316
|
-
return /^\s*\[\s*build-system\s*\]/m.test(
|
|
191971
|
+
return /^\s*\[\s*build-system\s*\]/m.test(readFileSync5(path4, "utf8"));
|
|
191317
191972
|
}
|
|
191318
191973
|
function configApplies(config3, cwd) {
|
|
191319
|
-
const path4 =
|
|
191320
|
-
return
|
|
191974
|
+
const path4 = join20(cwd, config3.file);
|
|
191975
|
+
return existsSync8(path4) && (config3.applies?.(path4) ?? true);
|
|
191321
191976
|
}
|
|
191322
191977
|
var PYTHON_CONFIGS = [
|
|
191323
191978
|
{
|
|
@@ -191471,7 +192126,7 @@ var installPythonDependencies = {
|
|
|
191471
192126
|
var prepSteps = [installNodeDependencies, installPythonDependencies];
|
|
191472
192127
|
async function runPrepPhase(options) {
|
|
191473
192128
|
log2.debug("\xBB starting prep phase...");
|
|
191474
|
-
const startTime =
|
|
192129
|
+
const startTime = performance9.now();
|
|
191475
192130
|
const results = [];
|
|
191476
192131
|
const preDirty = await dirtyTrackedPaths();
|
|
191477
192132
|
try {
|
|
@@ -191493,7 +192148,7 @@ async function runPrepPhase(options) {
|
|
|
191493
192148
|
} finally {
|
|
191494
192149
|
await restoreDirtiedSince({ before: preDirty, actor: "prep" });
|
|
191495
192150
|
}
|
|
191496
|
-
const totalDurationMs =
|
|
192151
|
+
const totalDurationMs = performance9.now() - startTime;
|
|
191497
192152
|
log2.debug(`\xBB prep phase completed (${Math.round(totalDurationMs)}ms)`);
|
|
191498
192153
|
return results;
|
|
191499
192154
|
}
|
|
@@ -191638,15 +192293,15 @@ function AwaitDependencyInstallationTool(ctx) {
|
|
|
191638
192293
|
}
|
|
191639
192294
|
|
|
191640
192295
|
// mcp/gh.ts
|
|
191641
|
-
import { mkdirSync as
|
|
191642
|
-
import { join as
|
|
192296
|
+
import { mkdirSync as mkdirSync9 } from "node:fs";
|
|
192297
|
+
import { join as join22 } from "node:path";
|
|
191643
192298
|
|
|
191644
192299
|
// mcp/shell.ts
|
|
191645
192300
|
import { spawn as spawn5, spawnSync as spawnSync6 } from "node:child_process";
|
|
191646
192301
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
191647
|
-
import { closeSync, openSync, writeFileSync as
|
|
192302
|
+
import { closeSync, openSync, writeFileSync as writeFileSync13 } from "node:fs";
|
|
191648
192303
|
import { userInfo as userInfo2 } from "node:os";
|
|
191649
|
-
import { join as
|
|
192304
|
+
import { join as join21 } from "node:path";
|
|
191650
192305
|
import { setTimeout as sleep3 } from "node:timers/promises";
|
|
191651
192306
|
var ShellParams = type({
|
|
191652
192307
|
command: "string",
|
|
@@ -191909,8 +192564,8 @@ ${spawnError}` : spawnError;
|
|
|
191909
192564
|
}
|
|
191910
192565
|
function capOutput(output) {
|
|
191911
192566
|
if (output.length <= MAX_OUTPUT_CHARS) return output;
|
|
191912
|
-
const fullPath =
|
|
191913
|
-
|
|
192567
|
+
const fullPath = join21(getTempDir(), `shell-${randomUUID4().slice(0, 8)}.log`);
|
|
192568
|
+
writeFileSync13(fullPath, output);
|
|
191914
192569
|
const elided = output.length - MAX_OUTPUT_CHARS;
|
|
191915
192570
|
return `... [${elided} chars truncated; full output saved to ${fullPath}] ...
|
|
191916
192571
|
${output.slice(-MAX_OUTPUT_CHARS)}`;
|
|
@@ -191964,8 +192619,8 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
|
|
|
191964
192619
|
if (params.background) {
|
|
191965
192620
|
const tempDir = getTempDir();
|
|
191966
192621
|
const handle = `bg-${randomUUID4().slice(0, 8)}`;
|
|
191967
|
-
const outputPath =
|
|
191968
|
-
const pidPath =
|
|
192622
|
+
const outputPath = join21(tempDir, `${handle}.log`);
|
|
192623
|
+
const pidPath = join21(tempDir, `${handle}.pid`);
|
|
191969
192624
|
const logFd = openSync(outputPath, "a");
|
|
191970
192625
|
let proc;
|
|
191971
192626
|
try {
|
|
@@ -191982,7 +192637,7 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
|
|
|
191982
192637
|
throw new Error("failed to start background process");
|
|
191983
192638
|
}
|
|
191984
192639
|
proc.unref();
|
|
191985
|
-
|
|
192640
|
+
writeFileSync13(pidPath, `${proc.pid}
|
|
191986
192641
|
`);
|
|
191987
192642
|
ctx.toolState.backgroundProcesses.set(handle, { pid: proc.pid, outputPath, pidPath });
|
|
191988
192643
|
return {
|
|
@@ -192062,8 +192717,8 @@ function GhTool(ctx) {
|
|
|
192062
192717
|
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
192718
|
parameters: GhParams,
|
|
192064
192719
|
execute: execute(async (params) => {
|
|
192065
|
-
const configDir =
|
|
192066
|
-
|
|
192720
|
+
const configDir = join22(ctx.tmpdir, "gh-config");
|
|
192721
|
+
mkdirSync9(configDir, { recursive: true });
|
|
192067
192722
|
const command = ["gh", ...params.args.map(shellQuote)].join(" ");
|
|
192068
192723
|
const result = await runSandboxed({
|
|
192069
192724
|
command,
|
|
@@ -192786,8 +193441,8 @@ function PullRequestInfoTool(ctx) {
|
|
|
192786
193441
|
}
|
|
192787
193442
|
|
|
192788
193443
|
// mcp/reviewComments.ts
|
|
192789
|
-
import { writeFileSync as
|
|
192790
|
-
import { join as
|
|
193444
|
+
import { writeFileSync as writeFileSync14 } from "node:fs";
|
|
193445
|
+
import { join as join23 } from "node:path";
|
|
192791
193446
|
var COMMENTS_PER_THREAD = 50;
|
|
192792
193447
|
var REVIEW_THREADS_QUERY = `
|
|
192793
193448
|
query ($owner: String!, $name: String!, $prNumber: Int!, $cursor: String) {
|
|
@@ -193260,8 +193915,8 @@ function GetReviewCommentsTool(ctx) {
|
|
|
193260
193915
|
throw new Error("PULLFROG_TEMP_DIR not set");
|
|
193261
193916
|
}
|
|
193262
193917
|
const filename = `review-${params.review_id}-threads.md`;
|
|
193263
|
-
const commentsPath =
|
|
193264
|
-
|
|
193918
|
+
const commentsPath = join23(tempDir, filename);
|
|
193919
|
+
writeFileSync14(commentsPath, formatted.content);
|
|
193265
193920
|
log2.debug(`wrote ${threadBlocks.length} threads to ${commentsPath}`);
|
|
193266
193921
|
return {
|
|
193267
193922
|
review_id: params.review_id,
|
|
@@ -193594,8 +194249,8 @@ function UploadFileTool(ctx) {
|
|
|
193594
194249
|
}
|
|
193595
194250
|
|
|
193596
194251
|
// mcp/xrepo.ts
|
|
193597
|
-
import { mkdirSync as
|
|
193598
|
-
import { join as
|
|
194252
|
+
import { mkdirSync as mkdirSync10, rmSync as rmSync3 } from "node:fs";
|
|
194253
|
+
import { join as join24 } from "node:path";
|
|
193599
194254
|
function assertValidRepoName(name) {
|
|
193600
194255
|
if (!/^[A-Za-z0-9._-]+$/.test(name) || name.startsWith("-") || name.includes("..")) {
|
|
193601
194256
|
throw new Error(
|
|
@@ -193675,8 +194330,8 @@ function CheckoutRepoTool(ctx) {
|
|
|
193675
194330
|
return { path: existing.dir, access: existing.access, note: "already checked out." };
|
|
193676
194331
|
}
|
|
193677
194332
|
const access = accessFor(ctx, repo);
|
|
193678
|
-
const dir =
|
|
193679
|
-
|
|
194333
|
+
const dir = join24(ctx.tmpdir, "xrepo", repo);
|
|
194334
|
+
mkdirSync10(dir, { recursive: true });
|
|
193680
194335
|
const state = ensureRepoState(ctx.toolState, { owner, name: repo, dir, access });
|
|
193681
194336
|
const rc = resolveRepoCtx(ctx, repo);
|
|
193682
194337
|
try {
|
|
@@ -193922,7 +194577,10 @@ function hasEnvVar2(name) {
|
|
|
193922
194577
|
return typeof val === "string" && val.length > 0;
|
|
193923
194578
|
}
|
|
193924
194579
|
function hasClaudeCodeAuth() {
|
|
193925
|
-
return hasEnvVar2("CLAUDE_CODE_OAUTH_TOKEN") || hasEnvVar2("ANTHROPIC_API_KEY");
|
|
194580
|
+
return hasEnvVar2("CLAUDE_CODE_OAUTH_TOKEN") || hasEnvVar2("ANTHROPIC_API_KEY") || hasEnvVar2("ANTHROPIC_AUTH_TOKEN");
|
|
194581
|
+
}
|
|
194582
|
+
function hasCodexAuth() {
|
|
194583
|
+
return hasEnvVar2("CODEX_AUTH_JSON") || hasEnvVar2("OPENAI_API_KEY");
|
|
193926
194584
|
}
|
|
193927
194585
|
function hasBedrockAuth() {
|
|
193928
194586
|
return hasEnvVar2("AWS_BEARER_TOKEN_BEDROCK") || hasEnvVar2("AWS_ACCESS_KEY_ID") && hasEnvVar2("AWS_SECRET_ACCESS_KEY");
|
|
@@ -193950,6 +194608,15 @@ function resolveSlug(slug2) {
|
|
|
193950
194608
|
}
|
|
193951
194609
|
return vertexId;
|
|
193952
194610
|
}
|
|
194611
|
+
if (alias?.routing === "azure") {
|
|
194612
|
+
const deployment = process.env[AZURE_DEPLOYMENT_ENV]?.trim();
|
|
194613
|
+
if (!deployment) {
|
|
194614
|
+
throw new Error(
|
|
194615
|
+
`${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.`
|
|
194616
|
+
);
|
|
194617
|
+
}
|
|
194618
|
+
return `${AZURE_PROVIDER}/${deployment}`;
|
|
194619
|
+
}
|
|
193953
194620
|
if (alias?.routing === "openai-compatible") {
|
|
193954
194621
|
const modelId = process.env[OPENAI_COMPATIBLE_MODEL_ENV]?.trim();
|
|
193955
194622
|
if (!modelId) {
|
|
@@ -193988,6 +194655,7 @@ function resolveAgent(ctx) {
|
|
|
193988
194655
|
}
|
|
193989
194656
|
log2.warning(`\xBB unknown PULLFROG_AGENT="${envAgent}" \u2014 falling through to auto-select`);
|
|
193990
194657
|
}
|
|
194658
|
+
if (ctx.proxyModel) return agents.opencode;
|
|
193991
194659
|
if (ctx.model && hasBedrockAuth() && process.env[BEDROCK_MODEL_ID_ENV]?.trim() === ctx.model) {
|
|
193992
194660
|
return isBedrockAnthropicId(ctx.model) ? agents.claude : agents.opencode;
|
|
193993
194661
|
}
|
|
@@ -193997,12 +194665,17 @@ function resolveAgent(ctx) {
|
|
|
193997
194665
|
if (ctx.model) {
|
|
193998
194666
|
try {
|
|
193999
194667
|
const provider2 = getModelProvider(ctx.model);
|
|
194000
|
-
if (provider2 === "anthropic" && hasClaudeCodeAuth())
|
|
194001
|
-
|
|
194002
|
-
}
|
|
194668
|
+
if (provider2 === "anthropic" && hasClaudeCodeAuth()) return agents.claude;
|
|
194669
|
+
if (provider2 === "openai" && ctx.codexAgent && hasCodexAuth()) return agents.codex;
|
|
194003
194670
|
} catch {
|
|
194004
194671
|
}
|
|
194005
194672
|
}
|
|
194673
|
+
if (!ctx.model) {
|
|
194674
|
+
if (hasEnvVar2("ANTHROPIC_AUTH_TOKEN") && !hasEnvVar2("ANTHROPIC_API_KEY") && !hasEnvVar2("CLAUDE_CODE_OAUTH_TOKEN")) {
|
|
194675
|
+
return agents.claude;
|
|
194676
|
+
}
|
|
194677
|
+
if (ctx.codexAgent && hasCodexAuth() && !hasClaudeCodeAuth()) return agents.codex;
|
|
194678
|
+
}
|
|
194006
194679
|
return agents.opencode;
|
|
194007
194680
|
}
|
|
194008
194681
|
|
|
@@ -194100,10 +194773,37 @@ auto-compaction is disabled, so long runs grow until your endpoint refuses them.
|
|
|
194100
194773
|
|
|
194101
194774
|
for full setup instructions, see https://docs.pullfrog.com/openai-compatible`;
|
|
194102
194775
|
}
|
|
194776
|
+
function buildAzureSetupError(params) {
|
|
194777
|
+
const githubSecretsUrl = `https://github.com/${params.owner}/${params.name}/settings/secrets/actions`;
|
|
194778
|
+
return `Azure OpenAI selected but required configuration is missing: ${params.missing.join(", ")}.
|
|
194779
|
+
|
|
194780
|
+
only the API key is sensitive \u2014 add it as a secret at ${githubSecretsUrl}. the rest is plain workflow \`env:\`:
|
|
194781
|
+
|
|
194782
|
+
${AZURE_RESOURCE_NAME_ENV}: <name>
|
|
194783
|
+
${AZURE_API_KEY_ENV}: \${{ secrets.${AZURE_API_KEY_ENV} }}
|
|
194784
|
+
${AZURE_DEPLOYMENT_ENV}: <deployment-name>
|
|
194785
|
+
${AZURE_CONTEXT_ENV}: "400000"
|
|
194786
|
+
${AZURE_MAX_OUTPUT_ENV}: "128000"
|
|
194787
|
+
|
|
194788
|
+
${AZURE_RESOURCE_NAME_ENV} is the \`<name>\` in your endpoint https://<name>.openai.azure.com.
|
|
194789
|
+
${AZURE_DEPLOYMENT_ENV} is the name of the deployment, which is not necessarily the name of
|
|
194790
|
+
the model it serves \u2014 Azure routes on the deployment name.
|
|
194791
|
+
|
|
194792
|
+
set the last two to the real limits of whichever model your deployment serves. Pullfrog can't
|
|
194793
|
+
discover them \u2014 a deployment name carries no catalog metadata \u2014 and without them completions
|
|
194794
|
+
are capped at 32000 tokens (rejected outright by models with a smaller cap) and auto-compaction
|
|
194795
|
+
is disabled, so long runs grow until Azure refuses them.
|
|
194796
|
+
|
|
194797
|
+
for full setup instructions, see https://docs.pullfrog.com/azure`;
|
|
194798
|
+
}
|
|
194103
194799
|
function hasEnvVar3(name) {
|
|
194104
194800
|
const value2 = process.env[name];
|
|
194105
194801
|
return typeof value2 === "string" && value2.length > 0;
|
|
194106
194802
|
}
|
|
194803
|
+
function modelHasRuntimeAuth(model) {
|
|
194804
|
+
const authVars = [...getModelEnvVars(model), ...getModelManagedCredentials(model)];
|
|
194805
|
+
return authVars.length === 0 || authVars.some(hasEnvVar3);
|
|
194806
|
+
}
|
|
194107
194807
|
function hasPositiveNumberEnvVar(name) {
|
|
194108
194808
|
return Number(process.env[name]) > 0;
|
|
194109
194809
|
}
|
|
@@ -194122,6 +194822,17 @@ function validateOpenAICompatibleSetup(params) {
|
|
|
194122
194822
|
);
|
|
194123
194823
|
}
|
|
194124
194824
|
}
|
|
194825
|
+
function validateAzureSetup(params) {
|
|
194826
|
+
const missing = [];
|
|
194827
|
+
if (!hasEnvVar3(AZURE_API_KEY_ENV)) missing.push(AZURE_API_KEY_ENV);
|
|
194828
|
+
if (!hasEnvVar3(AZURE_RESOURCE_NAME_ENV)) missing.push(AZURE_RESOURCE_NAME_ENV);
|
|
194829
|
+
if (!hasEnvVar3(AZURE_DEPLOYMENT_ENV)) missing.push(AZURE_DEPLOYMENT_ENV);
|
|
194830
|
+
if (!hasPositiveNumberEnvVar(AZURE_CONTEXT_ENV)) missing.push(AZURE_CONTEXT_ENV);
|
|
194831
|
+
if (!hasPositiveNumberEnvVar(AZURE_MAX_OUTPUT_ENV)) missing.push(AZURE_MAX_OUTPUT_ENV);
|
|
194832
|
+
if (missing.length > 0) {
|
|
194833
|
+
throw new Error(buildAzureSetupError({ owner: params.owner, name: params.name, missing }));
|
|
194834
|
+
}
|
|
194835
|
+
}
|
|
194125
194836
|
function validateBedrockSetup(params) {
|
|
194126
194837
|
const hasAuth = hasEnvVar3("AWS_BEARER_TOKEN_BEDROCK") || hasEnvVar3("AWS_ACCESS_KEY_ID") && hasEnvVar3("AWS_SECRET_ACCESS_KEY");
|
|
194127
194838
|
const missing = [];
|
|
@@ -194145,6 +194856,12 @@ function validateVertexSetup(params) {
|
|
|
194145
194856
|
throw new Error(buildVertexSetupError({ owner: params.owner, name: params.name, missing }));
|
|
194146
194857
|
}
|
|
194147
194858
|
}
|
|
194859
|
+
function hasSingleProviderAuth(agentName) {
|
|
194860
|
+
if (agentName === "codex") {
|
|
194861
|
+
return hasEnvVar3("OPENAI_API_KEY") || hasEnvVar3("CODEX_AUTH_JSON");
|
|
194862
|
+
}
|
|
194863
|
+
return hasEnvVar3("ANTHROPIC_API_KEY") || hasEnvVar3("ANTHROPIC_AUTH_TOKEN") || hasEnvVar3("CLAUDE_CODE_OAUTH_TOKEN");
|
|
194864
|
+
}
|
|
194148
194865
|
function validateAgentApiKey(params) {
|
|
194149
194866
|
if (params.model) {
|
|
194150
194867
|
const alias = resolveDisplayAlias(params.model);
|
|
@@ -194160,6 +194877,10 @@ function validateAgentApiKey(params) {
|
|
|
194160
194877
|
validateOpenAICompatibleSetup({ owner: params.owner, name: params.name });
|
|
194161
194878
|
return;
|
|
194162
194879
|
}
|
|
194880
|
+
if (params.model.startsWith(`${AZURE_PROVIDER}/`)) {
|
|
194881
|
+
validateAzureSetup({ owner: params.owner, name: params.name });
|
|
194882
|
+
return;
|
|
194883
|
+
}
|
|
194163
194884
|
if (!params.model.includes("/")) {
|
|
194164
194885
|
if (process.env[VERTEX_MODEL_ID_ENV]?.trim() === params.model) {
|
|
194165
194886
|
validateVertexSetup({ owner: params.owner, name: params.name });
|
|
@@ -194183,7 +194904,7 @@ function validateAgentApiKey(params) {
|
|
|
194183
194904
|
})
|
|
194184
194905
|
);
|
|
194185
194906
|
}
|
|
194186
|
-
if (
|
|
194907
|
+
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
194187
194908
|
throw new Error(
|
|
194188
194909
|
buildKeyError({
|
|
194189
194910
|
owner: params.owner,
|
|
@@ -194195,7 +194916,7 @@ function validateAgentApiKey(params) {
|
|
|
194195
194916
|
);
|
|
194196
194917
|
}
|
|
194197
194918
|
if (params.agent.name === "opencode") {
|
|
194198
|
-
if (params.authorized.
|
|
194919
|
+
if ([...params.authorized].some(modelHasRuntimeAuth)) return;
|
|
194199
194920
|
const reason = getModelsFailure();
|
|
194200
194921
|
if (reason) throw new Error(reason);
|
|
194201
194922
|
throw new Error(
|
|
@@ -194207,7 +194928,7 @@ function validateAgentApiKey(params) {
|
|
|
194207
194928
|
})
|
|
194208
194929
|
);
|
|
194209
194930
|
}
|
|
194210
|
-
if (
|
|
194931
|
+
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
194211
194932
|
throw new Error(
|
|
194212
194933
|
buildKeyError({
|
|
194213
194934
|
owner: params.owner,
|
|
@@ -194471,7 +195192,8 @@ var PROBES = {
|
|
|
194471
195192
|
request: (value2) => ({
|
|
194472
195193
|
url: "https://api.anthropic.com/v1/models",
|
|
194473
195194
|
headers: { "x-api-key": value2, "anthropic-version": "2023-06-01" }
|
|
194474
|
-
})
|
|
195195
|
+
}),
|
|
195196
|
+
hostConfigurable: true
|
|
194475
195197
|
},
|
|
194476
195198
|
OPENROUTER_API_KEY: {
|
|
194477
195199
|
request: (value2) => ({
|
|
@@ -194520,12 +195242,18 @@ function hasEnvVar4(name) {
|
|
|
194520
195242
|
const value2 = process.env[name];
|
|
194521
195243
|
return typeof value2 === "string" && value2.length > 0;
|
|
194522
195244
|
}
|
|
195245
|
+
var HOST_OVERRIDES = {
|
|
195246
|
+
ANTHROPIC_API_KEY: "ANTHROPIC_BASE_URL",
|
|
195247
|
+
CLAUDE_CODE_OAUTH_TOKEN: "ANTHROPIC_BASE_URL"
|
|
195248
|
+
};
|
|
194523
195249
|
function envVarsFor(model) {
|
|
194524
195250
|
return model.includes("/") ? getModelEnvVars(model) : [];
|
|
194525
195251
|
}
|
|
194526
195252
|
async function checkOne(params) {
|
|
194527
195253
|
const value2 = process.env[params.envVar];
|
|
194528
195254
|
if (!value2) return null;
|
|
195255
|
+
const hostOverride = HOST_OVERRIDES[params.envVar];
|
|
195256
|
+
if (hostOverride && hasEnvVar4(hostOverride)) return null;
|
|
194529
195257
|
if (params.envVar === "CLAUDE_CODE_OAUTH_TOKEN") {
|
|
194530
195258
|
const preflight = await preflightClaudeSubscription({
|
|
194531
195259
|
token: value2,
|
|
@@ -194580,9 +195308,9 @@ async function checkConfiguredCredentials(params) {
|
|
|
194580
195308
|
|
|
194581
195309
|
// utils/gitAuthServer.ts
|
|
194582
195310
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
194583
|
-
import { writeFileSync as
|
|
195311
|
+
import { writeFileSync as writeFileSync15 } from "node:fs";
|
|
194584
195312
|
import { createServer as createServer3 } from "node:http";
|
|
194585
|
-
import { join as
|
|
195313
|
+
import { join as join25 } from "node:path";
|
|
194586
195314
|
var REVOKED_TRAP_MS = 6e4;
|
|
194587
195315
|
function revokeGitHubToken(token) {
|
|
194588
195316
|
fetch("https://api.github.com/installation/token", {
|
|
@@ -194651,7 +195379,7 @@ async function startGitAuthServer(tmpdir4) {
|
|
|
194651
195379
|
function writeAskpassScript(code) {
|
|
194652
195380
|
const scriptId = randomUUID5();
|
|
194653
195381
|
const scriptName = `askpass-${scriptId}.js`;
|
|
194654
|
-
const scriptPath =
|
|
195382
|
+
const scriptPath = join25(tmpdir4, scriptName);
|
|
194655
195383
|
const content = [
|
|
194656
195384
|
`#!/usr/bin/env node`,
|
|
194657
195385
|
`var a=process.argv[2]||"";`,
|
|
@@ -194664,7 +195392,7 @@ async function startGitAuthServer(tmpdir4) {
|
|
|
194664
195392
|
`r.on("end",function(){process.stdout.write(d+"\\n")})`,
|
|
194665
195393
|
`}).on("error",function(){process.exit(1)})}`
|
|
194666
195394
|
].join("\n");
|
|
194667
|
-
|
|
195395
|
+
writeFileSync15(scriptPath, content, { mode: 448 });
|
|
194668
195396
|
return scriptPath;
|
|
194669
195397
|
}
|
|
194670
195398
|
async function close() {
|
|
@@ -195103,7 +195831,7 @@ function resolveInstructions(ctx) {
|
|
|
195103
195831
|
|
|
195104
195832
|
// utils/learnings.ts
|
|
195105
195833
|
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
195106
|
-
import { dirname as dirname4, join as
|
|
195834
|
+
import { dirname as dirname4, join as join26 } from "node:path";
|
|
195107
195835
|
|
|
195108
195836
|
// utils/learningsTruncate.ts
|
|
195109
195837
|
var MAX_LEARNINGS_LENGTH = 1e5;
|
|
@@ -195121,10 +195849,10 @@ function truncateAtLineBoundary(body, cap) {
|
|
|
195121
195849
|
var LEARNINGS_FILE_NAME = "pullfrog-learnings.md";
|
|
195122
195850
|
var XREPO_LEARNINGS_FILE_NAME = "pullfrog-xrepo-learnings.md";
|
|
195123
195851
|
function learningsFilePath(tmpdir4) {
|
|
195124
|
-
return
|
|
195852
|
+
return join26(tmpdir4, LEARNINGS_FILE_NAME);
|
|
195125
195853
|
}
|
|
195126
195854
|
function xrepoLearningsFilePath(tmpdir4) {
|
|
195127
|
-
return
|
|
195855
|
+
return join26(tmpdir4, XREPO_LEARNINGS_FILE_NAME);
|
|
195128
195856
|
}
|
|
195129
195857
|
async function seedLearningsFile(params) {
|
|
195130
195858
|
const path4 = learningsFilePath(params.tmpdir);
|
|
@@ -195240,7 +195968,7 @@ async function persistXrepoLearnings(ctx) {
|
|
|
195240
195968
|
// utils/modelAccess.ts
|
|
195241
195969
|
function decideModelAccess(input) {
|
|
195242
195970
|
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}/`));
|
|
195971
|
+
const byokAuthorized = !!input.resolvedModel && (input.authorized.has(input.resolvedModel) || !input.resolvedModel.includes("/") || input.resolvedModel.startsWith(`${OPENAI_COMPATIBLE_PROVIDER}/`) || input.resolvedModel.startsWith(`${AZURE_PROVIDER}/`));
|
|
195244
195972
|
if (input.proxyActive) {
|
|
195245
195973
|
const target = resolveOpenRouterModel(input.model);
|
|
195246
195974
|
if (input.oss) {
|
|
@@ -195285,7 +196013,7 @@ function buildModelAccessError(input) {
|
|
|
195285
196013
|
}
|
|
195286
196014
|
|
|
195287
196015
|
// utils/normalizeEnv.ts
|
|
195288
|
-
var
|
|
196016
|
+
var core5 = __toESM(require_core(), 1);
|
|
195289
196017
|
function hasControlCharacter(value2) {
|
|
195290
196018
|
return [...value2].some((ch) => {
|
|
195291
196019
|
const code = ch.charCodeAt(0);
|
|
@@ -195311,7 +196039,7 @@ function sanitizeSecret(key, value2) {
|
|
|
195311
196039
|
`\xBB stripped whitespace from ${key} (whitespace in secret values breaks GitHub Actions log masking)`
|
|
195312
196040
|
);
|
|
195313
196041
|
}
|
|
195314
|
-
|
|
196042
|
+
core5.setSecret(trimmed);
|
|
195315
196043
|
return trimmed;
|
|
195316
196044
|
}
|
|
195317
196045
|
function normalizeEnv() {
|
|
@@ -195355,7 +196083,7 @@ function normalizeEnv() {
|
|
|
195355
196083
|
}
|
|
195356
196084
|
|
|
195357
196085
|
// utils/overrides.ts
|
|
195358
|
-
var
|
|
196086
|
+
var core6 = __toESM(require_core(), 1);
|
|
195359
196087
|
var DENIED_OVERRIDE_NAMES = /* @__PURE__ */ new Set([
|
|
195360
196088
|
"GITHUB_TOKEN",
|
|
195361
196089
|
"GH_TOKEN",
|
|
@@ -195401,7 +196129,7 @@ function applyOverrides(params) {
|
|
|
195401
196129
|
denied.push(key);
|
|
195402
196130
|
continue;
|
|
195403
196131
|
}
|
|
195404
|
-
if (value2.length > 0)
|
|
196132
|
+
if (value2.length > 0) core6.setSecret(value2);
|
|
195405
196133
|
params.env[key] = value2;
|
|
195406
196134
|
applied.push(key);
|
|
195407
196135
|
}
|
|
@@ -195410,8 +196138,8 @@ function applyOverrides(params) {
|
|
|
195410
196138
|
}
|
|
195411
196139
|
|
|
195412
196140
|
// utils/payload.ts
|
|
195413
|
-
var
|
|
195414
|
-
import { readFileSync as
|
|
196141
|
+
var core7 = __toESM(require_core(), 1);
|
|
196142
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
195415
196143
|
import { isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
|
|
195416
196144
|
|
|
195417
196145
|
// utils/versioning.ts
|
|
@@ -195498,8 +196226,8 @@ function resolveCwd(cwd) {
|
|
|
195498
196226
|
return workspace ? resolve2(workspace, cwd) : cwd;
|
|
195499
196227
|
}
|
|
195500
196228
|
function resolvePromptInput() {
|
|
195501
|
-
const promptInput =
|
|
195502
|
-
const promptFile =
|
|
196229
|
+
const promptInput = core7.getInput("prompt");
|
|
196230
|
+
const promptFile = core7.getInput("prompt_file");
|
|
195503
196231
|
if (promptInput && promptFile) {
|
|
195504
196232
|
throw new Error("set exactly one of 'prompt' or 'prompt_file' inputs, not both.");
|
|
195505
196233
|
}
|
|
@@ -195525,7 +196253,7 @@ function resolvePromptInput() {
|
|
|
195525
196253
|
function resolvePromptFile(input) {
|
|
195526
196254
|
const workspace = process.env.GITHUB_WORKSPACE;
|
|
195527
196255
|
const path4 = isAbsolute2(input) ? input : workspace ? resolve2(workspace, input) : resolve2(input);
|
|
195528
|
-
const content =
|
|
196256
|
+
const content = readFileSync7(path4, "utf-8");
|
|
195529
196257
|
if (!content.trim()) {
|
|
195530
196258
|
throw new Error(`prompt_file ${JSON.stringify(input)} is empty.`);
|
|
195531
196259
|
}
|
|
@@ -195533,7 +196261,7 @@ function resolvePromptFile(input) {
|
|
|
195533
196261
|
}
|
|
195534
196262
|
function warnIfDeprecatedStatusChecks(value2) {
|
|
195535
196263
|
if (value2 !== void 0) {
|
|
195536
|
-
|
|
196264
|
+
core7.warning(
|
|
195537
196265
|
"`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
196266
|
);
|
|
195539
196267
|
}
|
|
@@ -195541,15 +196269,15 @@ function warnIfDeprecatedStatusChecks(value2) {
|
|
|
195541
196269
|
}
|
|
195542
196270
|
function resolveNonPromptInputs() {
|
|
195543
196271
|
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:
|
|
196272
|
+
model: core7.getInput("model") || void 0,
|
|
196273
|
+
effort: core7.getInput("effort") || void 0,
|
|
196274
|
+
debug: core7.getInput("debug") || void 0,
|
|
196275
|
+
timeout: core7.getInput("timeout") || void 0,
|
|
196276
|
+
cwd: core7.getInput("cwd") || void 0,
|
|
196277
|
+
push: core7.getInput("push") || void 0,
|
|
196278
|
+
shell: core7.getInput("shell") || void 0,
|
|
196279
|
+
status_checks: warnIfDeprecatedStatusChecks(core7.getInput("status_checks") || void 0),
|
|
196280
|
+
progress_comments: core7.getInput("progress_comments") || void 0
|
|
195553
196281
|
});
|
|
195554
196282
|
}
|
|
195555
196283
|
function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
@@ -195617,7 +196345,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
195617
196345
|
};
|
|
195618
196346
|
}
|
|
195619
196347
|
function resolveOutputSchema() {
|
|
195620
|
-
const raw2 =
|
|
196348
|
+
const raw2 = core7.getInput("output_schema");
|
|
195621
196349
|
if (!raw2) return void 0;
|
|
195622
196350
|
let parsed2;
|
|
195623
196351
|
try {
|
|
@@ -195633,10 +196361,10 @@ function resolveOutputSchema() {
|
|
|
195633
196361
|
}
|
|
195634
196362
|
|
|
195635
196363
|
// utils/proxy.ts
|
|
195636
|
-
var
|
|
196364
|
+
var core9 = __toESM(require_core(), 1);
|
|
195637
196365
|
|
|
195638
196366
|
// utils/token.ts
|
|
195639
|
-
var
|
|
196367
|
+
var core8 = __toESM(require_core(), 1);
|
|
195640
196368
|
import assert2 from "node:assert/strict";
|
|
195641
196369
|
var mcpTokenValue;
|
|
195642
196370
|
var refreshMcpTokenFn;
|
|
@@ -195644,7 +196372,7 @@ function getMcpTokenRefresh() {
|
|
|
195644
196372
|
return refreshMcpTokenFn;
|
|
195645
196373
|
}
|
|
195646
196374
|
function getJobToken() {
|
|
195647
|
-
const inputToken =
|
|
196375
|
+
const inputToken = core8.getInput("token");
|
|
195648
196376
|
if (inputToken) {
|
|
195649
196377
|
return inputToken;
|
|
195650
196378
|
}
|
|
@@ -195660,7 +196388,7 @@ async function resolveTokens(params) {
|
|
|
195660
196388
|
if (externalToken) {
|
|
195661
196389
|
mcpTokenValue = externalToken;
|
|
195662
196390
|
if (isGitHubActions) {
|
|
195663
|
-
|
|
196391
|
+
core8.setSecret(externalToken);
|
|
195664
196392
|
}
|
|
195665
196393
|
log2.info("\xBB using external GH_TOKEN for both git and MCP");
|
|
195666
196394
|
return {
|
|
@@ -195680,7 +196408,7 @@ async function resolveTokens(params) {
|
|
|
195680
196408
|
const gitPermissions = params.push === "disabled" ? { contents: "read" } : { contents: "write", workflows: "write" };
|
|
195681
196409
|
const gitToken = await acquireNewToken({ repos: writeRepos, permissions: gitPermissions });
|
|
195682
196410
|
if (isGitHubActions) {
|
|
195683
|
-
|
|
196411
|
+
core8.setSecret(gitToken);
|
|
195684
196412
|
}
|
|
195685
196413
|
log2.info(
|
|
195686
196414
|
`\xBB acquired git token (${Object.entries(gitPermissions).map((e) => e.join(":")).join(", ")})`
|
|
@@ -195697,7 +196425,7 @@ async function resolveTokens(params) {
|
|
|
195697
196425
|
};
|
|
195698
196426
|
const mcpToken = await acquireNewToken({ repos: writeRepos, permissions: mcpPermissions });
|
|
195699
196427
|
if (isGitHubActions) {
|
|
195700
|
-
|
|
196428
|
+
core8.setSecret(mcpToken);
|
|
195701
196429
|
}
|
|
195702
196430
|
log2.info(
|
|
195703
196431
|
`\xBB acquired scoped MCP token (${Object.entries(mcpPermissions).map((e) => e.join(":")).join(", ")})`
|
|
@@ -195706,7 +196434,7 @@ async function resolveTokens(params) {
|
|
|
195706
196434
|
let ghToken;
|
|
195707
196435
|
if (ghPermissions) {
|
|
195708
196436
|
ghToken = await acquireNewToken({ permissions: ghPermissions });
|
|
195709
|
-
if (isGitHubActions)
|
|
196437
|
+
if (isGitHubActions) core8.setSecret(ghToken);
|
|
195710
196438
|
log2.info(
|
|
195711
196439
|
`\xBB acquired gh token mirroring ${params.authorPermission} (${formatPermissions(ghPermissions)})`
|
|
195712
196440
|
);
|
|
@@ -195717,7 +196445,7 @@ async function resolveTokens(params) {
|
|
|
195717
196445
|
repos: params.xrepo.read,
|
|
195718
196446
|
permissions: { contents: "read" }
|
|
195719
196447
|
});
|
|
195720
|
-
if (isGitHubActions)
|
|
196448
|
+
if (isGitHubActions) core8.setSecret(readToken);
|
|
195721
196449
|
log2.info(`\xBB acquired cross-repo read token (contents:read, ${params.xrepo.read.length} repos)`);
|
|
195722
196450
|
}
|
|
195723
196451
|
mcpTokenValue = mcpToken;
|
|
@@ -195736,7 +196464,7 @@ async function resolveTokens(params) {
|
|
|
195736
196464
|
oidc: params.oidc ?? void 0
|
|
195737
196465
|
}).then((fresh) => {
|
|
195738
196466
|
if (isGitHubActions) {
|
|
195739
|
-
|
|
196467
|
+
core8.setSecret(fresh);
|
|
195740
196468
|
}
|
|
195741
196469
|
mcpTokenValue = fresh;
|
|
195742
196470
|
currentMcpToken = fresh;
|
|
@@ -195757,7 +196485,7 @@ async function resolveTokens(params) {
|
|
|
195757
196485
|
permissions: gitPermissions,
|
|
195758
196486
|
oidc: params.oidc ?? void 0
|
|
195759
196487
|
}).then((fresh) => {
|
|
195760
|
-
if (isGitHubActions)
|
|
196488
|
+
if (isGitHubActions) core8.setSecret(fresh);
|
|
195761
196489
|
void revokeGitHubInstallationToken(currentGitToken);
|
|
195762
196490
|
currentGitToken = fresh;
|
|
195763
196491
|
log2.warning("\xBB GitHub rejected the git token; re-acquired a fresh git token");
|
|
@@ -195774,7 +196502,7 @@ async function resolveTokens(params) {
|
|
|
195774
196502
|
permissions: { contents: "read" },
|
|
195775
196503
|
oidc: params.oidc ?? void 0
|
|
195776
196504
|
}).then((fresh) => {
|
|
195777
|
-
if (isGitHubActions)
|
|
196505
|
+
if (isGitHubActions) core8.setSecret(fresh);
|
|
195778
196506
|
void revokeGitHubInstallationToken(read2);
|
|
195779
196507
|
currentReadToken = fresh;
|
|
195780
196508
|
log2.warning("\xBB GitHub rejected the read token; re-acquired a fresh read token");
|
|
@@ -195988,7 +196716,7 @@ async function resolveProxyModel(ctx) {
|
|
|
195988
196716
|
});
|
|
195989
196717
|
if (!key) return;
|
|
195990
196718
|
process.env.OPENROUTER_API_KEY = key;
|
|
195991
|
-
|
|
196719
|
+
core9.setSecret(key);
|
|
195992
196720
|
ctx.payload.proxyModel = ctx.proxyModel;
|
|
195993
196721
|
ctx.toolState.model = ctx.proxyModel;
|
|
195994
196722
|
const label = ctx.oss ? "oss" : "router";
|
|
@@ -196059,7 +196787,7 @@ async function runProxyResolution(ctx) {
|
|
|
196059
196787
|
|
|
196060
196788
|
// utils/prSummary.ts
|
|
196061
196789
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
|
|
196062
|
-
import { dirname as dirname5, join as
|
|
196790
|
+
import { dirname as dirname5, join as join27 } from "node:path";
|
|
196063
196791
|
var SUMMARY_FILE_NAME = "pullfrog-summary.md";
|
|
196064
196792
|
var SUMMARY_SCAFFOLD = `# PR summary
|
|
196065
196793
|
|
|
@@ -196069,7 +196797,7 @@ var SUMMARY_SCAFFOLD = `# PR summary
|
|
|
196069
196797
|
var MIN_SNAPSHOT_LENGTH = 60;
|
|
196070
196798
|
var MAX_SNAPSHOT_LENGTH = 32768;
|
|
196071
196799
|
function summaryFilePath(tmpdir4) {
|
|
196072
|
-
return
|
|
196800
|
+
return join27(tmpdir4, SUMMARY_FILE_NAME);
|
|
196073
196801
|
}
|
|
196074
196802
|
async function seedSummaryFile(params) {
|
|
196075
196803
|
const path4 = summaryFilePath(params.tmpdir);
|
|
@@ -196198,6 +196926,7 @@ var defaultSettings = {
|
|
|
196198
196926
|
shell: "restricted",
|
|
196199
196927
|
prApproveEnabled: false,
|
|
196200
196928
|
autoMergeEnabled: false,
|
|
196929
|
+
codexAgent: false,
|
|
196201
196930
|
signedCommits: false,
|
|
196202
196931
|
repoIntelligence: false,
|
|
196203
196932
|
progressComments: true,
|
|
@@ -196686,7 +197415,7 @@ ${genericBody}`,
|
|
|
196686
197415
|
}
|
|
196687
197416
|
|
|
196688
197417
|
// utils/runLifecycle.ts
|
|
196689
|
-
var
|
|
197418
|
+
var core10 = __toESM(require_core(), 1);
|
|
196690
197419
|
|
|
196691
197420
|
// utils/autoMerge.ts
|
|
196692
197421
|
function hasBlockingHumanReview(reviews) {
|
|
@@ -197072,7 +197801,7 @@ async function finalizeSuccessRun(input) {
|
|
|
197072
197801
|
}
|
|
197073
197802
|
if (input.toolState.output) {
|
|
197074
197803
|
log2.info(`::pullfrog-output::${Buffer.from(input.toolState.output).toString("base64")}`);
|
|
197075
|
-
|
|
197804
|
+
core10.setOutput("result", input.toolState.output);
|
|
197076
197805
|
}
|
|
197077
197806
|
if (input.result.success) {
|
|
197078
197807
|
await approveAfterFix(input.toolContext).catch((error52) => {
|
|
@@ -197536,7 +198265,11 @@ async function main() {
|
|
|
197536
198265
|
}
|
|
197537
198266
|
const resolvedModel = credentials.kind === "fellBack" ? credentials.replacement : configuredModel;
|
|
197538
198267
|
vertexCredentials = materializeVertexCredentials({ model: resolvedModel });
|
|
197539
|
-
const agent2 = resolveAgent({
|
|
198268
|
+
const agent2 = resolveAgent({
|
|
198269
|
+
model: resolvedModel,
|
|
198270
|
+
proxyModel: payload.proxyModel,
|
|
198271
|
+
codexAgent: runContext.repoSettings.codexAgent
|
|
198272
|
+
});
|
|
197540
198273
|
const effectiveModel = payload.proxyModel ?? resolvedModel ?? payload.model;
|
|
197541
198274
|
toolState.model = effectiveModel;
|
|
197542
198275
|
if (!payload.proxyModel) {
|
|
@@ -197720,8 +198453,8 @@ ${instructions.user}` : null,
|
|
|
197720
198453
|
log2.info(instructions.full);
|
|
197721
198454
|
});
|
|
197722
198455
|
if (agentId === "opencode") {
|
|
197723
|
-
const pluginDir =
|
|
197724
|
-
const hasPlugins =
|
|
198456
|
+
const pluginDir = join28(process.cwd(), ".opencode", "plugin");
|
|
198457
|
+
const hasPlugins = existsSync9(pluginDir) && readdirSync2(pluginDir).some((f) => /\.[jt]sx?$/.test(f));
|
|
197725
198458
|
if (hasPlugins && toolState.dependencyInstallation?.promise) {
|
|
197726
198459
|
log2.info(
|
|
197727
198460
|
"\xBB .opencode/plugin/ detected \u2014 awaiting dependency installation before agent start"
|
|
@@ -197753,16 +198486,14 @@ ${instructions.user}` : null,
|
|
|
197753
198486
|
const onInnerActivityTimeout = () => {
|
|
197754
198487
|
if (innerTimeoutFired) return;
|
|
197755
198488
|
innerTimeoutFired = true;
|
|
197756
|
-
log2.info(
|
|
197757
|
-
"\xBB inner activity timeout fired \u2014 stopping MCP server and starting 5min safety-net timer"
|
|
197758
|
-
);
|
|
197759
|
-
mcpHttpServer[Symbol.asyncDispose]().catch((err) => {
|
|
197760
|
-
log2.debug(
|
|
197761
|
-
`mcp server stop after inner kill failed: ${err instanceof Error ? err.message : String(err)}`
|
|
197762
|
-
);
|
|
197763
|
-
});
|
|
198489
|
+
log2.info("\xBB inner activity timeout fired \u2014 starting 5min safety-net timer");
|
|
197764
198490
|
safetyNetTimer = setTimeout(
|
|
197765
198491
|
() => {
|
|
198492
|
+
mcpHttpServer[Symbol.asyncDispose]().catch((err) => {
|
|
198493
|
+
log2.debug(
|
|
198494
|
+
`mcp server stop after inner kill failed: ${err instanceof Error ? err.message : String(err)}`
|
|
198495
|
+
);
|
|
198496
|
+
});
|
|
197766
198497
|
activityTimeout?.forceReject(
|
|
197767
198498
|
"agent still pending 5min after inner activity kill \u2014 forcing exit"
|
|
197768
198499
|
);
|
|
@@ -197771,6 +198502,13 @@ ${instructions.user}` : null,
|
|
|
197771
198502
|
);
|
|
197772
198503
|
safetyNetTimer.unref?.();
|
|
197773
198504
|
};
|
|
198505
|
+
const onTurnRecovered = () => {
|
|
198506
|
+
if (!innerTimeoutFired) return;
|
|
198507
|
+
innerTimeoutFired = false;
|
|
198508
|
+
if (safetyNetTimer) clearTimeout(safetyNetTimer);
|
|
198509
|
+
safetyNetTimer = void 0;
|
|
198510
|
+
log2.info("\xBB inner activity safety net stood down \u2014 turn recovered");
|
|
198511
|
+
};
|
|
197774
198512
|
const agentPromise = agent2.run({
|
|
197775
198513
|
payload,
|
|
197776
198514
|
resolvedModel,
|
|
@@ -197791,6 +198529,7 @@ ${instructions.user}` : null,
|
|
|
197791
198529
|
toolState,
|
|
197792
198530
|
apiToken: runContext.apiToken,
|
|
197793
198531
|
onActivityTimeout: onInnerActivityTimeout,
|
|
198532
|
+
onTurnRecovered,
|
|
197794
198533
|
onToolUse: (event) => {
|
|
197795
198534
|
const wasTracked = recordDiffReadFromToolUse({
|
|
197796
198535
|
state: primaryRepoState(toolState).diffCoverage,
|
|
@@ -197913,27 +198652,27 @@ async function runMain() {
|
|
|
197913
198652
|
}
|
|
197914
198653
|
} catch (error52) {
|
|
197915
198654
|
const errorMessage = error52 instanceof Error ? error52.message : "unknown error occurred";
|
|
197916
|
-
|
|
198655
|
+
core11.setFailed(`action failed: ${errorMessage}`);
|
|
197917
198656
|
}
|
|
197918
198657
|
}
|
|
197919
198658
|
async function tokenMain() {
|
|
197920
|
-
const reposInput =
|
|
198659
|
+
const reposInput = core11.getInput("repos");
|
|
197921
198660
|
const additionalRepos = reposInput ? reposInput.split(",").map((r2) => r2.trim()).filter(Boolean) : [];
|
|
197922
198661
|
const token = await acquireNewToken({ repos: additionalRepos });
|
|
197923
|
-
|
|
197924
|
-
|
|
197925
|
-
|
|
198662
|
+
core11.setSecret(token);
|
|
198663
|
+
core11.saveState(STATE_TOKEN, token);
|
|
198664
|
+
core11.setOutput("token", token);
|
|
197926
198665
|
const scope2 = additionalRepos.length ? `current repo + ${additionalRepos.join(", ")}` : "current repo only";
|
|
197927
|
-
|
|
198666
|
+
core11.info(`\xBB installation token acquired (${scope2})`);
|
|
197928
198667
|
}
|
|
197929
198668
|
async function tokenPost() {
|
|
197930
|
-
const token =
|
|
198669
|
+
const token = core11.getState(STATE_TOKEN);
|
|
197931
198670
|
if (!token) {
|
|
197932
|
-
|
|
198671
|
+
core11.debug("no token found in state, skipping revocation");
|
|
197933
198672
|
return;
|
|
197934
198673
|
}
|
|
197935
198674
|
await revokeGitHubInstallationToken(token);
|
|
197936
|
-
|
|
198675
|
+
core11.info("\xBB installation token revoked");
|
|
197937
198676
|
}
|
|
197938
198677
|
function printGhaUsage(params) {
|
|
197939
198678
|
params.stream(`usage: ${params.prog} gha [subcommand]
|
|
@@ -198049,7 +198788,7 @@ async function run(args2) {
|
|
|
198049
198788
|
}
|
|
198050
198789
|
} catch (error52) {
|
|
198051
198790
|
const message = error52 instanceof Error ? error52.message : String(error52);
|
|
198052
|
-
|
|
198791
|
+
core11.setFailed(message);
|
|
198053
198792
|
}
|
|
198054
198793
|
}
|
|
198055
198794
|
|
|
@@ -198064,34 +198803,6 @@ var PULLFROG_API_URL2 = (process.env.PULLFROG_API_URL || "https://pullfrog.com")
|
|
|
198064
198803
|
function link(text, url4) {
|
|
198065
198804
|
return `\x1B]8;;${url4}\x07${text}\x1B]8;;\x07`;
|
|
198066
198805
|
}
|
|
198067
|
-
function buildProviders() {
|
|
198068
|
-
return Object.entries(providers).filter(([key]) => key !== "opencode" && key !== "openrouter").map(([key, config3]) => {
|
|
198069
|
-
const aliases = modelAliases.filter(
|
|
198070
|
-
(a2) => a2.provider === key && !a2.fallback && !a2.routing && !a2.hidden
|
|
198071
|
-
);
|
|
198072
|
-
const recommended = aliases.find((a2) => a2.preferred);
|
|
198073
|
-
const sorted = [...aliases].sort((a2, b) => {
|
|
198074
|
-
if (a2.preferred && !b.preferred) return -1;
|
|
198075
|
-
if (!a2.preferred && b.preferred) return 1;
|
|
198076
|
-
return 0;
|
|
198077
|
-
});
|
|
198078
|
-
return {
|
|
198079
|
-
id: key,
|
|
198080
|
-
name: config3.displayName,
|
|
198081
|
-
envVars: config3.envVars,
|
|
198082
|
-
models: sorted.map((a2) => ({
|
|
198083
|
-
value: a2.slug,
|
|
198084
|
-
label: a2.displayName,
|
|
198085
|
-
hint: a2 === recommended ? "recommended" : void 0
|
|
198086
|
-
}))
|
|
198087
|
-
};
|
|
198088
|
-
}).filter((p) => p.models.length > 0);
|
|
198089
|
-
}
|
|
198090
|
-
var CLI_PROVIDERS = buildProviders();
|
|
198091
|
-
function resolveModelProvider(slug2) {
|
|
198092
|
-
const providerId = slug2.split("/")[0];
|
|
198093
|
-
return CLI_PROVIDERS.find((p) => p.id === providerId) ?? null;
|
|
198094
|
-
}
|
|
198095
198806
|
var activeSpin2 = null;
|
|
198096
198807
|
function bail2(msg) {
|
|
198097
198808
|
if (activeSpin2) {
|
|
@@ -198176,15 +198887,11 @@ function openBrowser(url4) {
|
|
|
198176
198887
|
}
|
|
198177
198888
|
}
|
|
198178
198889
|
async function pullfrogApi2(ctx) {
|
|
198179
|
-
const headers = { authorization: `Bearer ${ctx.token}` };
|
|
198180
|
-
if (ctx.body) headers["content-type"] = "application/json";
|
|
198181
198890
|
const controller = new AbortController();
|
|
198182
198891
|
const timeout = setTimeout(() => controller.abort(), 3e4);
|
|
198183
198892
|
try {
|
|
198184
198893
|
const response = await fetch(`${PULLFROG_API_URL2}${ctx.path}`, {
|
|
198185
|
-
|
|
198186
|
-
headers,
|
|
198187
|
-
body: ctx.body ? JSON.stringify(ctx.body) : null,
|
|
198894
|
+
headers: { authorization: `Bearer ${ctx.token}` },
|
|
198188
198895
|
signal: controller.signal
|
|
198189
198896
|
});
|
|
198190
198897
|
const data = await response.json().catch(() => ({}));
|
|
@@ -198212,406 +198919,27 @@ async function fetchStatus2(ctx) {
|
|
|
198212
198919
|
isOrg: result.data.isOrg === true
|
|
198213
198920
|
};
|
|
198214
198921
|
}
|
|
198215
|
-
bail2(errorMsg || `
|
|
198922
|
+
bail2(errorMsg || `installation check failed (${result.status})`);
|
|
198216
198923
|
}
|
|
198217
198924
|
return {
|
|
198218
198925
|
installed: true,
|
|
198219
198926
|
isOrg: result.data.isOrg === true,
|
|
198220
|
-
installationId: typeof result.data.installationId === "number" ? result.data.installationId : null
|
|
198221
|
-
secretsAccessible: result.data.accessible !== false,
|
|
198222
|
-
repoSecrets: result.data.repoSecrets || [],
|
|
198223
|
-
orgSecrets: result.data.orgSecrets || [],
|
|
198224
|
-
pullfrogSecrets: result.data.pullfrogSecrets || [],
|
|
198225
|
-
model: result.data.repoModel ?? null,
|
|
198226
|
-
hasRuns: result.data.hasRuns === true
|
|
198227
|
-
};
|
|
198228
|
-
}
|
|
198229
|
-
async function createSession(ctx) {
|
|
198230
|
-
try {
|
|
198231
|
-
const result = await pullfrogApi2({
|
|
198232
|
-
path: "/api/cli/session",
|
|
198233
|
-
token: ctx.token,
|
|
198234
|
-
method: "POST",
|
|
198235
|
-
body: { owner: ctx.owner.toLowerCase(), repo: ctx.repo.toLowerCase() }
|
|
198236
|
-
});
|
|
198237
|
-
if (!result.ok || !result.data.id) return null;
|
|
198238
|
-
return result.data.id;
|
|
198239
|
-
} catch {
|
|
198240
|
-
return null;
|
|
198241
|
-
}
|
|
198242
|
-
}
|
|
198243
|
-
async function pollSession(ctx) {
|
|
198244
|
-
const result = await pullfrogApi2({
|
|
198245
|
-
path: `/api/cli/session/${ctx.sessionId}`,
|
|
198246
|
-
token: ctx.token
|
|
198247
|
-
});
|
|
198248
|
-
if (result.status === 410) return "expired";
|
|
198249
|
-
if (!result.ok) return "pending";
|
|
198250
|
-
return result.data.installed === true ? "installed" : "pending";
|
|
198251
|
-
}
|
|
198252
|
-
function cleanupSession(ctx) {
|
|
198253
|
-
void pullfrogApi2({
|
|
198254
|
-
path: `/api/cli/session/${ctx.sessionId}`,
|
|
198255
|
-
token: ctx.token,
|
|
198256
|
-
method: "DELETE"
|
|
198257
|
-
}).catch(() => {
|
|
198258
|
-
});
|
|
198259
|
-
}
|
|
198260
|
-
var SESSION_POLL_MS = 750;
|
|
198261
|
-
var FALLBACK_POLL_MS = 5e3;
|
|
198262
|
-
var HINT_AFTER_MS = 1e4;
|
|
198263
|
-
var TIMEOUT_MS = 3 * 60 * 1e3;
|
|
198264
|
-
function listenForKey(key) {
|
|
198265
|
-
let triggered = false;
|
|
198266
|
-
const onData = (data) => {
|
|
198267
|
-
if (data.toString().toLowerCase() === key) triggered = true;
|
|
198268
|
-
};
|
|
198269
|
-
process.stdin.setRawMode?.(true);
|
|
198270
|
-
process.stdin.resume();
|
|
198271
|
-
process.stdin.on("data", onData);
|
|
198272
|
-
return {
|
|
198273
|
-
consume() {
|
|
198274
|
-
if (!triggered) return false;
|
|
198275
|
-
triggered = false;
|
|
198276
|
-
return true;
|
|
198277
|
-
},
|
|
198278
|
-
stop() {
|
|
198279
|
-
process.stdin.removeListener("data", onData);
|
|
198280
|
-
process.stdin.setRawMode?.(false);
|
|
198281
|
-
process.stdin.pause();
|
|
198282
|
-
}
|
|
198927
|
+
installationId: typeof result.data.installationId === "number" ? result.data.installationId : null
|
|
198283
198928
|
};
|
|
198284
198929
|
}
|
|
198285
198930
|
function installationConfigUrl(ctx) {
|
|
198286
198931
|
return ctx.isOrg ? `https://github.com/organizations/${ctx.owner}/settings/installations/${ctx.installationId}` : `https://github.com/settings/installations/${ctx.installationId}`;
|
|
198287
198932
|
}
|
|
198288
|
-
|
|
198289
|
-
|
|
198290
|
-
const initial = await fetchStatus2(ctx);
|
|
198291
|
-
if (initial.installed) {
|
|
198292
|
-
activeSpin2.stop(`pullfrog app is installed on ${import_picocolors3.default.cyan(`@${ctx.owner}`)}`);
|
|
198293
|
-
if (initial.installationId) {
|
|
198294
|
-
const configUrl = installationConfigUrl({
|
|
198295
|
-
owner: ctx.owner,
|
|
198296
|
-
installationId: initial.installationId,
|
|
198297
|
-
isOrg: initial.isOrg
|
|
198298
|
-
});
|
|
198299
|
-
process.stdout.write(`${import_picocolors3.default.gray(S_BAR)} ${link(import_picocolors3.default.dim(configUrl), configUrl)}
|
|
198300
|
-
`);
|
|
198301
|
-
}
|
|
198302
|
-
return initial;
|
|
198303
|
-
}
|
|
198304
|
-
const sessionId = await createSession(ctx);
|
|
198305
|
-
if (initial.installationId) {
|
|
198306
|
-
const repoRef = import_picocolors3.default.bold(`${ctx.owner}/${ctx.repo}`);
|
|
198307
|
-
const configUrl = installationConfigUrl({
|
|
198308
|
-
owner: ctx.owner,
|
|
198309
|
-
installationId: initial.installationId,
|
|
198310
|
-
isOrg: initial.isOrg
|
|
198311
|
-
});
|
|
198312
|
-
activeSpin2.stop(`pullfrog is installed on selected repos, but ${repoRef} is not included.`);
|
|
198313
|
-
log.info(
|
|
198314
|
-
`add it under "Repository access" on the installation config page.
|
|
198315
|
-
${import_picocolors3.default.dim(configUrl)}`
|
|
198316
|
-
);
|
|
198317
|
-
const openIt = await confirm({ message: "open browser?", active: "yes", inactive: "no" });
|
|
198318
|
-
handleCancel2(openIt);
|
|
198319
|
-
if (openIt) openBrowser(configUrl);
|
|
198320
|
-
} else {
|
|
198321
|
-
activeSpin2.stop("pullfrog app not installed");
|
|
198322
|
-
const installUrl = `https://github.com/apps/${initial.appSlug}/installations/select_target?state=cli`;
|
|
198323
|
-
log.info(`opening browser to install...
|
|
198324
|
-
${import_picocolors3.default.dim(installUrl)}`);
|
|
198325
|
-
openBrowser(installUrl);
|
|
198326
|
-
}
|
|
198327
|
-
const isRepoAccessUpdate = !!initial.installationId;
|
|
198328
|
-
const baseMsg = isRepoAccessUpdate ? "once you've added the repo, onboarding will proceed automatically" : "once you've installed the app, onboarding will proceed automatically";
|
|
198329
|
-
activeSpin2.start(baseMsg);
|
|
198330
|
-
let activeSessionId = sessionId;
|
|
198331
|
-
let pollMs = activeSessionId ? SESSION_POLL_MS : FALLBACK_POLL_MS;
|
|
198332
|
-
const listener = listenForKey("r");
|
|
198333
|
-
const startedAt = Date.now();
|
|
198334
|
-
let hintShown = false;
|
|
198335
|
-
try {
|
|
198336
|
-
while (Date.now() - startedAt < TIMEOUT_MS) {
|
|
198337
|
-
await new Promise((r2) => setTimeout(r2, pollMs));
|
|
198338
|
-
if (!hintShown && Date.now() - startedAt > HINT_AFTER_MS) {
|
|
198339
|
-
activeSpin2.message(`${baseMsg} ${import_picocolors3.default.dim("(press r to recheck manually)")}`);
|
|
198340
|
-
hintShown = true;
|
|
198341
|
-
}
|
|
198342
|
-
const doneMsg = isRepoAccessUpdate ? "repo access confirmed" : "pullfrog app installed";
|
|
198343
|
-
if (listener.consume()) {
|
|
198344
|
-
activeSpin2.message("rechecking via GitHub API");
|
|
198345
|
-
try {
|
|
198346
|
-
const status = await fetchStatus2(ctx);
|
|
198347
|
-
if (status.installed) {
|
|
198348
|
-
if (activeSessionId) cleanupSession({ token: ctx.token, sessionId: activeSessionId });
|
|
198349
|
-
activeSpin2.stop(doneMsg);
|
|
198350
|
-
return status;
|
|
198351
|
-
}
|
|
198352
|
-
} catch {
|
|
198353
|
-
}
|
|
198354
|
-
activeSpin2.message(`${baseMsg} ${import_picocolors3.default.dim("(press r to recheck manually)")}`);
|
|
198355
|
-
continue;
|
|
198356
|
-
}
|
|
198357
|
-
if (activeSessionId) {
|
|
198358
|
-
try {
|
|
198359
|
-
const result = await pollSession({ token: ctx.token, sessionId: activeSessionId });
|
|
198360
|
-
if (result === "expired") {
|
|
198361
|
-
activeSessionId = null;
|
|
198362
|
-
pollMs = FALLBACK_POLL_MS;
|
|
198363
|
-
continue;
|
|
198364
|
-
}
|
|
198365
|
-
if (result === "installed") {
|
|
198366
|
-
const status = await fetchStatus2(ctx);
|
|
198367
|
-
if (status.installed) {
|
|
198368
|
-
cleanupSession({ token: ctx.token, sessionId: activeSessionId });
|
|
198369
|
-
activeSpin2.stop(doneMsg);
|
|
198370
|
-
return status;
|
|
198371
|
-
}
|
|
198372
|
-
}
|
|
198373
|
-
} catch {
|
|
198374
|
-
}
|
|
198375
|
-
} else {
|
|
198376
|
-
try {
|
|
198377
|
-
const status = await fetchStatus2(ctx);
|
|
198378
|
-
if (status.installed) {
|
|
198379
|
-
activeSpin2.stop(doneMsg);
|
|
198380
|
-
return status;
|
|
198381
|
-
}
|
|
198382
|
-
} catch {
|
|
198383
|
-
}
|
|
198384
|
-
}
|
|
198385
|
-
}
|
|
198386
|
-
} finally {
|
|
198387
|
-
listener.stop();
|
|
198388
|
-
}
|
|
198389
|
-
if (activeSessionId) cleanupSession({ token: ctx.token, sessionId: activeSessionId });
|
|
198390
|
-
bail2(
|
|
198391
|
-
isRepoAccessUpdate ? `timed out waiting for repo access.
|
|
198392
|
-
${import_picocolors3.default.dim("add the repo, then re-run:")} npx pullfrog init` : `timed out waiting for app installation.
|
|
198393
|
-
${import_picocolors3.default.dim("if your org requires admin approval, ask an admin to approve,")}
|
|
198394
|
-
${import_picocolors3.default.dim("then re-run:")} npx pullfrog init`
|
|
198395
|
-
);
|
|
198933
|
+
function consoleUrl(ctx) {
|
|
198934
|
+
return `${PULLFROG_API_URL2}/console/${ctx.owner}?repo=${encodeURIComponent(ctx.repo)}`;
|
|
198396
198935
|
}
|
|
198397
|
-
function
|
|
198398
|
-
|
|
198399
|
-
|
|
198400
|
-
try {
|
|
198401
|
-
execFileSync8("gh", ["secret", "set", ctx.name, "--org", ctx.org, "--visibility", "all"], {
|
|
198402
|
-
input: ctx.value,
|
|
198403
|
-
stdio: ["pipe", "ignore", "pipe"],
|
|
198404
|
-
encoding: "utf-8"
|
|
198405
|
-
});
|
|
198406
|
-
return { saved: true, orgFailed: false };
|
|
198407
|
-
} catch {
|
|
198408
|
-
orgFailed = true;
|
|
198409
|
-
}
|
|
198410
|
-
}
|
|
198411
|
-
try {
|
|
198412
|
-
execFileSync8("gh", ["secret", "set", ctx.name, "--repo", ctx.repoSlug], {
|
|
198413
|
-
input: ctx.value,
|
|
198414
|
-
stdio: ["pipe", "ignore", "pipe"],
|
|
198415
|
-
encoding: "utf-8"
|
|
198416
|
-
});
|
|
198417
|
-
return { saved: true, orgFailed };
|
|
198418
|
-
} catch {
|
|
198419
|
-
return { saved: false, orgFailed };
|
|
198420
|
-
}
|
|
198936
|
+
function installUrl(ctx) {
|
|
198937
|
+
const state = encodeURIComponent(`cli:${ctx.owner}/${ctx.repo}`);
|
|
198938
|
+
return `https://github.com/apps/${ctx.appSlug}/installations/select_target?state=${state}`;
|
|
198421
198939
|
}
|
|
198422
|
-
|
|
198423
|
-
|
|
198424
|
-
|
|
198425
|
-
token: ctx.token,
|
|
198426
|
-
method: "POST",
|
|
198427
|
-
body: {
|
|
198428
|
-
owner: ctx.owner,
|
|
198429
|
-
repo: ctx.repo,
|
|
198430
|
-
name: ctx.name,
|
|
198431
|
-
value: ctx.value,
|
|
198432
|
-
scope: ctx.scope
|
|
198433
|
-
}
|
|
198434
|
-
});
|
|
198435
|
-
if (result.ok && result.data.success === true) {
|
|
198436
|
-
return { saved: true, error: "" };
|
|
198437
|
-
}
|
|
198438
|
-
return { saved: false, error: result.data.error || `api returned ${result.status}` };
|
|
198439
|
-
}
|
|
198440
|
-
async function promptScope2(ctx) {
|
|
198441
|
-
const scope2 = await select({
|
|
198442
|
-
message: "secret scope",
|
|
198443
|
-
options: [
|
|
198444
|
-
{ value: "account", label: `${ctx.owner} organization`, hint: "shared across repos" },
|
|
198445
|
-
{ value: "repo", label: `${ctx.owner}/${ctx.repo} only` }
|
|
198446
|
-
]
|
|
198447
|
-
});
|
|
198448
|
-
handleCancel2(scope2);
|
|
198449
|
-
return scope2;
|
|
198450
|
-
}
|
|
198451
|
-
async function handleSecret(ctx) {
|
|
198452
|
-
const repoSecretsUrl = `https://github.com/${ctx.owner}/${ctx.repo}/settings/secrets/actions`;
|
|
198453
|
-
const matches = [];
|
|
198454
|
-
for (const v of ctx.provider.envVars) {
|
|
198455
|
-
if (ctx.secrets.pullfrogSecrets.includes(v)) matches.push({ name: v, source: "pullfrog" });
|
|
198456
|
-
else if (ctx.secrets.secretsAccessible && ctx.secrets.orgSecrets.includes(v))
|
|
198457
|
-
matches.push({ name: v, source: "org secret" });
|
|
198458
|
-
else if (ctx.secrets.secretsAccessible && ctx.secrets.repoSecrets.includes(v))
|
|
198459
|
-
matches.push({ name: v, source: "repo secret" });
|
|
198460
|
-
}
|
|
198461
|
-
if (matches.length > 0) {
|
|
198462
|
-
activeSpin2.start("");
|
|
198463
|
-
activeSpin2.stop("secrets already configured");
|
|
198464
|
-
for (const m of matches) {
|
|
198465
|
-
process.stdout.write(
|
|
198466
|
-
`${import_picocolors3.default.gray(S_BAR)} ${import_picocolors3.default.cyan(m.name)} ${import_picocolors3.default.dim(`(${m.source})`)}
|
|
198467
|
-
`
|
|
198468
|
-
);
|
|
198469
|
-
}
|
|
198470
|
-
return;
|
|
198471
|
-
}
|
|
198472
|
-
if (!ctx.secrets.secretsAccessible) {
|
|
198473
|
-
log.info(`could not verify GitHub secrets (app lacks permission)`);
|
|
198474
|
-
}
|
|
198475
|
-
const hasOAuthOption = ctx.provider.envVars.includes("CLAUDE_CODE_OAUTH_TOKEN");
|
|
198476
|
-
let envVar = ctx.provider.envVars[0];
|
|
198477
|
-
if (hasOAuthOption) {
|
|
198478
|
-
const authMethod = await select({
|
|
198479
|
-
message: "which credential do you want to use?",
|
|
198480
|
-
options: [
|
|
198481
|
-
{
|
|
198482
|
-
value: "oauth",
|
|
198483
|
-
label: "Claude Code OAuth token",
|
|
198484
|
-
hint: `run ${import_picocolors3.default.cyan("claude setup-token")} \u2014 works with Pro/Max subscriptions`
|
|
198485
|
-
},
|
|
198486
|
-
{
|
|
198487
|
-
value: "api",
|
|
198488
|
-
label: "Anthropic API key",
|
|
198489
|
-
hint: "from console.anthropic.com"
|
|
198490
|
-
}
|
|
198491
|
-
]
|
|
198492
|
-
});
|
|
198493
|
-
handleCancel2(authMethod);
|
|
198494
|
-
if (authMethod === "oauth") envVar = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
198495
|
-
}
|
|
198496
|
-
const method = await select({
|
|
198497
|
-
message: `where should ${import_picocolors3.default.cyan(envVar)} be stored?`,
|
|
198498
|
-
options: [
|
|
198499
|
-
{
|
|
198500
|
-
value: "pullfrog",
|
|
198501
|
-
label: "Pullfrog",
|
|
198502
|
-
hint: "recommended \u2014 auto-injected, no workflow changes"
|
|
198503
|
-
},
|
|
198504
|
-
{
|
|
198505
|
-
value: "github",
|
|
198506
|
-
label: "GitHub Actions secret",
|
|
198507
|
-
hint: "requires env block in pullfrog.yml"
|
|
198508
|
-
}
|
|
198509
|
-
]
|
|
198510
|
-
});
|
|
198511
|
-
handleCancel2(method);
|
|
198512
|
-
const pasteLabel = envVar === "CLAUDE_CODE_OAUTH_TOKEN" ? "OAuth token" : `${ctx.provider.name} API key`;
|
|
198513
|
-
const apiKey = await password({
|
|
198514
|
-
message: `paste your ${pasteLabel} ${import_picocolors3.default.dim("(Enter to skip)")}`,
|
|
198515
|
-
mask: "*",
|
|
198516
|
-
validate: () => void 0
|
|
198517
|
-
});
|
|
198518
|
-
handleCancel2(apiKey);
|
|
198519
|
-
if (!apiKey) {
|
|
198520
|
-
log.info(
|
|
198521
|
-
`skipped \u2014 set it manually at:
|
|
198522
|
-
${import_picocolors3.default.dim(method === "pullfrog" ? `${PULLFROG_API_URL2}/console/${ctx.owner}` : repoSecretsUrl)}`
|
|
198523
|
-
);
|
|
198524
|
-
return;
|
|
198525
|
-
}
|
|
198526
|
-
if (method === "pullfrog") {
|
|
198527
|
-
const scope2 = ctx.secrets.isOrg ? await promptScope2(ctx) : "account";
|
|
198528
|
-
const target = describeSecretTarget({ owner: ctx.owner, repo: ctx.repo, scope: scope2 });
|
|
198529
|
-
activeSpin2.start(`saving ${import_picocolors3.default.cyan(envVar)} to ${target}`);
|
|
198530
|
-
let saveResult;
|
|
198531
|
-
try {
|
|
198532
|
-
saveResult = await setPullfrogSecret2({
|
|
198533
|
-
token: ctx.token,
|
|
198534
|
-
owner: ctx.owner,
|
|
198535
|
-
repo: ctx.repo,
|
|
198536
|
-
name: envVar,
|
|
198537
|
-
value: apiKey,
|
|
198538
|
-
scope: scope2
|
|
198539
|
-
});
|
|
198540
|
-
} catch (error52) {
|
|
198541
|
-
activeSpin2.stop(import_picocolors3.default.red("could not save secret"));
|
|
198542
|
-
log.warn(
|
|
198543
|
-
`${error52 instanceof Error ? error52.message : "network error"}
|
|
198544
|
-
set it manually at: ${import_picocolors3.default.dim(`${PULLFROG_API_URL2}/console/${ctx.owner}`)}`
|
|
198545
|
-
);
|
|
198546
|
-
return;
|
|
198547
|
-
}
|
|
198548
|
-
if (saveResult.saved) {
|
|
198549
|
-
activeSpin2.stop(`saved ${import_picocolors3.default.cyan(envVar)} to ${target}`);
|
|
198550
|
-
} else {
|
|
198551
|
-
activeSpin2.stop(import_picocolors3.default.red("could not save secret"));
|
|
198552
|
-
log.warn(
|
|
198553
|
-
`${saveResult.error}
|
|
198554
|
-
set it manually at: ${import_picocolors3.default.dim(`${PULLFROG_API_URL2}/console/${ctx.owner}`)}`
|
|
198555
|
-
);
|
|
198556
|
-
}
|
|
198557
|
-
return;
|
|
198558
|
-
}
|
|
198559
|
-
let org = null;
|
|
198560
|
-
if (ctx.secrets.isOrg) {
|
|
198561
|
-
const scope2 = await promptScope2(ctx);
|
|
198562
|
-
org = scope2 === "account" ? ctx.owner : null;
|
|
198563
|
-
}
|
|
198564
|
-
const secretsUrl = org ? `https://github.com/organizations/${org}/settings/secrets/actions` : repoSecretsUrl;
|
|
198565
|
-
activeSpin2.start(`saving ${envVar}`);
|
|
198566
|
-
const secretResult = setGhSecret({
|
|
198567
|
-
name: envVar,
|
|
198568
|
-
value: apiKey,
|
|
198569
|
-
org,
|
|
198570
|
-
repoSlug: `${ctx.owner}/${ctx.repo}`
|
|
198571
|
-
});
|
|
198572
|
-
if (secretResult.saved) {
|
|
198573
|
-
activeSpin2.stop(
|
|
198574
|
-
`saved ${import_picocolors3.default.cyan(envVar)} to ${org && !secretResult.orgFailed ? `${import_picocolors3.default.dim(ctx.owner)} org secret` : "GitHub Actions secret"}`
|
|
198575
|
-
);
|
|
198576
|
-
if (secretResult.orgFailed) {
|
|
198577
|
-
log.warn("org secret failed (admin access required) \u2014 saved as repo secret instead");
|
|
198578
|
-
}
|
|
198579
|
-
} else {
|
|
198580
|
-
activeSpin2.stop(import_picocolors3.default.red("could not set secret"));
|
|
198581
|
-
log.warn(`set it manually at:
|
|
198582
|
-
${import_picocolors3.default.dim(secretsUrl)}`);
|
|
198583
|
-
}
|
|
198584
|
-
}
|
|
198585
|
-
async function promptTestRun(ctx) {
|
|
198586
|
-
const proceed = await select({
|
|
198587
|
-
message: "test your installation?",
|
|
198588
|
-
options: [
|
|
198589
|
-
{ value: true, label: "yes", hint: "dispatches a test run in your GitHub Actions" },
|
|
198590
|
-
{ value: false, label: "skip" }
|
|
198591
|
-
]
|
|
198592
|
-
});
|
|
198593
|
-
handleCancel2(proceed);
|
|
198594
|
-
if (!proceed) return;
|
|
198595
|
-
activeSpin2.start("dispatching test run");
|
|
198596
|
-
const result = await pullfrogApi2({
|
|
198597
|
-
path: "/api/cli/dispatch",
|
|
198598
|
-
token: ctx.token,
|
|
198599
|
-
method: "POST",
|
|
198600
|
-
body: { owner: ctx.owner, repo: ctx.repo, prompt: "Tell me a joke" }
|
|
198601
|
-
});
|
|
198602
|
-
if (!result.ok) {
|
|
198603
|
-
activeSpin2.stop(import_picocolors3.default.red("could not dispatch"));
|
|
198604
|
-
log.warn(result.data.error || `dispatch failed (${result.status})`);
|
|
198605
|
-
return;
|
|
198606
|
-
}
|
|
198607
|
-
activeSpin2.stop("dispatched test run");
|
|
198608
|
-
if (result.data.url) {
|
|
198609
|
-
process.stdout.write(
|
|
198610
|
-
`${import_picocolors3.default.gray(S_BAR)} ${link(import_picocolors3.default.dim(result.data.url), result.data.url)}
|
|
198611
|
-
`
|
|
198612
|
-
);
|
|
198613
|
-
openBrowser(result.data.url);
|
|
198614
|
-
}
|
|
198940
|
+
function printLink(url4) {
|
|
198941
|
+
process.stdout.write(`${import_picocolors3.default.gray(S_BAR)} ${link(import_picocolors3.default.dim(url4), url4)}
|
|
198942
|
+
`);
|
|
198615
198943
|
}
|
|
198616
198944
|
async function main2() {
|
|
198617
198945
|
intro(import_picocolors3.default.bgGreen(import_picocolors3.default.black(" pullfrog ")));
|
|
@@ -198633,98 +198961,58 @@ async function main2() {
|
|
|
198633
198961
|
spin.start("detecting repository");
|
|
198634
198962
|
const remote = parseGitRemote2();
|
|
198635
198963
|
spin.stop(`detected repo ${import_picocolors3.default.cyan(`${remote.owner}/${remote.repo}`)}`);
|
|
198636
|
-
|
|
198637
|
-
|
|
198638
|
-
|
|
198639
|
-
if (
|
|
198640
|
-
|
|
198641
|
-
const resolved = resolveModelProvider(secrets.model);
|
|
198642
|
-
if (!resolved) bail2(`unknown model provider: ${secrets.model}`);
|
|
198643
|
-
provider2 = resolved;
|
|
198644
|
-
const displayAlias = resolveDisplayAlias(secrets.model);
|
|
198645
|
-
const label = displayAlias ? displayAlias.displayName : secrets.model;
|
|
198964
|
+
spin.start("checking pullfrog app installation");
|
|
198965
|
+
const status = await fetchStatus2({ token, owner: remote.owner, repo: remote.repo });
|
|
198966
|
+
const handoff = consoleUrl({ owner: remote.owner, repo: remote.repo });
|
|
198967
|
+
if (status.installed) {
|
|
198968
|
+
spin.stop(`pullfrog app is installed on ${import_picocolors3.default.cyan(`@${remote.owner}`)}`);
|
|
198646
198969
|
spin.start("");
|
|
198647
|
-
spin.stop(
|
|
198648
|
-
|
|
198649
|
-
|
|
198650
|
-
|
|
198651
|
-
|
|
198652
|
-
|
|
198653
|
-
label: cp.name
|
|
198654
|
-
}))
|
|
198655
|
-
});
|
|
198656
|
-
handleCancel2(providerId);
|
|
198657
|
-
const found = CLI_PROVIDERS.find((cp) => cp.id === providerId);
|
|
198658
|
-
if (!found) bail2(`unknown provider: ${providerId}`);
|
|
198659
|
-
provider2 = found;
|
|
198660
|
-
if (provider2.models.length === 1) {
|
|
198661
|
-
model = provider2.models[0].value;
|
|
198662
|
-
spin.start("");
|
|
198663
|
-
spin.stop(`using ${import_picocolors3.default.bold(provider2.models[0].label)}`);
|
|
198664
|
-
} else {
|
|
198665
|
-
const recommendedModel = provider2.models.find((m) => m.hint === "recommended");
|
|
198666
|
-
const options = provider2.models.map((m) => {
|
|
198667
|
-
if (m.hint) return { value: m.value, label: m.label, hint: m.hint };
|
|
198668
|
-
return { value: m.value, label: m.label };
|
|
198669
|
-
});
|
|
198670
|
-
const selected = await select(
|
|
198671
|
-
recommendedModel ? { message: "select model", initialValue: recommendedModel.value, options } : { message: "select model", options }
|
|
198672
|
-
);
|
|
198673
|
-
handleCancel2(selected);
|
|
198674
|
-
model = selected;
|
|
198675
|
-
}
|
|
198676
|
-
}
|
|
198677
|
-
await handleSecret({ token, owner: remote.owner, repo: remote.repo, provider: provider2, secrets });
|
|
198678
|
-
spin.start("creating pullfrog.yml workflow");
|
|
198679
|
-
const result = await pullfrogApi2({
|
|
198680
|
-
path: "/api/cli/setup",
|
|
198681
|
-
token,
|
|
198682
|
-
method: "POST",
|
|
198683
|
-
body: { owner: remote.owner, repo: remote.repo, model }
|
|
198684
|
-
});
|
|
198685
|
-
if (!result.ok) {
|
|
198686
|
-
bail2(result.data.error || `api returned ${result.status}`);
|
|
198687
|
-
}
|
|
198688
|
-
let skipTestRun = false;
|
|
198689
|
-
if (result.data.already_existed) {
|
|
198690
|
-
spin.stop("pullfrog.yml already exists");
|
|
198691
|
-
} else if (result.data.pull_request_url) {
|
|
198692
|
-
spin.stop("opened pull request with pullfrog.yml");
|
|
198693
|
-
process.stdout.write(
|
|
198694
|
-
`${import_picocolors3.default.gray(S_BAR)} ${link(import_picocolors3.default.dim(result.data.pull_request_url), result.data.pull_request_url)}
|
|
198695
|
-
`
|
|
198970
|
+
spin.stop("opening your dashboard");
|
|
198971
|
+
printLink(handoff);
|
|
198972
|
+
openBrowser(handoff);
|
|
198973
|
+
activeSpin2 = null;
|
|
198974
|
+
outro(
|
|
198975
|
+
`finish setup in your browser \u2014 ${import_picocolors3.default.cyan(`${remote.owner}/${remote.repo}`)} is ready.`
|
|
198696
198976
|
);
|
|
198697
|
-
|
|
198698
|
-
|
|
198699
|
-
|
|
198700
|
-
|
|
198701
|
-
|
|
198702
|
-
|
|
198703
|
-
|
|
198977
|
+
return;
|
|
198978
|
+
}
|
|
198979
|
+
if (status.installationId) {
|
|
198980
|
+
const repoRef = import_picocolors3.default.bold(`${remote.owner}/${remote.repo}`);
|
|
198981
|
+
const configUrl = installationConfigUrl({
|
|
198982
|
+
owner: remote.owner,
|
|
198983
|
+
installationId: status.installationId,
|
|
198984
|
+
isOrg: status.isOrg
|
|
198704
198985
|
});
|
|
198705
|
-
|
|
198706
|
-
|
|
198707
|
-
|
|
198708
|
-
|
|
198709
|
-
spin.stop(
|
|
198710
|
-
short ? `committed pullfrog.yml to repo ${import_picocolors3.default.dim(short)}` : "committed pullfrog.yml to repo"
|
|
198986
|
+
spin.stop(`pullfrog is installed on selected repos, but ${repoRef} is not included.`);
|
|
198987
|
+
log.info(
|
|
198988
|
+
`add it under "Repository access" on the installation config page.
|
|
198989
|
+
${import_picocolors3.default.dim(configUrl)}`
|
|
198711
198990
|
);
|
|
198991
|
+
const openIt = await confirm({ message: "open browser?", active: "yes", inactive: "no" });
|
|
198992
|
+
handleCancel2(openIt);
|
|
198993
|
+
if (openIt) openBrowser(configUrl);
|
|
198994
|
+
log.info("once the repo is added, finish setup at:");
|
|
198995
|
+
printLink(handoff);
|
|
198996
|
+
activeSpin2 = null;
|
|
198997
|
+
outro("done.");
|
|
198998
|
+
return;
|
|
198712
198999
|
}
|
|
198713
|
-
|
|
198714
|
-
|
|
198715
|
-
|
|
198716
|
-
|
|
198717
|
-
|
|
198718
|
-
|
|
198719
|
-
|
|
198720
|
-
|
|
199000
|
+
spin.stop("pullfrog app not installed");
|
|
199001
|
+
const install = installUrl({
|
|
199002
|
+
appSlug: status.appSlug,
|
|
199003
|
+
owner: remote.owner,
|
|
199004
|
+
repo: remote.repo
|
|
199005
|
+
});
|
|
199006
|
+
log.info("opening browser to install...");
|
|
199007
|
+
printLink(install);
|
|
199008
|
+
openBrowser(install);
|
|
198721
199009
|
activeSpin2 = null;
|
|
198722
|
-
outro("
|
|
199010
|
+
outro("GitHub will drop you at your dashboard to finish setup.");
|
|
198723
199011
|
}
|
|
198724
199012
|
function printInitUsage(params) {
|
|
198725
199013
|
params.stream(`usage: ${params.prog} init
|
|
198726
199014
|
`);
|
|
198727
|
-
params.stream("
|
|
199015
|
+
params.stream("install pullfrog on the current repository and open its dashboard.");
|
|
198728
199016
|
params.stream("");
|
|
198729
199017
|
params.stream("options:");
|
|
198730
199018
|
params.stream(" -h, --help show help");
|
|
@@ -198896,7 +199184,7 @@ async function runCli4(input) {
|
|
|
198896
199184
|
}
|
|
198897
199185
|
|
|
198898
199186
|
// cli.ts
|
|
198899
|
-
var VERSION10 = "0.1.
|
|
199187
|
+
var VERSION10 = "0.1.60";
|
|
198900
199188
|
var bin = basename2(process.argv[1] || "");
|
|
198901
199189
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
198902
199190
|
var rawArgs = process.argv.slice(2);
|
|
@@ -198904,7 +199192,7 @@ function printMainUsage(stream) {
|
|
|
198904
199192
|
stream(`usage: ${PROG} <command>
|
|
198905
199193
|
`);
|
|
198906
199194
|
stream("commands:");
|
|
198907
|
-
stream(" init
|
|
199195
|
+
stream(" init install pullfrog on the current repository and open its dashboard");
|
|
198908
199196
|
stream(" auth manage provider credentials for the current repository");
|
|
198909
199197
|
stream(" watch stream a PR's activity as one JSON line per event");
|
|
198910
199198
|
stream("");
|