@f-o-h/cli 0.1.44 → 0.1.46

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 (3) hide show
  1. package/README.md +38 -38
  2. package/dist/foh.js +87 -3
  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.40`
7
+ Current published baseline: `@f-o-h/cli@0.1.46`
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.
@@ -61,7 +61,7 @@ foh auth login --web --json
61
61
  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
- FOH_CLI_SPEND_POLICY=no_spend foh setup --org <org-id> --agent-template <template-id> --agent-name "Demo Agent" --phone-mode observe --json
64
+ FOH_CLI_SPEND_POLICY=no_spend foh setup --org <org-id> --agent-template <template-id> --agent-name "Demo Agent" --phone-mode observe --json
65
65
  foh prove --agent <agent-id> --json --out foh-proof.json
66
66
  foh test run --suite ./suite.yml --agent <agent-id> --json --out foh-test-report.json
67
67
  foh agent replay --file ./transcript-export.json --json
@@ -80,35 +80,35 @@ prints the fallback URL. `auth login --web` starts browser device
80
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
- `foh prove` produces a compact signed proof report across auth, org context,
84
- agent validation, contact phone readiness, voice provider health, widget
85
- channel/embed readiness, widget smoke, and simulation certification. It is
86
- read-only by default; pass `--mutation-mode ensure` or `--repair` only when you
87
- explicitly want proof to ensure missing widget state. Use `--strict` in
88
- automation when holds should fail the command, and `--mission voice` or
89
- `--require-phone` when a voice/contact number is mandatory for the demo.
90
- Use `--contact-path byon` when the proof is meant to validate a
91
- customer-owned/BYON phone route; missing BYON config then reports
92
- `byon_voice_number_not_configured` instead of suggesting FOH number purchase.
93
- For repeated or parallel proof missions in AI-agent evals, pass
94
- `--proof-cache-dir .foh/proof-cache` so simulation certification runs once and
95
- sibling proofs reuse the same signed certification detail.
96
-
97
- For mass AI-agent evals and repeated demo rehearsals, keep setup on the free
98
- scaffold lane:
99
-
100
- ```bash
101
- FOH_CLI_SPEND_POLICY=no_spend foh setup --org <org-id> --agent-template <template-id> --agent-name "Demo Agent" --phone-mode observe --json
102
- ```
103
-
104
- `--phone-mode observe` checks whether a contact phone already exists without
105
- buying one. `--phone-mode skip` bypasses the phone step. `--phone-mode purchase`
106
- is the explicit paid contact path and is fail-closed when
107
- `FOH_CLI_SPEND_POLICY=no_spend` is set.
108
-
109
- If managed-number provisioning is blocked by account/provider capacity or empty
110
- reserve inventory, proof reports `provider_capacity_blocked`; fix capacity or
111
- switch to BYON rather than retrying blindly.
83
+ `foh prove` produces a compact signed proof report across auth, org context,
84
+ agent validation, contact phone readiness, voice provider health, widget
85
+ channel/embed readiness, widget smoke, and simulation certification. It is
86
+ read-only by default; pass `--mutation-mode ensure` or `--repair` only when you
87
+ explicitly want proof to ensure missing widget state. Use `--strict` in
88
+ automation when holds should fail the command, and `--mission voice` or
89
+ `--require-phone` when a voice/contact number is mandatory for the demo.
90
+ Use `--contact-path byon` when the proof is meant to validate a
91
+ customer-owned/BYON phone route; missing BYON config then reports
92
+ `byon_voice_number_not_configured` instead of suggesting FOH number purchase.
93
+ For repeated or parallel proof missions in AI-agent evals, pass
94
+ `--proof-cache-dir .foh/proof-cache` so simulation certification runs once and
95
+ sibling proofs reuse the same signed certification detail.
96
+
97
+ For mass AI-agent evals and repeated demo rehearsals, keep setup on the free
98
+ scaffold lane:
99
+
100
+ ```bash
101
+ FOH_CLI_SPEND_POLICY=no_spend foh setup --org <org-id> --agent-template <template-id> --agent-name "Demo Agent" --phone-mode observe --json
102
+ ```
103
+
104
+ `--phone-mode observe` checks whether a contact phone already exists without
105
+ buying one. `--phone-mode skip` bypasses the phone step. `--phone-mode purchase`
106
+ is the explicit paid contact path and is fail-closed when
107
+ `FOH_CLI_SPEND_POLICY=no_spend` is set.
108
+
109
+ If managed-number provisioning is blocked by account/provider capacity or empty
110
+ reserve inventory, proof reports `provider_capacity_blocked`; fix capacity or
111
+ switch to BYON rather than retrying blindly.
112
112
 
113
113
  The CLI defaults to the production API at `https://api.frontofhouse.okii.uk`.
114
114
 
@@ -133,13 +133,13 @@ foh eval external-agent run \
133
133
  --prompt-version blank-setup.v1
