@f-o-h/cli 0.1.51 → 0.1.53
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
CHANGED
|
@@ -106,11 +106,21 @@ buying one. `--phone-mode skip` bypasses the phone step. `--phone-mode purchase`
|
|
|
106
106
|
is the explicit paid contact path and is fail-closed when
|
|
107
107
|
`FOH_CLI_SPEND_POLICY=no_spend` is set.
|
|
108
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
|
-
|
|
113
|
-
|
|
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
|
+
|
|
113
|
+
Attach a customer-owned voice number without FOH purchasing inventory:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
foh provision byon attach --phone-number <e164> --confirm-owned --org <org-id> --json
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The attach command requires explicit ownership confirmation, writes the org's
|
|
120
|
+
voice channel, returns Twilio webhook URLs, and preserves the cost boundary:
|
|
121
|
+
the customer owns the number/provider account.
|
|
122
|
+
|
|
123
|
+
The CLI defaults to the production API at `https://api.frontofhouse.okii.uk`.
|
|
114
124
|
|
|
115
125
|
## External-Agent Eval Capture
|
|
116
126
|
|
|
@@ -133,13 +143,26 @@ foh eval external-agent run \
|
|
|
133
143
|
--prompt-version blank-setup.v1
|
|
134
144
|
```
|
|
135
145
|
|
|
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
|
|
141
|
-
explicit: org, agent, and widget
|
|
142
|
-
|
|
146
|
+
The command writes a versioned prompt, launches an instrumented shell, captures
|
|
147
|
+
FOH CLI commands into `commands.ndjson`, and finalizes `run.json` as an
|
|
148
|
+
`external_agent_run.v1` artifact when the shell exits.
|
|
149
|
+
|
|
150
|
+
Run artifacts include `eval_state` so repeated benchmark runs make lifecycle
|
|
151
|
+
intent explicit: reuse the existing eval org, agent, and widget by default;
|
|
152
|
+
create ephemeral orgs only for explicit lifecycle tests; do not create paid
|
|
153
|
+
phone resources unless a BYON/customer-owned or operator-approved paid lane is
|
|
154
|
+
selected.
|
|
155
|
+
|
|
156
|
+
## Common Missions
|
|
157
|
+
|
|
158
|
+
| Mission | Command |
|
|
159
|
+
|---|---|
|
|
160
|
+
| Start | `foh start` |
|
|
161
|
+
| Setup | `foh setup --phone-mode observe --json` |
|
|
162
|
+
| Prove | `foh prove --agent <agent_id> --mission widget --json` |
|
|
163
|
+
| Debug | `foh debug --out test-results/foh-cli-diag.latest.json --json` |
|
|
164
|
+
| Improve | `foh bug improve --from-file <artifact.json> --json` |
|
|
165
|
+
| Publish | `foh agent publish --agent <agent_id> --json` |
|
|
143
166
|
|
|
144
167
|
For a planted knowledge-miss benchmark:
|
|
145
168
|
|
package/dist/foh.js
CHANGED
|
@@ -11164,6 +11164,35 @@ function registerProvision(program3) {
|
|
|
11164
11164
|
});
|
|
11165
11165
|
format(data, { json: opts.json ?? false });
|
|
11166
11166
|
}));
|
|
11167
|
+
const byon = provision.command("byon").description("Attach a customer-owned voice number without FOH number purchase");
|
|
11168
|
+
byon.command("attach").description("Attach a customer-owned Twilio/voice number to the current org").requiredOption("--phone-number <e164>", "Customer-owned E.164 phone number, for example +447700900000").option("--twilio-sid <sid>", "Optional Twilio phone number SID reference").option("--twilio-account-sid <sid>", "Optional customer Twilio account SID reference; only a suffix is stored in metadata").option("--label <label>", "Optional human label for this BYON contact path").option("--confirm-owned", "Confirm the customer controls this number and authorizes attachment").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
11169
|
+
const resolvedOrg = requiredOrg2(opts, "provision.byon.attach");
|
|
11170
|
+
if (!opts.confirmOwned) {
|
|
11171
|
+
format({
|
|
11172
|
+
ok: false,
|
|
11173
|
+
status: "blocked",
|
|
11174
|
+
reason_code: "ownership_confirmation_required",
|
|
11175
|
+
safe_to_retry: false,
|
|
11176
|
+
remediation: "Retry only after the customer confirms ownership: foh provision byon attach --phone-number <e164> --confirm-owned --org <org> --json"
|
|
11177
|
+
}, { json: opts.json ?? false });
|
|
11178
|
+
markCommandFailed(1);
|
|
11179
|
+
return;
|
|
11180
|
+
}
|
|
11181
|
+
const data = await apiFetch("/v1/console/org/twilio/byon/attach", {
|
|
11182
|
+
method: "POST",
|
|
11183
|
+
body: JSON.stringify({
|
|
11184
|
+
phone_number: opts.phoneNumber,
|
|
11185
|
+
twilio_sid: opts.twilioSid,
|
|
11186
|
+
twilio_account_sid: opts.twilioAccountSid,
|
|
11187
|
+
label: opts.label,
|
|
11188
|
+
ownership_confirmed: true
|
|
11189
|
+
}),
|
|
11190
|
+
headers: { "Idempotency-Key": `foh-cli-byon-attach:${(0, import_crypto.randomUUID)()}` },
|
|
11191
|
+
orgId: resolvedOrg,
|
|
11192
|
+
apiUrlOverride: opts.apiUrl
|
|
11193
|
+
});
|
|
11194
|
+
format(data, { json: opts.json ?? false });
|
|
11195
|
+
}));
|
|
11167
11196
|
provision.command("status").description("Show provisioning status for an org").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
11168
11197
|
const resolvedOrg = requiredOrg2(opts, "provision.status");
|
|
11169
11198
|
const data = await apiFetch(`/v1/console/org/${resolvedOrg}/onboarding`, {
|
|
@@ -32801,7 +32830,7 @@ var StdioServerTransport = class {
|
|
|
32801
32830
|
};
|
|
32802
32831
|
|
|
32803
32832
|
// src/lib/cli-version.ts
|
|
32804
|
-
var CLI_VERSION = "0.1.
|
|
32833
|
+
var CLI_VERSION = "0.1.53";
|
|
32805
32834
|
|
|
32806
32835
|
// src/commands/mcp-serve.ts
|
|
32807
32836
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -36486,7 +36515,7 @@ function toErrorRecord(error2) {
|
|
|
36486
36515
|
return { message: String(error2) };
|
|
36487
36516
|
}
|
|
36488
36517
|
function registerDiag(program3) {
|
|
36489
|
-
program3.command("diag").description("Collect support diagnostics bundle for current CLI/API context").requiredOption("--out <path>", "Write diagnostics bundle JSON to this file path").option("--org <id>", "Org ID to probe (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as machine-readable JSON").action(async (opts) => {
|
|
36518
|
+
program3.command("diag").alias("debug").description("Collect support diagnostics bundle for current CLI/API context").requiredOption("--out <path>", "Write diagnostics bundle JSON to this file path").option("--org <id>", "Org ID to probe (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as machine-readable JSON").action(async (opts) => {
|
|
36490
36519
|
try {
|
|
36491
36520
|
const checks = [];
|
|
36492
36521
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -39794,14 +39823,19 @@ function buildExecutedRunArtifact(input) {
|
|
|
39794
39823
|
commands_run: commands.map((command) => command.command),
|
|
39795
39824
|
docs_pages_used: agentMetadata.docs_pages_used,
|
|
39796
39825
|
eval_state: {
|
|
39826
|
+
lifecycle_strategy: "reuse_existing_eval_state",
|
|
39797
39827
|
org_reuse_expected: true,
|
|
39798
39828
|
agent_reuse_expected: true,
|
|
39799
39829
|
widget_reuse_expected: true,
|
|
39800
39830
|
fresh_org_expected: false,
|
|
39831
|
+
ephemeral_org_expected: false,
|
|
39801
39832
|
fresh_agent_expected: false,
|
|
39802
39833
|
phone_purchase_expected: false,
|
|
39803
39834
|
paid_resource_creation_expected: false,
|
|
39804
39835
|
spend_policy_expected: NO_SPEND_POLICY,
|
|
39836
|
+
cleanup_expected: false,
|
|
39837
|
+
cleanup_strategy: "no_cleanup_for_reused_eval_state",
|
|
39838
|
+
paid_resource_strategy: "blocked_unless_explicit_byon_or_operator_approved",
|
|
39805
39839
|
rationale: "Mass external-agent evals benchmark public docs/CLI/API clarity; reuse avoids paid phone and Twilio inventory churn."
|
|
39806
39840
|
},
|
|
39807
39841
|
artifacts: {
|
|
@@ -40108,14 +40142,19 @@ function writeSession(runDir, session) {
|
|
|
40108
40142
|
}
|
|
40109
40143
|
function buildDefaultEvalState() {
|
|
40110
40144
|
return {
|
|
40145
|
+
lifecycle_strategy: "reuse_existing_eval_state",
|
|
40111
40146
|
org_reuse_expected: true,
|
|
40112
40147
|
agent_reuse_expected: true,
|
|
40113
40148
|
widget_reuse_expected: true,
|
|
40114
40149
|
fresh_org_expected: false,
|
|
40150
|
+
ephemeral_org_expected: false,
|
|
40115
40151
|
fresh_agent_expected: false,
|
|
40116
40152
|
phone_purchase_expected: false,
|
|
40117
40153
|
paid_resource_creation_expected: false,
|
|
40118
40154
|
spend_policy_expected: "no_spend",
|
|
40155
|
+
cleanup_expected: false,
|
|
40156
|
+
cleanup_strategy: "no_cleanup_for_reused_eval_state",
|
|
40157
|
+
paid_resource_strategy: "blocked_unless_explicit_byon_or_operator_approved",
|
|
40119
40158
|
rationale: "Mass external-agent evals benchmark public docs/CLI/API clarity; reuse avoids paid phone and Twilio inventory churn."
|
|
40120
40159
|
};
|
|
40121
40160
|
}
|
|
@@ -40506,6 +40545,28 @@ function installSoftExitTrap() {
|
|
|
40506
40545
|
});
|
|
40507
40546
|
}
|
|
40508
40547
|
|
|
40548
|
+
// src/lib/mission-help.ts
|
|
40549
|
+
var CLI_MISSION_EXAMPLES = [
|
|
40550
|
+
{ mission: "Start", command: "foh start", description: "guided setup and next action selector" },
|
|
40551
|
+
{ mission: "Setup", command: "foh setup --phone-mode observe --json", description: "create or update agent, widget, voice config, and proof scaffold" },
|
|
40552
|
+
{ mission: "Prove", command: "foh prove --agent <agent_id> --mission widget --json", description: "produce a machine-readable proof report" },
|
|
40553
|
+
{ mission: "Debug", command: "foh debug --out test-results/foh-cli-diag.latest.json --json", description: "collect auth/org/API diagnostics" },
|
|
40554
|
+
{ mission: "Improve", command: "foh bug improve --from-file <artifact.json> --json", description: "convert a failure artifact into a redacted improvement packet" },
|
|
40555
|
+
{ mission: "Publish", command: "foh agent publish --agent <agent_id> --json", description: "publish after proof gates pass" }
|
|
40556
|
+
];
|
|
40557
|
+
function missionHelpText() {
|
|
40558
|
+
return [
|
|
40559
|
+
"",
|
|
40560
|
+
"Common missions:",
|
|
40561
|
+
...CLI_MISSION_EXAMPLES.map((item) => ` ${item.command.padEnd(66)} ${item.description}`),
|
|
40562
|
+
"",
|
|
40563
|
+
"For AI agents: prefer --json and follow next_commands exactly when a command blocks."
|
|
40564
|
+
].join("\n");
|
|
40565
|
+
}
|
|
40566
|
+
function addMissionHelp(program3) {
|
|
40567
|
+
program3.addHelpText("afterAll", missionHelpText());
|
|
40568
|
+
}
|
|
40569
|
+
|
|
40509
40570
|
// src/index.ts
|
|
40510
40571
|
installSoftExitTrap();
|
|
40511
40572
|
installExternalAgentCliCompletionRecorder(recordExternalAgentCliInvocation({ argv: process.argv, cliVersion: CLI_VERSION }));
|
|
@@ -40563,6 +40624,7 @@ function writeKnownError(message, remediation) {
|
|
|
40563
40624
|
`);
|
|
40564
40625
|
}
|
|
40565
40626
|
program2.name("foh").description("Front Of House CLI - AI-operator provisioning tool").version(CLI_VERSION).option("--json", "Output as machine-readable JSON").option("--api-url <url>", "Internal API base URL override (operators only)").option("--no-color", "Disable colour output");
|
|
40627
|
+
addMissionHelp(program2);
|
|
40566
40628
|
registerAuth(program2);
|
|
40567
40629
|
registerOrg(program2);
|
|
40568
40630
|
registerTenant(program2);
|
|
@@ -39,14 +39,19 @@
|
|
|
39
39
|
"https://frontofhouse.okii.uk/guides/error-handling-and-debugging"
|
|
40
40
|
],
|
|
41
41
|
"eval_state": {
|
|
42
|
+
"lifecycle_strategy": "reuse_existing_eval_state",
|
|
42
43
|
"org_reuse_expected": true,
|
|
43
44
|
"agent_reuse_expected": true,
|
|
44
45
|
"widget_reuse_expected": true,
|
|
45
46
|
"fresh_org_expected": false,
|
|
47
|
+
"ephemeral_org_expected": false,
|
|
46
48
|
"fresh_agent_expected": false,
|
|
47
49
|
"phone_purchase_expected": false,
|
|
48
50
|
"paid_resource_creation_expected": false,
|
|
49
51
|
"spend_policy_expected": "no_spend",
|
|
52
|
+
"cleanup_expected": false,
|
|
53
|
+
"cleanup_strategy": "no_cleanup_for_reused_eval_state",
|
|
54
|
+
"paid_resource_strategy": "blocked_unless_explicit_byon_or_operator_approved",
|
|
50
55
|
"rationale": "Mass external-agent evals benchmark public docs/CLI/API clarity; reuse avoids paid phone and Twilio inventory churn."
|
|
51
56
|
},
|
|
52
57
|
"artifacts": {
|
package/package.json
CHANGED
|
@@ -70,14 +70,19 @@
|
|
|
70
70
|
"eval_state": {
|
|
71
71
|
"type": "object",
|
|
72
72
|
"properties": {
|
|
73
|
+
"lifecycle_strategy": { "type": "string" },
|
|
73
74
|
"org_reuse_expected": { "type": "boolean" },
|
|
74
75
|
"agent_reuse_expected": { "type": "boolean" },
|
|
75
76
|
"widget_reuse_expected": { "type": "boolean" },
|
|
76
77
|
"fresh_org_expected": { "type": "boolean" },
|
|
78
|
+
"ephemeral_org_expected": { "type": "boolean" },
|
|
77
79
|
"fresh_agent_expected": { "type": "boolean" },
|
|
78
80
|
"phone_purchase_expected": { "type": "boolean" },
|
|
79
81
|
"paid_resource_creation_expected": { "type": "boolean" },
|
|
80
82
|
"spend_policy_expected": { "type": "string" },
|
|
83
|
+
"cleanup_expected": { "type": "boolean" },
|
|
84
|
+
"cleanup_strategy": { "type": "string" },
|
|
85
|
+
"paid_resource_strategy": { "type": "string" },
|
|
81
86
|
"rationale": { "type": "string" }
|
|
82
87
|
},
|
|
83
88
|
"additionalProperties": true
|