@f-o-h/cli 0.1.15 → 0.1.16
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 +51 -3
- 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
|
@@ -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.16";
|
|
32685
32685
|
|
|
32686
32686
|
// src/commands/mcp-serve.ts
|
|
32687
32687
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -38662,6 +38662,29 @@ ${help.stderr}`;
|
|
|
38662
38662
|
}
|
|
38663
38663
|
return { binaryChecked: true, requiredFlagsChecked: true };
|
|
38664
38664
|
}
|
|
38665
|
+
function normalizeCodexSandboxBackend(value) {
|
|
38666
|
+
const normalized = (value || "default").trim().toLowerCase();
|
|
38667
|
+
if (normalized === "default" || normalized === "legacy-landlock") return normalized;
|
|
38668
|
+
throw new ExternalAgentExecutorError(
|
|
38669
|
+
"invalid_codex_sandbox_backend",
|
|
38670
|
+
`Unsupported Codex sandbox backend: ${value}. Use default or legacy-landlock.`
|
|
38671
|
+
);
|
|
38672
|
+
}
|
|
38673
|
+
function codexConfigArgs(input) {
|
|
38674
|
+
const args = [];
|
|
38675
|
+
if (input.backend === "legacy-landlock") {
|
|
38676
|
+
args.push(
|
|
38677
|
+
"-c",
|
|
38678
|
+
"features.use_legacy_landlock=true",
|
|
38679
|
+
"-c",
|
|
38680
|
+
"features.use_linux_sandbox_bwrap=false"
|
|
38681
|
+
);
|
|
38682
|
+
}
|
|
38683
|
+
if (input.networkAccess) {
|
|
38684
|
+
args.push("-c", "sandbox_workspace_write.network_access=true");
|
|
38685
|
+
}
|
|
38686
|
+
return args;
|
|
38687
|
+
}
|
|
38665
38688
|
function safeRunId(value) {
|
|
38666
38689
|
return value.toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "") || "run";
|
|
38667
38690
|
}
|
|
@@ -38684,6 +38707,8 @@ function createExternalAgentExecutorPlan(options) {
|
|
|
38684
38707
|
const batchPath = (0, import_path12.resolve)(options.batchPath);
|
|
38685
38708
|
const batch = readBatch(batchPath);
|
|
38686
38709
|
const runnerProbe = validateCodexRunner(options);
|
|
38710
|
+
const codexSandboxBackend = normalizeCodexSandboxBackend(options.codexSandboxBackend);
|
|
38711
|
+
const codexNetworkAccess = options.codexNetworkAccess === true;
|
|
38687
38712
|
const privateRepoRoot = (0, import_path12.resolve)(options.privateRepoRoot || options.cwd || process.cwd());
|
|
38688
38713
|
const workspaceRoot = resolveWorkspaceRoot({ batchPath, workspaceRoot: options.workspaceRoot, privateRepoRoot });
|
|
38689
38714
|
if (isPathInside(workspaceRoot, privateRepoRoot)) {
|
|
@@ -38726,6 +38751,7 @@ function createExternalAgentExecutorPlan(options) {
|
|
|
38726
38751
|
const artifactSafetyPath = (0, import_path12.join)(runDir, "artifact-safety.json");
|
|
38727
38752
|
const args = [
|
|
38728
38753
|
"exec",
|
|
38754
|
+
...codexConfigArgs({ backend: codexSandboxBackend, networkAccess: codexNetworkAccess }),
|
|
38729
38755
|
"--cd",
|
|
38730
38756
|
workspaceDir,
|
|
38731
38757
|
"--skip-git-repo-check",
|
|
@@ -38778,7 +38804,9 @@ function createExternalAgentExecutorPlan(options) {
|
|
|
38778
38804
|
runner_probe: {
|
|
38779
38805
|
binary_checked: runnerProbe.binaryChecked,
|
|
38780
38806
|
required_flags_checked: runnerProbe.requiredFlagsChecked
|
|
38781
|
-
}
|
|
38807
|
+
},
|
|
38808
|
+
codex_sandbox_backend: codexSandboxBackend,
|
|
38809
|
+
codex_network_access: codexNetworkAccess
|
|
38782
38810
|
},
|
|
38783
38811
|
runs
|
|
38784
38812
|
};
|
|
@@ -38835,6 +38863,24 @@ ${stderr}`;
|
|
|
38835
38863
|
if (/(?:blocked|rejected|declined) by policy|EXEC_POLICY_BLOCKED|command execution was rejected|shell commands were rejected/i.test(combined)) {
|
|
38836
38864
|
return { status: "hold", reasonCode: "codex_exec_policy_blocked" };
|
|
38837
38865
|
}
|
|
38866
|
+
if (/bwrap:.*(?:RTM_NEWADDR|Operation not permitted)|bubblewrap.*(?:RTM_NEWADDR|Operation not permitted)|Failed RTM_NEWADDR|ENV_SANDBOX_EXEC_BLOCKED/i.test(combined)) {
|
|
38867
|
+
return { status: "hold", reasonCode: "codex_sandbox_exec_blocked" };
|
|
38868
|
+
}
|
|
38869
|
+
if (/ENV_NETWORK_DNS_BLOCK|Could not resolve host|npm ping.*timeout|NO_EXECUTABLE_INSTALL/i.test(combined)) {
|
|
38870
|
+
return { status: "hold", reasonCode: "codex_network_dns_blocked" };
|
|
38871
|
+
}
|
|
38872
|
+
if (/contact_phone_missing/i.test(combined)) {
|
|
38873
|
+
return { status: "hold", reasonCode: "voice_contact_phone_missing" };
|
|
38874
|
+
}
|
|
38875
|
+
if (/simulation_certification_failed/i.test(combined)) {
|
|
38876
|
+
return { status: "hold", reasonCode: "simulation_certification_failed" };
|
|
38877
|
+
}
|
|
38878
|
+
if (/proof_held/i.test(combined)) {
|
|
38879
|
+
return { status: "hold", reasonCode: "external_agent_proof_held" };
|
|
38880
|
+
}
|
|
38881
|
+
if (/agent_limit_reached/i.test(combined)) {
|
|
38882
|
+
return { status: "hold", reasonCode: "eval_org_agent_limit_reached" };
|
|
38883
|
+
}
|
|
38838
38884
|
if (/browser|approve|approval|login|auth|sign in/i.test(combined) && !proofArtifactPasses(input.run.run_dir)) {
|
|
38839
38885
|
return { status: "hold", reasonCode: "auth_browser_approval_required" };
|
|
38840
38886
|
}
|
|
@@ -39298,7 +39344,7 @@ Exit the shell to finalize run.json.
|
|
|
39298
39344
|
}), { json: Boolean(opts.json) });
|
|
39299
39345
|
if (!report.ok) process.exitCode = 1;
|
|
39300
39346
|
});
|
|
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) => {
|
|
39347
|
+
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
39348
|
try {
|
|
39303
39349
|
const plan = createExternalAgentExecutorPlan({
|
|
39304
39350
|
batchPath: String(opts.batch),
|
|
@@ -39306,6 +39352,8 @@ Exit the shell to finalize run.json.
|
|
|
39306
39352
|
workspaceRoot: opts.workspaceRoot ? String(opts.workspaceRoot) : void 0,
|
|
39307
39353
|
privateRepoRoot: opts.privateRepoRoot ? String(opts.privateRepoRoot) : void 0,
|
|
39308
39354
|
timeoutMinutes: Number(opts.timeoutMinutes || 30),
|
|
39355
|
+
codexSandboxBackend: String(opts.codexSandboxBackend || "default"),
|
|
39356
|
+
codexNetworkAccess: Boolean(opts.codexNetworkAccess),
|
|
39309
39357
|
skipRunnerProbe: Boolean(opts.skipRunnerProbe),
|
|
39310
39358
|
cwd: process.cwd()
|
|
39311
39359
|
});
|