134
134
  ```
135
135
 
136
- The command writes a versioned prompt, launches an instrumented shell, captures
137
- FOH CLI commands into `commands.ndjson`, and finalizes `run.json` as an
138
- `external_agent_run.v1` artifact when the shell exits.
139
-
140
- Run artifacts include `eval_state` so repeated benchmark runs make reuse
141
- explicit: org, agent, and widget reuse are expected; fresh paid phone-number
142
- creation is not expected.
136
+ The command writes a versioned prompt, launches an instrumented shell, captures
137
+ FOH CLI commands into `commands.ndjson`, and finalizes `run.json` as an
138
+ `external_agent_run.v1` artifact when the shell exits.
139
+
140
+ Run artifacts include `eval_state` so repeated benchmark runs make reuse
141
+ explicit: org, agent, and widget reuse are expected; fresh paid phone-number
142
+ creation is not expected.
143
143
 
144
144
  For guarded programmable-runner planning:
145
145
 
package/dist/foh.js CHANGED
@@ -32801,7 +32801,7 @@ var StdioServerTransport = class {
32801
32801
  };
32802
32802
 
32803
32803
  // src/lib/cli-version.ts
32804
- var CLI_VERSION = "0.1.44";
32804
+ var CLI_VERSION = "0.1.46";
32805
32805
 
32806
32806
  // src/commands/mcp-serve.ts
32807
32807
  var DEFAULT_TIMEOUT_MS = 12e4;
@@ -39181,6 +39181,7 @@ var EXTERNAL_AGENT_EVAL_AUTH_ENV_MAP = {
39181
39181
  FOH_EXTERNAL_AGENT_EVAL_API_URL: "FOH_API_URL",
39182
39182
  FOH_EXTERNAL_AGENT_EVAL_TOKEN_EXPIRES_AT: "FOH_TOKEN_EXPIRES_AT"
39183
39183
  };
39184
+ var DEFAULT_FOH_API_URL2 = "https://api.frontofhouse.okii.uk";
39184
39185
  var ExternalAgentExecutorError = class extends Error {
39185
39186
  reasonCode;
39186
39187
  constructor(reasonCode, message) {
@@ -39219,6 +39220,61 @@ function buildCodexExecutorEnv(input) {
39219
39220
  env.FOH_CLI_SUPPRESS_BANNER = "1";
39220
39221
  return env;
39221
39222
  }
39223
+ function readExternalAgentEvalAuthEnv(env = process.env) {
39224
+ return {
39225
+ token: String(env.FOH_EXTERNAL_AGENT_EVAL_TOKEN || "").trim(),
39226
+ orgId: String(env.FOH_EXTERNAL_AGENT_EVAL_ORG_ID || "").trim(),
39227
+ apiUrl: String(env.FOH_EXTERNAL_AGENT_EVAL_API_URL || env.FOH_API_URL || DEFAULT_FOH_API_URL2).trim() || DEFAULT_FOH_API_URL2,
39228
+ expiresAt: String(env.FOH_EXTERNAL_AGENT_EVAL_TOKEN_EXPIRES_AT || "").trim()
39229
+ };
39230
+ }
39231
+ function shouldRunExternalAgentEvalAuthPreflight(env = process.env) {
39232
+ return Boolean(
39233
+ env.FOH_EXTERNAL_AGENT_EVAL_TOKEN || env.FOH_EXTERNAL_AGENT_EVAL_ORG_ID || env.FOH_EXTERNAL_AGENT_EVAL_API_URL || env.FOH_EXTERNAL_AGENT_EVAL_TOKEN_EXPIRES_AT
39234
+ );
39235
+ }
39236
+ async function runExternalAgentEvalAuthPreflight(env = process.env) {
39237
+ if (!shouldRunExternalAgentEvalAuthPreflight(env)) return null;
39238
+ const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
39239
+ const auth = readExternalAgentEvalAuthEnv(env);
39240
+ const base = {
39241
+ api_url: auth.apiUrl,
39242
+ org_id: auth.orgId || null,
39243
+ checked_at: checkedAt,
39244
+ token_present: Boolean(auth.token),
39245
+ expires_at: auth.expiresAt || null,
39246
+ matched_org: null
39247
+ };
39248
+ if (!auth.token || !auth.orgId) {
39249
+ return { ...base, ok: false, reason_code: "eval_auth_missing" };
39250
+ }
39251
+ if (auth.expiresAt) {
39252
+ const expiresMs = Date.parse(auth.expiresAt);
39253
+ if (Number.isFinite(expiresMs) && expiresMs <= Date.now()) {
39254
+ return { ...base, ok: false, reason_code: "eval_auth_expired" };
39255
+ }
39256
+ }
39257
+ const res = await fetch(`${auth.apiUrl.replace(/\/$/, "")}/v1/console/auth/my-orgs`, {
39258
+ headers: {
39259
+ Authorization: `Bearer ${auth.token}`
39260
+ }
39261
+ }).catch(() => null);
39262
+ if (!res || res.status === 401) {
39263
+ return { ...base, ok: false, reason_code: "eval_auth_expired" };
39264
+ }
39265
+ if (!res.ok) {
39266
+ return { ...base, ok: false, reason_code: "eval_auth_wrong_org" };
39267
+ }
39268
+ const body = await res.json().catch(() => ({}));
39269
+ const orgs = Array.isArray(body.orgs) ? body.orgs : [];
39270
+ const matchedOrg = orgs.some((org) => String(org?.org_id || "").trim() === auth.orgId);
39271
+ return {
39272
+ ...base,
39273
+ ok: matchedOrg,
39274
+ reason_code: matchedOrg ? "eval_auth_ok" : "eval_auth_wrong_org",
39275
+ matched_org: matchedOrg
39276
+ };
39277
+ }
39222
39278
  function normalizeForCompare(path2) {
39223
39279
  const resolved = (0, import_path13.resolve)(path2);
39224
39280
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
@@ -39594,11 +39650,14 @@ function redactOutputArtifacts(run, input = {}) {
39594
39650
  }
39595
39651
  function copyCommandCaptureArtifacts(input) {
39596
39652
  const commandLog = (0, import_path13.join)(input.captureDir, "commands.ndjson");
39597
- if (!(0, import_fs15.existsSync)(commandLog)) return;
39598
- (0, import_fs15.writeFileSync)((0, import_path13.join)(input.runDir, "commands.ndjson"), (0, import_fs15.readFileSync)(commandLog, "utf8"), "utf8");
39653
+ if ((0, import_fs15.existsSync)(commandLog)) {
39654
+ (0, import_fs15.writeFileSync)((0, import_path13.join)(input.runDir, "commands.ndjson"), (0, import_fs15.readFileSync)(commandLog, "utf8"), "utf8");
39655
+ }
39599
39656
  for (const name of (0, import_fs15.readdirSync)(input.captureDir)) {
39600
39657
  if (name.startsWith("command-output-cmd_")) {
39601
39658
  (0, import_fs15.copyFileSync)((0, import_path13.join)(input.captureDir, name), (0, import_path13.join)(input.runDir, name));
39659
+ } else if (EXTERNAL_AGENT_METADATA_FILENAMES.includes(name)) {
39660
+ (0, import_fs15.copyFileSync)((0, import_path13.join)(input.captureDir, name), (0, import_path13.join)(input.runDir, name));
39602
39661
  }
39603
39662
  }
39604
39663
  }
@@ -39820,6 +39879,30 @@ async function executeExternalAgentExecutorPlan(plan, options = {}) {
39820
39879
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
39821
39880
  const results = [];
39822
39881
  const runnerCommand = options.runnerCommand || resolveCodexExecutionCommand();
39882
+ const authPreflight = await runExternalAgentEvalAuthPreflight(options.env);
39883
+ if (authPreflight && !authPreflight.ok) {
39884
+ const endedAt2 = (/* @__PURE__ */ new Date()).toISOString();
39885
+ return {
39886
+ schema_version: "external_agent_execution_batch_result.v1",
39887
+ ok: false,
39888
+ status: "hold",
39889
+ reason_code: authPreflight.reason_code,
39890
+ auth_preflight: authPreflight,
39891
+ started_at: startedAt,
39892
+ ended_at: endedAt2,
39893
+ runner: plan.runner,
39894
+ run_count: plan.runs.length,
39895
+ results: plan.runs.map((run) => ({
39896
+ run_id: run.run_id,
39897
+ status: "hold",
39898
+ failure_reason_code: authPreflight.reason_code,
39899
+ exit_code: null,
39900
+ timed_out: false,
39901
+ duration_ms: 0,
39902
+ artifacts: run.outputs
39903
+ }))
39904
+ };
39905
+ }
39823
39906
  for (const run of plan.runs) {
39824
39907
  const runStartedAt = (/* @__PURE__ */ new Date()).toISOString();
39825
39908
  const commandCaptureDir = (0, import_path13.join)(run.workspace_dir, ".foh-capture");
@@ -39887,6 +39970,7 @@ async function executeExternalAgentExecutorPlan(plan, options = {}) {
39887
39970
  ok: status === "pass",
39888
39971
  status,
39889
39972
  reason_code: status === "pass" ? "external_agent_execution_passed" : "external_agent_execution_needs_review",
39973
+ ...authPreflight ? { auth_preflight: authPreflight } : {},
39890
39974
  started_at: startedAt,
39891
39975
  ended_at: endedAt,
39892
39976
  runner: plan.runner,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@f-o-h/cli",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
4
4
  "description": "FOH CLI - AI-operator provisioning tool for Front Of House",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {