@f-o-h/cli 0.1.15 → 0.1.17
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/README.md +41 -26
- package/dist/foh.js +194 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ AI-operator provisioning CLI for Front Of House.
|
|
|
4
4
|
|
|
5
5
|
Public mirror: https://github.com/iiko38/front-of-house-cli
|
|
6
6
|
|
|
7
|
-
Current published baseline: `@f-o-h/cli@0.1.
|
|
7
|
+
Current published baseline: `@f-o-h/cli@0.1.16`
|
|
8
8
|
|
|
9
9
|
This mirror is a generated release artifact. The private product monorepo is not
|
|
10
10
|
published here, and no open-source license is granted unless stated separately.
|
|
@@ -62,22 +62,22 @@ foh auth login --email "$FOH_EMAIL" --password "$FOH_PASSWORD" --json
|
|
|
62
62
|
foh org list --json
|
|
63
63
|
foh org use --org <org-id> --json
|
|
64
64
|
foh setup --org <org-id> --agent-template <template-id> --agent-name "Demo Agent" --json
|
|
65
|
-
foh prove --agent <agent-id> --json --out foh-proof.json
|
|
66
|
-
foh test run --suite ./suite.yml --agent <agent-id> --json --out foh-test-report.json
|
|
67
|
-
foh agent replay --file ./transcript-export.json --json
|
|
68
|
-
foh bug improve --from-file foh-proof.json --out foh-improvement.json --json
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Trusted server-side automation can use a scoped service token without browser
|
|
72
|
-
approval:
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
FOH_SERVICE_TOKEN="$FOH_SERVICE_TOKEN" FOH_ORG_ID="$FOH_ORG_ID" foh auth whoami --json
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
`auth signup --web` opens the console signup page when possible and always
|
|
79
|
-
prints the fallback URL. `auth login --web` starts browser device
|
|
80
|
-
authorization, opens `/cli-auth`, waits for console approval, and stores the
|
|
65
|
+
foh prove --agent <agent-id> --json --out foh-proof.json
|
|
66
|
+
foh test run --suite ./suite.yml --agent <agent-id> --json --out foh-test-report.json
|
|
67
|
+
foh agent replay --file ./transcript-export.json --json
|
|
68
|
+
foh bug improve --from-file foh-proof.json --out foh-improvement.json --json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Trusted server-side automation can use a scoped service token without browser
|
|
72
|
+
approval:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
FOH_SERVICE_TOKEN="$FOH_SERVICE_TOKEN" FOH_ORG_ID="$FOH_ORG_ID" foh auth whoami --json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`auth signup --web` opens the console signup page when possible and always
|
|
79
|
+
prints the fallback URL. `auth login --web` starts browser device
|
|
80
|
+
authorization, opens `/cli-auth`, waits for console approval, and stores the
|
|
81
81
|
returned short-lived token. Credential auth remains available as fallback.
|
|
82
82
|
|
|
83
83
|
`foh prove` produces a compact signed proof report across auth, org context,
|
|
@@ -144,15 +144,30 @@ After dry-run review, one controlled Codex run can be launched explicitly with
|
|
|
144
144
|
`run.json` even on timeout or non-zero exit:
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
|
-
foh eval external-agent execute \
|
|
148
|
-
--runner codex \
|
|
149
|
-
--batch test-results/external-agent-runs/<one-model-batch>/batch.json \
|
|
150
|
-
--timeout-minutes 30 \
|
|
151
|
-
--live \
|
|
152
|
-
--json
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
|
|
147
|
+
foh eval external-agent execute \
|
|
148
|
+
--runner codex \
|
|
149
|
+
--batch test-results/external-agent-runs/<one-model-batch>/batch.json \
|
|
150
|
+
--timeout-minutes 30 \
|
|
151
|
+
--live \
|
|
152
|
+
--json
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
For Linux eval hosts where Codex's default Bubblewrap sandbox cannot configure
|
|
156
|
+
loopback networking, keep sandboxing enabled and select the legacy Landlock
|
|
157
|
+
backend explicitly:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
foh eval external-agent execute \
|
|
161
|
+
--runner codex \
|
|
162
|
+
--batch test-results/external-agent-runs/<one-model-batch>/batch.json \
|
|
163
|
+
--codex-sandbox-backend legacy-landlock \
|
|
164
|
+
--codex-network-access \
|
|
165
|
+
--timeout-minutes 30 \
|
|
166
|
+
--live \
|
|
167
|
+
--json
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Local Scenario Suites
|
|
156
171
|
|
|
157
172
|
`foh test run --suite <file>` runs deterministic widget-runtime checks for a
|
|
158
173
|
specific agent. The suite format supports reply text checks plus structured
|
package/dist/foh.js
CHANGED
|
@@ -14637,9 +14637,9 @@ function registerAgent(program3) {
|
|
|
14637
14637
|
process.stdout.write(yaml);
|
|
14638
14638
|
return;
|
|
14639
14639
|
}
|
|
14640
|
-
const { writeFileSync:
|
|
14640
|
+
const { writeFileSync: writeFileSync10 } = await import("fs");
|
|
14641
14641
|
const outputPath = opts.output ?? "tenant.yaml";
|
|
14642
|
-
|
|
14642
|
+
writeFileSync10(
|
|
14643
14643
|
outputPath,
|
|
14644
14644
|
`# tenant.yaml - Front Of House agent manifest
|
|
14645
14645
|
# Edit this file and run: foh plan tenant.yaml
|
|
@@ -16074,11 +16074,11 @@ function registerVoice(program3) {
|
|
|
16074
16074
|
}
|
|
16075
16075
|
const outputPath = String(opts.out || `foh-voice-preview-${provider}-${voiceId}.mp3`).trim();
|
|
16076
16076
|
const audio = Buffer.from(await res.arrayBuffer());
|
|
16077
|
-
const { mkdirSync: mkdirSync7, writeFileSync:
|
|
16077
|
+
const { mkdirSync: mkdirSync7, writeFileSync: writeFileSync10 } = await import("fs");
|
|
16078
16078
|
const { dirname: dirname6, resolve: resolve12 } = await import("path");
|
|
16079
16079
|
const absolutePath = resolve12(outputPath);
|
|
16080
16080
|
mkdirSync7(dirname6(absolutePath), { recursive: true });
|
|
16081
|
-
|
|
16081
|
+
writeFileSync10(absolutePath, audio);
|
|
16082
16082
|
format({
|
|
16083
16083
|
status: "ok",
|
|
16084
16084
|
provider,
|
|
@@ -32681,7 +32681,7 @@ var StdioServerTransport = class {
|
|
|
32681
32681
|
};
|
|
32682
32682
|
|
|
32683
32683
|
// src/lib/cli-version.ts
|
|
32684
|
-
var CLI_VERSION = "0.1.
|
|
32684
|
+
var CLI_VERSION = "0.1.17";
|
|
32685
32685
|
|
|
32686
32686
|
// src/commands/mcp-serve.ts
|
|
32687
32687
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -34816,8 +34816,8 @@ function registerSetup(program3) {
|
|
|
34816
34816
|
}
|
|
34817
34817
|
try {
|
|
34818
34818
|
const manifest = await agentExport(resolvedAgentId, { apiUrlOverride: opts.apiUrl });
|
|
34819
|
-
const { writeFileSync:
|
|
34820
|
-
|
|
34819
|
+
const { writeFileSync: writeFileSync10 } = await import("fs");
|
|
34820
|
+
writeFileSync10(
|
|
34821
34821
|
"tenant.yaml",
|
|
34822
34822
|
`# tenant.yaml - Front Of House agent manifest
|
|
34823
34823
|
# Edit this file and run: foh plan tenant.yaml
|
|
@@ -34985,8 +34985,8 @@ function registerSim(program3) {
|
|
|
34985
34985
|
}
|
|
34986
34986
|
const cert = response.certificate;
|
|
34987
34987
|
if (opts.out) {
|
|
34988
|
-
const { writeFileSync:
|
|
34989
|
-
|
|
34988
|
+
const { writeFileSync: writeFileSync10 } = await import("fs");
|
|
34989
|
+
writeFileSync10(opts.out, JSON.stringify(cert, null, 2) + "\n", "utf-8");
|
|
34990
34990
|
process.stderr.write(` Certificate written to ${opts.out}
|
|
34991
34991
|
`);
|
|
34992
34992
|
}
|
|
@@ -35036,8 +35036,8 @@ function registerSim(program3) {
|
|
|
35036
35036
|
});
|
|
35037
35037
|
}
|
|
35038
35038
|
if (opts.out) {
|
|
35039
|
-
const { writeFileSync:
|
|
35040
|
-
|
|
35039
|
+
const { writeFileSync: writeFileSync10 } = await import("fs");
|
|
35040
|
+
writeFileSync10(opts.out, JSON.stringify(response.certificate, null, 2) + "\n", "utf-8");
|
|
35041
35041
|
process.stderr.write(` Final certificate written to ${opts.out}
|
|
35042
35042
|
`);
|
|
35043
35043
|
}
|
|
@@ -38376,7 +38376,8 @@ function artifactFiles(runDir) {
|
|
|
38376
38376
|
if (!(0, import_fs12.existsSync)(runDir)) return [];
|
|
38377
38377
|
return (0, import_fs12.readdirSync)(runDir).map((name) => (0, import_path10.join)(runDir, name)).filter((path2) => {
|
|
38378
38378
|
const stat = (0, import_fs12.statSync)(path2);
|
|
38379
|
-
|
|
38379
|
+
const name = path2.split(/[\\/]/).pop() || "";
|
|
38380
|
+
return stat.isFile() && (TEXT_ARTIFACT_NAMES.has(name) || name.startsWith("command-output-cmd_"));
|
|
38380
38381
|
}).sort();
|
|
38381
38382
|
}
|
|
38382
38383
|
function finding(kind, file2, count) {
|
|
@@ -38465,30 +38466,154 @@ function getExternalAgentRunDir() {
|
|
|
38465
38466
|
if (!raw || !raw.trim()) return null;
|
|
38466
38467
|
return (0, import_path11.resolve)(raw);
|
|
38467
38468
|
}
|
|
38469
|
+
function commandIdFor(input) {
|
|
38470
|
+
const seed = `${input.startedAt}:${input.argv.join("\0")}:${process.pid}`;
|
|
38471
|
+
let hash2 = 2166136261;
|
|
38472
|
+
for (let i = 0; i < seed.length; i += 1) {
|
|
38473
|
+
hash2 ^= seed.charCodeAt(i);
|
|
38474
|
+
hash2 = Math.imul(hash2, 16777619);
|
|
38475
|
+
}
|
|
38476
|
+
return `cmd_${(hash2 >>> 0).toString(16).padStart(8, "0")}`;
|
|
38477
|
+
}
|
|
38478
|
+
function outputArtifactName(commandId) {
|
|
38479
|
+
return `command-output-${commandId}.txt`;
|
|
38480
|
+
}
|
|
38481
|
+
function parseEnvelope(text) {
|
|
38482
|
+
const candidates = [
|
|
38483
|
+
...text.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.startsWith("{") && line.endsWith("}")).reverse()
|
|
38484
|
+
];
|
|
38485
|
+
const firstObject = text.indexOf("{");
|
|
38486
|
+
const lastObject = text.lastIndexOf("}");
|
|
38487
|
+
if (firstObject >= 0 && lastObject > firstObject) candidates.push(text.slice(firstObject, lastObject + 1));
|
|
38488
|
+
for (const candidate of candidates) {
|
|
38489
|
+
try {
|
|
38490
|
+
const parsed = JSON.parse(candidate);
|
|
38491
|
+
const status = typeof parsed.status === "string" ? parsed.status : parsed.ok === true ? "pass" : parsed.ok === false ? "fail" : null;
|
|
38492
|
+
const reasonCode = typeof parsed.reason_code === "string" ? parsed.reason_code : typeof parsed.code === "string" ? parsed.code : null;
|
|
38493
|
+
if (status || reasonCode) return { status, reasonCode };
|
|
38494
|
+
} catch {
|
|
38495
|
+
}
|
|
38496
|
+
}
|
|
38497
|
+
return { status: null, reasonCode: null };
|
|
38498
|
+
}
|
|
38468
38499
|
function recordExternalAgentCliInvocation(input) {
|
|
38469
38500
|
const runDir = getExternalAgentRunDir();
|
|
38470
|
-
if (!runDir) return;
|
|
38501
|
+
if (!runDir) return null;
|
|
38471
38502
|
try {
|
|
38472
38503
|
(0, import_fs13.mkdirSync)(runDir, { recursive: true });
|
|
38504
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
38473
38505
|
const args = input.argv.slice(2).map((arg) => redactText(String(arg)));
|
|
38506
|
+
const commandId = commandIdFor({ startedAt, argv: args });
|
|
38507
|
+
const promptVersion = process.env[EXTERNAL_AGENT_PROMPT_VERSION_ENV] || null;
|
|
38508
|
+
const cwd = redactPath(process.cwd());
|
|
38474
38509
|
const record2 = {
|
|
38475
|
-
schema_version: "external_agent_cli_command.
|
|
38476
|
-
|
|
38510
|
+
schema_version: "external_agent_cli_command.v2",
|
|
38511
|
+
command_id: commandId,
|
|
38512
|
+
phase: "started",
|
|
38513
|
+
recorded_at: startedAt,
|
|
38477
38514
|
cli_version: input.cliVersion,
|
|
38478
|
-
cwd
|
|
38515
|
+
cwd,
|
|
38479
38516
|
argv: args,
|
|
38480
38517
|
command: args.join(" "),
|
|
38481
38518
|
json_requested: args.includes("--json"),
|
|
38482
|
-
prompt_version:
|
|
38519
|
+
prompt_version: promptVersion,
|
|
38520
|
+
started_at: startedAt
|
|
38483
38521
|
};
|
|
38484
38522
|
(0, import_fs13.appendFileSync)((0, import_path11.join)(runDir, "commands.ndjson"), safeJsonLine(record2), "utf8");
|
|
38523
|
+
return {
|
|
38524
|
+
commandId,
|
|
38525
|
+
runDir,
|
|
38526
|
+
startedAt,
|
|
38527
|
+
cliVersion: input.cliVersion,
|
|
38528
|
+
cwd,
|
|
38529
|
+
argv: args,
|
|
38530
|
+
command: args.join(" "),
|
|
38531
|
+
jsonRequested: args.includes("--json"),
|
|
38532
|
+
promptVersion
|
|
38533
|
+
};
|
|
38485
38534
|
} catch {
|
|
38535
|
+
return null;
|
|
38536
|
+
}
|
|
38537
|
+
}
|
|
38538
|
+
function installExternalAgentCliCompletionRecorder(capture) {
|
|
38539
|
+
if (!capture) return;
|
|
38540
|
+
const chunks = [];
|
|
38541
|
+
const maxChars = 256 * 1024;
|
|
38542
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
38543
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
38544
|
+
function captureChunk(chunk) {
|
|
38545
|
+
if (typeof chunk === "string") {
|
|
38546
|
+
if (chunks.join("").length < maxChars) chunks.push(chunk.slice(0, maxChars));
|
|
38547
|
+
return;
|
|
38548
|
+
}
|
|
38549
|
+
if (Buffer.isBuffer(chunk)) {
|
|
38550
|
+
if (chunks.join("").length < maxChars) chunks.push(chunk.toString("utf8").slice(0, maxChars));
|
|
38551
|
+
}
|
|
38486
38552
|
}
|
|
38553
|
+
process.stdout.write = ((chunk, ...args) => {
|
|
38554
|
+
captureChunk(chunk);
|
|
38555
|
+
return originalStdoutWrite(chunk, ...args);
|
|
38556
|
+
});
|
|
38557
|
+
process.stderr.write = ((chunk, ...args) => {
|
|
38558
|
+
captureChunk(chunk);
|
|
38559
|
+
return originalStderrWrite(chunk, ...args);
|
|
38560
|
+
});
|
|
38561
|
+
process.once("exit", (code) => {
|
|
38562
|
+
try {
|
|
38563
|
+
process.stdout.write = originalStdoutWrite;
|
|
38564
|
+
process.stderr.write = originalStderrWrite;
|
|
38565
|
+
const output = redactPath(chunks.join("").slice(0, maxChars));
|
|
38566
|
+
completeExternalAgentCliInvocation(capture, {
|
|
38567
|
+
output,
|
|
38568
|
+
exitCode: Number.isInteger(code) ? code : process.exitCode && Number.isInteger(process.exitCode) ? Number(process.exitCode) : null
|
|
38569
|
+
});
|
|
38570
|
+
} catch {
|
|
38571
|
+
}
|
|
38572
|
+
});
|
|
38573
|
+
}
|
|
38574
|
+
function completeExternalAgentCliInvocation(capture, input) {
|
|
38575
|
+
const completedAt = input.completedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
38576
|
+
const output = redactPath(String(input.output || "").slice(0, 256 * 1024));
|
|
38577
|
+
const parsed = parseEnvelope(output);
|
|
38578
|
+
let artifact = null;
|
|
38579
|
+
if (output.trim()) {
|
|
38580
|
+
artifact = outputArtifactName(capture.commandId);
|
|
38581
|
+
(0, import_fs13.writeFileSync)((0, import_path11.join)(capture.runDir, artifact), output, "utf8");
|
|
38582
|
+
}
|
|
38583
|
+
const record2 = {
|
|
38584
|
+
schema_version: "external_agent_cli_command.v2",
|
|
38585
|
+
command_id: capture.commandId,
|
|
38586
|
+
phase: "completed",
|
|
38587
|
+
recorded_at: completedAt,
|
|
38588
|
+
cli_version: capture.cliVersion,
|
|
38589
|
+
cwd: capture.cwd,
|
|
38590
|
+
argv: capture.argv,
|
|
38591
|
+
command: capture.command,
|
|
38592
|
+
json_requested: capture.jsonRequested,
|
|
38593
|
+
prompt_version: capture.promptVersion,
|
|
38594
|
+
started_at: capture.startedAt,
|
|
38595
|
+
completed_at: completedAt,
|
|
38596
|
+
duration_ms: Math.max(0, Date.parse(completedAt) - Date.parse(capture.startedAt)),
|
|
38597
|
+
exit_code: Number.isInteger(input.exitCode) ? Number(input.exitCode) : null,
|
|
38598
|
+
status: parsed.status,
|
|
38599
|
+
reason_code: parsed.reasonCode,
|
|
38600
|
+
output_artifact: artifact,
|
|
38601
|
+
output_bytes: Buffer.byteLength(output, "utf8")
|
|
38602
|
+
};
|
|
38603
|
+
(0, import_fs13.appendFileSync)((0, import_path11.join)(capture.runDir, "commands.ndjson"), safeJsonLine(record2), "utf8");
|
|
38487
38604
|
}
|
|
38488
38605
|
function readCommandRecords(runDir) {
|
|
38489
38606
|
const commandLogPath = (0, import_path11.join)(runDir, "commands.ndjson");
|
|
38490
38607
|
if (!(0, import_fs13.existsSync)(commandLogPath)) return [];
|
|
38491
|
-
|
|
38608
|
+
const records = (0, import_fs13.readFileSync)(commandLogPath, "utf8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => JSON.parse(line));
|
|
38609
|
+
const byId = /* @__PURE__ */ new Map();
|
|
38610
|
+
const ordered = [];
|
|
38611
|
+
for (const record2 of records) {
|
|
38612
|
+
const id = record2.command_id || `${record2.recorded_at}:${record2.command}`;
|
|
38613
|
+
if (!byId.has(id)) ordered.push(record2);
|
|
38614
|
+
byId.set(id, record2.phase === "completed" ? record2 : byId.get(id) ?? record2);
|
|
38615
|
+
}
|
|
38616
|
+
return ordered.map((record2) => byId.get(record2.command_id || `${record2.recorded_at}:${record2.command}`) || record2);
|
|
38492
38617
|
}
|
|
38493
38618
|
|
|
38494
38619
|
// src/lib/external-agent-executor.ts
|
|
@@ -38662,6 +38787,29 @@ ${help.stderr}`;
|
|
|
38662
38787
|
}
|
|
38663
38788
|
return { binaryChecked: true, requiredFlagsChecked: true };
|
|
38664
38789
|
}
|
|
38790
|
+
function normalizeCodexSandboxBackend(value) {
|
|
38791
|
+
const normalized = (value || "default").trim().toLowerCase();
|
|
38792
|
+
if (normalized === "default" || normalized === "legacy-landlock") return normalized;
|
|
38793
|
+
throw new ExternalAgentExecutorError(
|
|
38794
|
+
"invalid_codex_sandbox_backend",
|
|
38795
|
+
`Unsupported Codex sandbox backend: ${value}. Use default or legacy-landlock.`
|
|
38796
|
+
);
|
|
38797
|
+
}
|
|
38798
|
+
function codexConfigArgs(input) {
|
|
38799
|
+
const args = [];
|
|
38800
|
+
if (input.backend === "legacy-landlock") {
|
|
38801
|
+
args.push(
|
|
38802
|
+
"-c",
|
|
38803
|
+
"features.use_legacy_landlock=true",
|
|
38804
|
+
"-c",
|
|
38805
|
+
"features.use_linux_sandbox_bwrap=false"
|
|
38806
|
+
);
|
|
38807
|
+
}
|
|
38808
|
+
if (input.networkAccess) {
|
|
38809
|
+
args.push("-c", "sandbox_workspace_write.network_access=true");
|
|
38810
|
+
}
|
|
38811
|
+
return args;
|
|
38812
|
+
}
|
|
38665
38813
|
function safeRunId(value) {
|
|
38666
38814
|
return value.toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "") || "run";
|
|
38667
38815
|
}
|
|
@@ -38684,6 +38832,8 @@ function createExternalAgentExecutorPlan(options) {
|
|
|
38684
38832
|
const batchPath = (0, import_path12.resolve)(options.batchPath);
|
|
38685
38833
|
const batch = readBatch(batchPath);
|
|
38686
38834
|
const runnerProbe = validateCodexRunner(options);
|
|
38835
|
+
const codexSandboxBackend = normalizeCodexSandboxBackend(options.codexSandboxBackend);
|
|
38836
|
+
const codexNetworkAccess = options.codexNetworkAccess === true;
|
|
38687
38837
|
const privateRepoRoot = (0, import_path12.resolve)(options.privateRepoRoot || options.cwd || process.cwd());
|
|
38688
38838
|
const workspaceRoot = resolveWorkspaceRoot({ batchPath, workspaceRoot: options.workspaceRoot, privateRepoRoot });
|
|
38689
38839
|
if (isPathInside(workspaceRoot, privateRepoRoot)) {
|
|
@@ -38726,6 +38876,7 @@ function createExternalAgentExecutorPlan(options) {
|
|
|
38726
38876
|
const artifactSafetyPath = (0, import_path12.join)(runDir, "artifact-safety.json");
|
|
38727
38877
|
const args = [
|
|
38728
38878
|
"exec",
|
|
38879
|
+
...codexConfigArgs({ backend: codexSandboxBackend, networkAccess: codexNetworkAccess }),
|
|
38729
38880
|
"--cd",
|
|
38730
38881
|
workspaceDir,
|
|
38731
38882
|
"--skip-git-repo-check",
|
|
@@ -38778,7 +38929,9 @@ function createExternalAgentExecutorPlan(options) {
|
|
|
38778
38929
|
runner_probe: {
|
|
38779
38930
|
binary_checked: runnerProbe.binaryChecked,
|
|
38780
38931
|
required_flags_checked: runnerProbe.requiredFlagsChecked
|
|
38781
|
-
}
|
|
38932
|
+
},
|
|
38933
|
+
codex_sandbox_backend: codexSandboxBackend,
|
|
38934
|
+
codex_network_access: codexNetworkAccess
|
|
38782
38935
|
},
|
|
38783
38936
|
runs
|
|
38784
38937
|
};
|
|
@@ -38835,6 +38988,24 @@ ${stderr}`;
|
|
|
38835
38988
|
if (/(?:blocked|rejected|declined) by policy|EXEC_POLICY_BLOCKED|command execution was rejected|shell commands were rejected/i.test(combined)) {
|
|
38836
38989
|
return { status: "hold", reasonCode: "codex_exec_policy_blocked" };
|
|
38837
38990
|
}
|
|
38991
|
+
if (/bwrap:.*(?:RTM_NEWADDR|Operation not permitted)|bubblewrap.*(?:RTM_NEWADDR|Operation not permitted)|Failed RTM_NEWADDR|ENV_SANDBOX_EXEC_BLOCKED/i.test(combined)) {
|
|
38992
|
+
return { status: "hold", reasonCode: "codex_sandbox_exec_blocked" };
|
|
38993
|
+
}
|
|
38994
|
+
if (/ENV_NETWORK_DNS_BLOCK|Could not resolve host|npm ping.*timeout|NO_EXECUTABLE_INSTALL/i.test(combined)) {
|
|
38995
|
+
return { status: "hold", reasonCode: "codex_network_dns_blocked" };
|
|
38996
|
+
}
|
|
38997
|
+
if (/contact_phone_missing/i.test(combined)) {
|
|
38998
|
+
return { status: "hold", reasonCode: "voice_contact_phone_missing" };
|
|
38999
|
+
}
|
|
39000
|
+
if (/simulation_certification_failed/i.test(combined)) {
|
|
39001
|
+
return { status: "hold", reasonCode: "simulation_certification_failed" };
|
|
39002
|
+
}
|
|
39003
|
+
if (/proof_held/i.test(combined)) {
|
|
39004
|
+
return { status: "hold", reasonCode: "external_agent_proof_held" };
|
|
39005
|
+
}
|
|
39006
|
+
if (/agent_limit_reached/i.test(combined)) {
|
|
39007
|
+
return { status: "hold", reasonCode: "eval_org_agent_limit_reached" };
|
|
39008
|
+
}
|
|
38838
39009
|
if (/browser|approve|approval|login|auth|sign in/i.test(combined) && !proofArtifactPasses(input.run.run_dir)) {
|
|
38839
39010
|
return { status: "hold", reasonCode: "auth_browser_approval_required" };
|
|
38840
39011
|
}
|
|
@@ -39298,7 +39469,7 @@ Exit the shell to finalize run.json.
|
|
|
39298
39469
|
}), { json: Boolean(opts.json) });
|
|
39299
39470
|
if (!report.ok) process.exitCode = 1;
|
|
39300
39471
|
});
|
|
39301
|
-
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("--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) => {
|
|
39472
|
+
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-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) => {
|
|
39302
39473
|
try {
|
|
39303
39474
|
const plan = createExternalAgentExecutorPlan({
|
|
39304
39475
|
batchPath: String(opts.batch),
|
|
@@ -39306,6 +39477,8 @@ Exit the shell to finalize run.json.
|
|
|
39306
39477
|
workspaceRoot: opts.workspaceRoot ? String(opts.workspaceRoot) : void 0,
|
|
39307
39478
|
privateRepoRoot: opts.privateRepoRoot ? String(opts.privateRepoRoot) : void 0,
|
|
39308
39479
|
timeoutMinutes: Number(opts.timeoutMinutes || 30),
|
|
39480
|
+
codexSandboxBackend: String(opts.codexSandboxBackend || "default"),
|
|
39481
|
+
codexNetworkAccess: Boolean(opts.codexNetworkAccess),
|
|
39309
39482
|
skipRunnerProbe: Boolean(opts.skipRunnerProbe),
|
|
39310
39483
|
cwd: process.cwd()
|
|
39311
39484
|
});
|
|
@@ -39453,7 +39626,7 @@ function installSoftExitTrap() {
|
|
|
39453
39626
|
|
|
39454
39627
|
// src/index.ts
|
|
39455
39628
|
installSoftExitTrap();
|
|
39456
|
-
recordExternalAgentCliInvocation({ argv: process.argv, cliVersion: CLI_VERSION });
|
|
39629
|
+
installExternalAgentCliCompletionRecorder(recordExternalAgentCliInvocation({ argv: process.argv, cliVersion: CLI_VERSION }));
|
|
39457
39630
|
var program2 = new Command();
|
|
39458
39631
|
var BUG_REPORT_URL = process.env.FOH_BUG_REPORT_URL ?? "https://github.com/iiko38/front-of-house/issues";
|
|
39459
39632
|
function shouldRenderBanner2(argv) {
|