@f-o-h/cli 0.1.57 → 0.1.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/foh.js +100 -10
- package/package.json +1 -1
package/dist/foh.js
CHANGED
|
@@ -32853,7 +32853,7 @@ var StdioServerTransport = class {
|
|
|
32853
32853
|
};
|
|
32854
32854
|
|
|
32855
32855
|
// src/lib/cli-version.ts
|
|
32856
|
-
var CLI_VERSION = "0.1.
|
|
32856
|
+
var CLI_VERSION = "0.1.59";
|
|
32857
32857
|
|
|
32858
32858
|
// src/commands/mcp-serve.ts
|
|
32859
32859
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -39244,6 +39244,7 @@ function readExternalAgentMetadata(runDir) {
|
|
|
39244
39244
|
}
|
|
39245
39245
|
|
|
39246
39246
|
// src/lib/external-agent-executor.ts
|
|
39247
|
+
var GEMINI_HEADLESS_PROBE_TIMEOUT_MS = 15e3;
|
|
39247
39248
|
var CODEX_EXECUTOR_DENIED_ENV_PREFIXES = [
|
|
39248
39249
|
"SUPABASE_",
|
|
39249
39250
|
"DATABASE_",
|
|
@@ -39411,11 +39412,16 @@ function readBatch(batchPath) {
|
|
|
39411
39412
|
return parsed;
|
|
39412
39413
|
}
|
|
39413
39414
|
function defaultRunnerProbe(command, args) {
|
|
39415
|
+
const isGeminiHeadlessSmoke = args.includes("FOH_GEMINI_HEADLESS_PROBE");
|
|
39416
|
+
const spawnOptions = {
|
|
39417
|
+
encoding: "utf8",
|
|
39418
|
+
timeout: isGeminiHeadlessSmoke ? GEMINI_HEADLESS_PROBE_TIMEOUT_MS : void 0
|
|
39419
|
+
};
|
|
39414
39420
|
const result = process.platform === "win32" && command.toLowerCase().endsWith(".cmd") ? (0, import_child_process4.spawnSync)(
|
|
39415
39421
|
"powershell.exe",
|
|
39416
39422
|
["-NoLogo", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", `& ${[command, ...args].map(quotePowerShellArg).join(" ")}`],
|
|
39417
|
-
|
|
39418
|
-
) : (0, import_child_process4.spawnSync)(command, args,
|
|
39423
|
+
spawnOptions
|
|
39424
|
+
) : (0, import_child_process4.spawnSync)(command, args, spawnOptions);
|
|
39419
39425
|
return {
|
|
39420
39426
|
status: typeof result.status === "number" ? result.status : null,
|
|
39421
39427
|
stdout: String(result.stdout || ""),
|
|
@@ -39423,6 +39429,9 @@ function defaultRunnerProbe(command, args) {
|
|
|
39423
39429
|
error: result.error
|
|
39424
39430
|
};
|
|
39425
39431
|
}
|
|
39432
|
+
function geminiCapacityUnavailable(text) {
|
|
39433
|
+
return /MODEL_CAPACITY_EXHAUSTED|RESOURCE_EXHAUSTED|No capacity available|rateLimitExceeded|exhausted your capacity|status 429/i.test(text);
|
|
39434
|
+
}
|
|
39426
39435
|
function quotePowerShellArg(value) {
|
|
39427
39436
|
return `'${value.replace(/'/g, "''")}'`;
|
|
39428
39437
|
}
|
|
@@ -39562,15 +39571,14 @@ ${yoloHelp.stderr}`;
|
|
|
39562
39571
|
};
|
|
39563
39572
|
}
|
|
39564
39573
|
function validateGeminiRunner(options) {
|
|
39574
|
+
const geminiSandboxMode = normalizeGeminiSandboxMode(options.geminiSandboxMode);
|
|
39565
39575
|
const execArgs = [
|
|
39566
39576
|
"--approval-mode",
|
|
39567
39577
|
"yolo",
|
|
39568
|
-
"--sandbox",
|
|
39569
39578
|
"--output-format",
|
|
39570
|
-
"stream-json"
|
|
39571
|
-
"--prompt",
|
|
39572
|
-
"Execute the FOH external-agent prompt supplied on stdin."
|
|
39579
|
+
"stream-json"
|
|
39573
39580
|
];
|
|
39581
|
+
if (geminiSandboxMode === "required") execArgs.splice(2, 0, "--sandbox");
|
|
39574
39582
|
if (options.skipRunnerProbe) {
|
|
39575
39583
|
return {
|
|
39576
39584
|
runner: "gemini",
|
|
@@ -39584,6 +39592,9 @@ function validateGeminiRunner(options) {
|
|
|
39584
39592
|
supportsYoloAlias: null,
|
|
39585
39593
|
yoloPolicy: "not_checked",
|
|
39586
39594
|
supportsGeminiHeadless: true,
|
|
39595
|
+
supportsGeminiSandbox: geminiSandboxMode === "required",
|
|
39596
|
+
geminiSandboxMode,
|
|
39597
|
+
headlessInvocationChecked: false,
|
|
39587
39598
|
automationMode: "gemini-yolo",
|
|
39588
39599
|
globalArgs: [],
|
|
39589
39600
|
execArgs
|
|
@@ -39603,7 +39614,8 @@ ${version2.stderr}`.trim() || null;
|
|
|
39603
39614
|
}
|
|
39604
39615
|
const helpText = `${help.stdout}
|
|
39605
39616
|
${help.stderr}`;
|
|
39606
|
-
const requiredFlags = ["--
|
|
39617
|
+
const requiredFlags = ["--approval-mode", "--output-format"];
|
|
39618
|
+
if (geminiSandboxMode === "required") requiredFlags.push("--sandbox");
|
|
39607
39619
|
const missing = requiredFlags.filter((flag) => !helpText.includes(flag));
|
|
39608
39620
|
if (missing.length > 0) {
|
|
39609
39621
|
throw new ExternalAgentExecutorError(
|
|
@@ -39611,6 +39623,39 @@ ${help.stderr}`;
|
|
|
39611
39623
|
`Gemini runner is missing required headless flag(s): ${missing.join(", ")}`
|
|
39612
39624
|
);
|
|
39613
39625
|
}
|
|
39626
|
+
const smoke = probe(probeCommand, [...execArgs, "FOH_GEMINI_HEADLESS_PROBE"]);
|
|
39627
|
+
const smokeText = `${smoke.stdout}
|
|
39628
|
+
${smoke.stderr}`;
|
|
39629
|
+
if (/Cannot use both a positional prompt and the --prompt/i.test(smokeText)) {
|
|
39630
|
+
throw new ExternalAgentExecutorError(
|
|
39631
|
+
"external_agent_runner_headless_probe_failed",
|
|
39632
|
+
"Gemini runner rejected the planned headless invocation before auth."
|
|
39633
|
+
);
|
|
39634
|
+
}
|
|
39635
|
+
if (/GEMINI_SANDBOX.*failed|failed to determine command for sandbox|install docker or podman/i.test(smokeText)) {
|
|
39636
|
+
throw new ExternalAgentExecutorError(
|
|
39637
|
+
"external_agent_runner_sandbox_unavailable",
|
|
39638
|
+
"Gemini runner sandbox is unavailable on this host. Install/configure Docker/Podman or rerun only on an externally isolated host with --gemini-sandbox-mode disabled."
|
|
39639
|
+
);
|
|
39640
|
+
}
|
|
39641
|
+
if (geminiCapacityUnavailable(smokeText)) {
|
|
39642
|
+
throw new ExternalAgentExecutorError(
|
|
39643
|
+
"external_agent_runner_capacity_unavailable",
|
|
39644
|
+
"Gemini runner reached the provider but the selected model has no available capacity. Retry later or configure a supported lower-contention Gemini model before live eval."
|
|
39645
|
+
);
|
|
39646
|
+
}
|
|
39647
|
+
if (smoke.error || smoke.status !== 0 && !/Auth method|GEMINI_API_KEY|GOOGLE_GENAI_USE_VERTEXAI|GOOGLE_GENAI_USE_GCA/i.test(smokeText)) {
|
|
39648
|
+
if (smoke.error?.code === "ETIMEDOUT") {
|
|
39649
|
+
throw new ExternalAgentExecutorError(
|
|
39650
|
+
"external_agent_runner_headless_probe_timed_out",
|
|
39651
|
+
"Gemini runner headless invocation probe timed out before reaching an auth boundary or provider response."
|
|
39652
|
+
);
|
|
39653
|
+
}
|
|
39654
|
+
throw new ExternalAgentExecutorError(
|
|
39655
|
+
"external_agent_runner_headless_probe_failed",
|
|
39656
|
+
"Gemini runner headless invocation probe failed before reaching an auth boundary."
|
|
39657
|
+
);
|
|
39658
|
+
}
|
|
39614
39659
|
return {
|
|
39615
39660
|
runner: "gemini",
|
|
39616
39661
|
binaryChecked: true,
|
|
@@ -39623,6 +39668,9 @@ ${help.stderr}`;
|
|
|
39623
39668
|
supportsYoloAlias: helpText.includes("--yolo"),
|
|
39624
39669
|
yoloPolicy: helpText.includes("--yolo") ? "observed_not_canonical" : "unsupported",
|
|
39625
39670
|
supportsGeminiHeadless: true,
|
|
39671
|
+
supportsGeminiSandbox: geminiSandboxMode === "required",
|
|
39672
|
+
geminiSandboxMode,
|
|
39673
|
+
headlessInvocationChecked: true,
|
|
39626
39674
|
automationMode: "gemini-yolo",
|
|
39627
39675
|
globalArgs: [],
|
|
39628
39676
|
execArgs
|
|
@@ -39648,6 +39696,14 @@ function normalizeCodexSandboxMode(value) {
|
|
|
39648
39696
|
`Unsupported Codex sandbox mode: ${value}. Use workspace-write or danger-full-access.`
|
|
39649
39697
|
);
|
|
39650
39698
|
}
|
|
39699
|
+
function normalizeGeminiSandboxMode(value) {
|
|
39700
|
+
const normalized = (value || "required").trim().toLowerCase();
|
|
39701
|
+
if (normalized === "required" || normalized === "disabled") return normalized;
|
|
39702
|
+
throw new ExternalAgentExecutorError(
|
|
39703
|
+
"invalid_gemini_sandbox_mode",
|
|
39704
|
+
`Unsupported Gemini sandbox mode: ${value}. Use required or disabled.`
|
|
39705
|
+
);
|
|
39706
|
+
}
|
|
39651
39707
|
function codexConfigArgs(input) {
|
|
39652
39708
|
const args = [];
|
|
39653
39709
|
if (input.backend === "legacy-landlock") {
|
|
@@ -39798,7 +39854,12 @@ function createExternalAgentExecutorPlan(options) {
|
|
|
39798
39854
|
selected_automation_mode: runnerProbe.automationMode,
|
|
39799
39855
|
canonical_command_policy: "explicit-flags",
|
|
39800
39856
|
yolo_policy: runnerProbe.yoloPolicy,
|
|
39801
|
-
...runnerProbe.runner === "gemini" ? {
|
|
39857
|
+
...runnerProbe.runner === "gemini" ? {
|
|
39858
|
+
supports_gemini_headless: runnerProbe.supportsGeminiHeadless,
|
|
39859
|
+
supports_gemini_sandbox: runnerProbe.supportsGeminiSandbox,
|
|
39860
|
+
gemini_sandbox_mode: runnerProbe.geminiSandboxMode,
|
|
39861
|
+
headless_invocation_checked: runnerProbe.headlessInvocationChecked
|
|
39862
|
+
} : {}
|
|
39802
39863
|
},
|
|
39803
39864
|
runner_automation_mode: runnerProbe.automationMode,
|
|
39804
39865
|
codex_automation_mode: runner === "codex" ? runnerProbe.automationMode : null,
|
|
@@ -40276,6 +40337,34 @@ function executorRecoveryCommands(reasonCode, runner) {
|
|
|
40276
40337
|
"Upgrade or reinstall the runner CLI on the isolated eval host, then rerun the dry-run executor plan."
|
|
40277
40338
|
];
|
|
40278
40339
|
}
|
|
40340
|
+
if (reasonCode === "external_agent_runner_sandbox_unavailable") {
|
|
40341
|
+
return [
|
|
40342
|
+
"gemini --version",
|
|
40343
|
+
"gemini --help",
|
|
40344
|
+
"Install/configure Docker or Podman for Gemini sandboxing, or rerun only on an externally isolated host with `--gemini-sandbox-mode disabled` after confirming no private repo or runtime secrets are present."
|
|
40345
|
+
];
|
|
40346
|
+
}
|
|
40347
|
+
if (reasonCode === "external_agent_runner_headless_probe_failed") {
|
|
40348
|
+
return [
|
|
40349
|
+
`${normalizedRunner} --version`,
|
|
40350
|
+
`${normalizedRunner} --help`,
|
|
40351
|
+
"Upgrade, downgrade, or reconfigure the runner CLI until the planned non-interactive invocation reaches an auth boundary without parser errors."
|
|
40352
|
+
];
|
|
40353
|
+
}
|
|
40354
|
+
if (reasonCode === "external_agent_runner_headless_probe_timed_out") {
|
|
40355
|
+
return [
|
|
40356
|
+
`${normalizedRunner} --version`,
|
|
40357
|
+
`${normalizedRunner} --help`,
|
|
40358
|
+
"Retry the dry-run once. If it repeats, reduce the probe/model contention or use a different subscribed runner before launching live evals."
|
|
40359
|
+
];
|
|
40360
|
+
}
|
|
40361
|
+
if (reasonCode === "external_agent_runner_capacity_unavailable") {
|
|
40362
|
+
return [
|
|
40363
|
+
"gemini --version",
|
|
40364
|
+
"gemini --help",
|
|
40365
|
+
"Retry after the Gemini capacity window resets, or configure a supported lower-contention Gemini model before rerunning the same executor dry-run."
|
|
40366
|
+
];
|
|
40367
|
+
}
|
|
40279
40368
|
return [
|
|
40280
40369
|
"Fix the executor plan input or workspace path and rerun with --dry-run."
|
|
40281
40370
|
];
|
|
@@ -40586,7 +40675,7 @@ Exit the shell to finalize run.json.
|
|
|
40586
40675
|
}), { json: Boolean(opts.json) });
|
|
40587
40676
|
if (!report.ok) process.exitCode = 1;
|
|
40588
40677
|
});
|
|
40589
|
-
external.command("execute").description("Create a guarded dry-run executor plan for programmable external-agent runners").requiredOption("--batch <path>", "Path to external_agent_batch_plan.v1 batch.json").option("--runner <runner>", "Runner implementation", "codex").option("--workspace-root <path>", "Clean executor workspace root; must be outside the private repo").option("--private-repo-root <path>", "Private repository root to guard against").option("--timeout-minutes <minutes>", "Per-run timeout planned for future execution", "30").option("--codex-sandbox-backend <backend>", "Codex sandbox backend override: default|legacy-landlock", "default").option("--codex-sandbox-mode <mode>", "Codex sandbox mode: workspace-write|danger-full-access", "workspace-write").option("--codex-network-access", "Allow Codex workspace-write sandbox network access for public docs/npm probes").option("--skip-runner-probe", "Skip local runner binary/help probing").option("--dry-run", "Write the executor plan without launching the runner", true).option("--live", "Launch one controlled external-agent run after writing the guarded plan").option("--json", "Output as JSON").action(async (opts) => {
|
|
40678
|
+
external.command("execute").description("Create a guarded dry-run executor plan for programmable external-agent runners").requiredOption("--batch <path>", "Path to external_agent_batch_plan.v1 batch.json").option("--runner <runner>", "Runner implementation", "codex").option("--workspace-root <path>", "Clean executor workspace root; must be outside the private repo").option("--private-repo-root <path>", "Private repository root to guard against").option("--timeout-minutes <minutes>", "Per-run timeout planned for future execution", "30").option("--codex-sandbox-backend <backend>", "Codex sandbox backend override: default|legacy-landlock", "default").option("--codex-sandbox-mode <mode>", "Codex sandbox mode: workspace-write|danger-full-access", "workspace-write").option("--codex-network-access", "Allow Codex workspace-write sandbox network access for public docs/npm probes").option("--gemini-sandbox-mode <mode>", "Gemini sandbox mode: required|disabled", "required").option("--skip-runner-probe", "Skip local runner binary/help probing").option("--dry-run", "Write the executor plan without launching the runner", true).option("--live", "Launch one controlled external-agent run after writing the guarded plan").option("--json", "Output as JSON").action(async (opts) => {
|
|
40590
40679
|
try {
|
|
40591
40680
|
const plan = createExternalAgentExecutorPlan({
|
|
40592
40681
|
batchPath: String(opts.batch),
|
|
@@ -40597,6 +40686,7 @@ Exit the shell to finalize run.json.
|
|
|
40597
40686
|
codexSandboxBackend: String(opts.codexSandboxBackend || "default"),
|
|
40598
40687
|
codexSandboxMode: String(opts.codexSandboxMode || "workspace-write"),
|
|
40599
40688
|
codexNetworkAccess: Boolean(opts.codexNetworkAccess),
|
|
40689
|
+
geminiSandboxMode: String(opts.geminiSandboxMode || "required"),
|
|
40600
40690
|
skipRunnerProbe: Boolean(opts.skipRunnerProbe),
|
|
40601
40691
|
cwd: process.cwd()
|
|
40602
40692
|
});
|