@f-o-h/cli 0.1.57 → 0.1.58

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.
Files changed (2) hide show
  1. package/dist/foh.js +63 -8
  2. 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.57";
32856
+ var CLI_VERSION = "0.1.58";
32857
32857
 
32858
32858
  // src/commands/mcp-serve.ts
32859
32859
  var DEFAULT_TIMEOUT_MS = 12e4;
@@ -39562,15 +39562,14 @@ ${yoloHelp.stderr}`;
39562
39562
  };
39563
39563
  }
39564
39564
  function validateGeminiRunner(options) {
39565
+ const geminiSandboxMode = normalizeGeminiSandboxMode(options.geminiSandboxMode);
39565
39566
  const execArgs = [
39566
39567
  "--approval-mode",
39567
39568
  "yolo",
39568
- "--sandbox",
39569
39569
  "--output-format",
39570
- "stream-json",
39571
- "--prompt",
39572
- "Execute the FOH external-agent prompt supplied on stdin."
39570
+ "stream-json"
39573
39571
  ];
39572
+ if (geminiSandboxMode === "required") execArgs.splice(2, 0, "--sandbox");
39574
39573
  if (options.skipRunnerProbe) {
39575
39574
  return {
39576
39575
  runner: "gemini",
@@ -39584,6 +39583,9 @@ function validateGeminiRunner(options) {
39584
39583
  supportsYoloAlias: null,
39585
39584
  yoloPolicy: "not_checked",
39586
39585
  supportsGeminiHeadless: true,
39586
+ supportsGeminiSandbox: geminiSandboxMode === "required",
39587
+ geminiSandboxMode,
39588
+ headlessInvocationChecked: false,
39587
39589
  automationMode: "gemini-yolo",
39588
39590
  globalArgs: [],
39589
39591
  execArgs
@@ -39603,7 +39605,8 @@ ${version2.stderr}`.trim() || null;
39603
39605
  }
39604
39606
  const helpText = `${help.stdout}
39605
39607
  ${help.stderr}`;
39606
- const requiredFlags = ["--prompt", "--approval-mode", "--sandbox", "--output-format"];
39608
+ const requiredFlags = ["--approval-mode", "--output-format"];
39609
+ if (geminiSandboxMode === "required") requiredFlags.push("--sandbox");
39607
39610
  const missing = requiredFlags.filter((flag) => !helpText.includes(flag));
39608
39611
  if (missing.length > 0) {
39609
39612
  throw new ExternalAgentExecutorError(
@@ -39611,6 +39614,27 @@ ${help.stderr}`;
39611
39614
  `Gemini runner is missing required headless flag(s): ${missing.join(", ")}`
39612
39615
  );
39613
39616
  }
39617
+ const smoke = probe(probeCommand, [...execArgs, "FOH_GEMINI_HEADLESS_PROBE"]);
39618
+ const smokeText = `${smoke.stdout}
39619
+ ${smoke.stderr}`;
39620
+ if (/Cannot use both a positional prompt and the --prompt/i.test(smokeText)) {
39621
+ throw new ExternalAgentExecutorError(
39622
+ "external_agent_runner_headless_probe_failed",
39623
+ "Gemini runner rejected the planned headless invocation before auth."
39624
+ );
39625
+ }
39626
+ if (/GEMINI_SANDBOX.*failed|failed to determine command for sandbox|install docker or podman/i.test(smokeText)) {
39627
+ throw new ExternalAgentExecutorError(
39628
+ "external_agent_runner_sandbox_unavailable",
39629
+ "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."
39630
+ );
39631
+ }
39632
+ if (smoke.error || smoke.status !== 0 && !/Auth method|GEMINI_API_KEY|GOOGLE_GENAI_USE_VERTEXAI|GOOGLE_GENAI_USE_GCA/i.test(smokeText)) {
39633
+ throw new ExternalAgentExecutorError(
39634
+ "external_agent_runner_headless_probe_failed",
39635
+ "Gemini runner headless invocation probe failed before reaching an auth boundary."
39636
+ );
39637
+ }
39614
39638
  return {
39615
39639
  runner: "gemini",
39616
39640
  binaryChecked: true,
@@ -39623,6 +39647,9 @@ ${help.stderr}`;
39623
39647
  supportsYoloAlias: helpText.includes("--yolo"),
39624
39648
  yoloPolicy: helpText.includes("--yolo") ? "observed_not_canonical" : "unsupported",
39625
39649
  supportsGeminiHeadless: true,
39650
+ supportsGeminiSandbox: geminiSandboxMode === "required",
39651
+ geminiSandboxMode,
39652
+ headlessInvocationChecked: true,
39626
39653
  automationMode: "gemini-yolo",
39627
39654
  globalArgs: [],
39628
39655
  execArgs
@@ -39648,6 +39675,14 @@ function normalizeCodexSandboxMode(value) {
39648
39675
  `Unsupported Codex sandbox mode: ${value}. Use workspace-write or danger-full-access.`
39649
39676
  );
39650
39677
  }
39678
+ function normalizeGeminiSandboxMode(value) {
39679
+ const normalized = (value || "required").trim().toLowerCase();
39680
+ if (normalized === "required" || normalized === "disabled") return normalized;
39681
+ throw new ExternalAgentExecutorError(
39682
+ "invalid_gemini_sandbox_mode",
39683
+ `Unsupported Gemini sandbox mode: ${value}. Use required or disabled.`
39684
+ );
39685
+ }
39651
39686
  function codexConfigArgs(input) {
39652
39687
  const args = [];
39653
39688
  if (input.backend === "legacy-landlock") {
@@ -39798,7 +39833,12 @@ function createExternalAgentExecutorPlan(options) {
39798
39833
  selected_automation_mode: runnerProbe.automationMode,
39799
39834
  canonical_command_policy: "explicit-flags",
39800
39835
  yolo_policy: runnerProbe.yoloPolicy,
39801
- ...runnerProbe.runner === "gemini" ? { supports_gemini_headless: runnerProbe.supportsGeminiHeadless } : {}
39836
+ ...runnerProbe.runner === "gemini" ? {
39837
+ supports_gemini_headless: runnerProbe.supportsGeminiHeadless,
39838
+ supports_gemini_sandbox: runnerProbe.supportsGeminiSandbox,
39839
+ gemini_sandbox_mode: runnerProbe.geminiSandboxMode,
39840
+ headless_invocation_checked: runnerProbe.headlessInvocationChecked
39841
+ } : {}
39802
39842
  },
39803
39843
  runner_automation_mode: runnerProbe.automationMode,
39804
39844
  codex_automation_mode: runner === "codex" ? runnerProbe.automationMode : null,
@@ -40276,6 +40316,20 @@ function executorRecoveryCommands(reasonCode, runner) {
40276
40316
  "Upgrade or reinstall the runner CLI on the isolated eval host, then rerun the dry-run executor plan."
40277
40317
  ];
40278
40318
  }
40319
+ if (reasonCode === "external_agent_runner_sandbox_unavailable") {
40320
+ return [
40321
+ "gemini --version",
40322
+ "gemini --help",
40323
+ "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."
40324
+ ];
40325
+ }
40326
+ if (reasonCode === "external_agent_runner_headless_probe_failed") {
40327
+ return [
40328
+ `${normalizedRunner} --version`,
40329
+ `${normalizedRunner} --help`,
40330
+ "Upgrade, downgrade, or reconfigure the runner CLI until the planned non-interactive invocation reaches an auth boundary without parser errors."
40331
+ ];
40332
+ }
40279
40333
  return [
40280
40334
  "Fix the executor plan input or workspace path and rerun with --dry-run."
40281
40335
  ];
@@ -40586,7 +40640,7 @@ Exit the shell to finalize run.json.
40586
40640
  }), { json: Boolean(opts.json) });
40587
40641
  if (!report.ok) process.exitCode = 1;
40588
40642
  });
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) => {
40643
+ 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
40644
  try {
40591
40645
  const plan = createExternalAgentExecutorPlan({
40592
40646
  batchPath: String(opts.batch),
@@ -40597,6 +40651,7 @@ Exit the shell to finalize run.json.
40597
40651
  codexSandboxBackend: String(opts.codexSandboxBackend || "default"),
40598
40652
  codexSandboxMode: String(opts.codexSandboxMode || "workspace-write"),
40599
40653
  codexNetworkAccess: Boolean(opts.codexNetworkAccess),
40654
+ geminiSandboxMode: String(opts.geminiSandboxMode || "required"),
40600
40655
  skipRunnerProbe: Boolean(opts.skipRunnerProbe),
40601
40656
  cwd: process.cwd()
40602
40657
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@f-o-h/cli",
3
- "version": "0.1.57",
3
+ "version": "0.1.58",
4
4
  "description": "FOH CLI - AI-operator provisioning tool for Front Of House",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {