@f-o-h/cli 0.1.54 → 0.1.55

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 +79 -8
  2. package/package.json +1 -1
package/dist/foh.js CHANGED
@@ -16021,6 +16021,19 @@ function getTtsProviders(catalog) {
16021
16021
  const fromProviders = Array.isArray(catalog.providers?.tts) ? catalog.providers?.tts : [];
16022
16022
  return fromProviders.map((provider) => String(provider || "").trim().toLowerCase()).filter((provider) => provider.length > 0).sort();
16023
16023
  }
16024
+ function getSttProviders(catalog) {
16025
+ const providerRows = Array.isArray(catalog.voice_catalog?.providers) ? catalog.voice_catalog?.providers : [];
16026
+ const fromRows = providerRows.filter((provider) => provider?.kind === "stt").map((provider) => String(provider.id || "").trim().toLowerCase()).filter((provider) => provider.length > 0);
16027
+ if (fromRows.length > 0) return [...new Set(fromRows)].sort();
16028
+ const fromProviders = Array.isArray(catalog.providers?.stt) ? catalog.providers?.stt : [];
16029
+ return fromProviders.map((provider) => String(provider || "").trim().toLowerCase()).filter((provider) => provider.length > 0).sort();
16030
+ }
16031
+ function resolveDefaultSttProvider(providers) {
16032
+ for (const preferred of ["deepgram", "azure", "twilio", "none"]) {
16033
+ if (providers.includes(preferred)) return preferred;
16034
+ }
16035
+ return providers[0] || "deepgram";
16036
+ }
16024
16037
  function registerVoice(program3) {
16025
16038
  const voice = program3.command("voice").description("Manage voice provider configuration");
16026
16039
  voice.command("verify").description("Run voice verification lanes (quick/full/release) through authenticated API orchestration").option("--mode <m>", "Verification mode: quick, full, release", "release").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 () => {
@@ -16248,11 +16261,12 @@ function registerVoice(program3) {
16248
16261
  const allReady = providers.length > 0 && providers.every((provider) => provider?.ready === true);
16249
16262
  if (!allReady) markCommandFailed(1);
16250
16263
  }));
16251
- voice.command("configure").description("Configure voice settings for an agent (does not publish unless --publish)").requiredOption("--agent <id>", "Agent ID").requiredOption("--provider <p>", "TTS provider: openai, azure, twilio").requiredOption("--voice <id>", "Voice ID").option("--stt-provider <p>", "STT provider (default: openai)").option("--publish", "Validate, simulation-certify, then publish after configuring").option("--cert-mode <m>", "Simulation cert mode before publish: quick, full, stress", "full").option("--cert-adaptive-runs <n>", "Adaptive runs for full/stress certification (default: 30)", "30").option("--cert-max-improvement-rounds <n>", "Max prompt improvement rounds before publish (0-5)", "1").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 () => {
16264
+ voice.command("configure").description("Configure voice settings for an agent (does not publish unless --publish)").requiredOption("--agent <id>", "Agent ID").requiredOption("--provider <p>", "TTS provider: openai, azure, twilio").requiredOption("--voice <id>", "Voice ID").option("--stt-provider <p>", "STT provider (default: best available, preferring deepgram)").option("--publish", "Validate, simulation-certify, then publish after configuring").option("--cert-mode <m>", "Simulation cert mode before publish: quick, full, stress", "full").option("--cert-adaptive-runs <n>", "Adaptive runs for full/stress certification (default: 30)", "30").option("--cert-max-improvement-rounds <n>", "Max prompt improvement rounds before publish (0-5)", "1").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 () => {
16252
16265
  const provider = String(opts.provider || "").trim().toLowerCase();
16253
16266
  const voiceId = String(opts.voice || "").trim();
16254
16267
  const catalog = await getSpeechCatalog(opts.apiUrl);
16255
16268
  const supportedProviders = getTtsProviders(catalog);
16269
+ const supportedSttProviders = getSttProviders(catalog);
16256
16270
  if (!supportedProviders.includes(provider)) {
16257
16271
  throw new FohError({
16258
16272
  step: "voice.configure",
@@ -16271,10 +16285,19 @@ function registerVoice(program3) {
16271
16285
  statusCode: 400
16272
16286
  });
16273
16287
  }
16288
+ const sttProvider = String(opts.sttProvider || resolveDefaultSttProvider(supportedSttProviders)).trim().toLowerCase();
16289
+ if (supportedSttProviders.length > 0 && !supportedSttProviders.includes(sttProvider)) {
16290
+ throw new FohError({
16291
+ step: "voice.configure",
16292
+ error: `STT provider "${sttProvider}" is not available in speech catalog`,
16293
+ remediation: `Use --stt-provider ${resolveDefaultSttProvider(supportedSttProviders)} or run: foh voice list-providers${opts.apiUrl ? ` --api-url ${opts.apiUrl}` : ""}`,
16294
+ statusCode: 400
16295
+ });
16296
+ }
16274
16297
  const voiceConfig = {
16275
16298
  tts_provider: provider,
16276
16299
  tts_voice_id: voiceId,
16277
- stt_provider: opts.sttProvider ?? "openai"
16300
+ stt_provider: sttProvider
16278
16301
  };
16279
16302
  const draft = await apiFetch(`/v1/console/agents/${opts.agent}/draft`, {
16280
16303
  method: "PATCH",
@@ -32830,7 +32853,7 @@ var StdioServerTransport = class {
32830
32853
  };
32831
32854
 
32832
32855
  // src/lib/cli-version.ts
32833
- var CLI_VERSION = "0.1.54";
32856
+ var CLI_VERSION = "0.1.55";
32834
32857
 
32835
32858
  // src/commands/mcp-serve.ts
32836
32859
  var DEFAULT_TIMEOUT_MS = 12e4;
@@ -34479,6 +34502,28 @@ function normalizeSetupPhoneMode(raw) {
34479
34502
  reasonCode: "setup_invalid_phone_mode"
34480
34503
  });
34481
34504
  }
34505
+ function complianceSkipDetail(phoneMode) {
34506
+ return {
34507
+ reason_code: `compliance_skipped_phone_mode_${phoneMode}`,
34508
+ phone_mode: phoneMode,
34509
+ spend_policy: resolveCliSpendPolicy(),
34510
+ spend_class: "free",
34511
+ safe_to_retry: true,
34512
+ operator_note: "Compliance is only required before paid FOH-owned phone purchase."
34513
+ };
34514
+ }
34515
+ function isMissingAgentTestsError(error2) {
34516
+ if (!(error2 instanceof FohError)) return false;
34517
+ if (error2.statusCode !== 404) return false;
34518
+ const text = [
34519
+ error2.error,
34520
+ error2.reasonCode,
34521
+ error2.detail?.error,
34522
+ error2.detail?.message,
34523
+ error2.detail?.reason_code
34524
+ ].filter((value) => value !== void 0 && value !== null).join(" ").toLowerCase();
34525
+ return text.includes("no tests found") || text.includes("tests_not_found") || text.includes("agent_tests_not_configured");
34526
+ }
34482
34527
  function buildMissingOptionsPlan(missing, opts) {
34483
34528
  const missingFlags = missing.map(optionNameToFlag);
34484
34529
  const signInUrl = buildConsoleSignInUrl(resolveConsoleBaseUrl(opts.consoleUrl));
@@ -34722,6 +34767,9 @@ function registerSetup(program3) {
34722
34767
  });
34723
34768
  await step("submit_compliance", "Submit standard compliance", async () => {
34724
34769
  if (opts.skipCompliance) return { step: "submit_compliance", status: "skipped", detail: "--skip-compliance" };
34770
+ if (phoneMode !== "purchase") {
34771
+ return { step: "submit_compliance", status: "skipped", detail: complianceSkipDetail(phoneMode) };
34772
+ }
34725
34773
  const status = await apiFetch("/v1/console/org/compliance/status", {
34726
34774
  orgId: opts.org,
34727
34775
  apiUrlOverride: opts.apiUrl
@@ -34742,6 +34790,9 @@ function registerSetup(program3) {
34742
34790
  });
34743
34791
  await step("wait_compliance", "Poll until compliance approved", async () => {
34744
34792
  if (opts.skipCompliance) return { step: "wait_compliance", status: "skipped", detail: "--skip-compliance" };
34793
+ if (phoneMode !== "purchase") {
34794
+ return { step: "wait_compliance", status: "skipped", detail: complianceSkipDetail(phoneMode) };
34795
+ }
34745
34796
  await pollUntil(
34746
34797
  async () => {
34747
34798
  const status = await apiFetch("/v1/console/org/compliance/status", {
@@ -34930,7 +34981,7 @@ function registerSetup(program3) {
34930
34981
  voice: {
34931
34982
  tts_provider: opts.voiceProvider,
34932
34983
  tts_voice_id: opts.voiceId,
34933
- stt_provider: "openai"
34984
+ stt_provider: "deepgram"
34934
34985
  }
34935
34986
  }),
34936
34987
  apiUrlOverride: opts.apiUrl
@@ -34940,10 +34991,30 @@ function registerSetup(program3) {
34940
34991
  await step("run_smoke_test", "Run all agent tests", async () => {
34941
34992
  if (opts.skipTests) return { step: "run_smoke_test", status: "skipped", detail: "--skip-tests" };
34942
34993
  const resolvedAgentId = requireAgentId("run_smoke_test");
34943
- const batch = await apiFetch(`/v1/console/agents/${resolvedAgentId}/tests/run-all`, {
34944
- method: "POST",
34945
- apiUrlOverride: opts.apiUrl
34946
- });
34994
+ let batch;
34995
+ try {
34996
+ batch = await apiFetch(`/v1/console/agents/${resolvedAgentId}/tests/run-all`, {
34997
+ method: "POST",
34998
+ apiUrlOverride: opts.apiUrl
34999
+ });
35000
+ } catch (error2) {
35001
+ if (isMissingAgentTestsError(error2)) {
35002
+ return {
35003
+ step: "run_smoke_test",
35004
+ status: "skipped",
35005
+ detail: {
35006
+ reason_code: "agent_tests_not_configured",
35007
+ safe_to_retry: true,
35008
+ next_commands: [
35009
+ `foh test run --agent ${resolvedAgentId} --json`,
35010
+ `foh prove --agent ${resolvedAgentId} --mission widget --json`
35011
+ ],
35012
+ operator_note: "No saved agent tests exist yet; setup continues to simulation certification and widget proof."
35013
+ }
35014
+ };
35015
+ }
35016
+ throw error2;
35017
+ }
34947
35018
  if (!batch.batch_id) return { step: "run_smoke_test", status: "done" };
34948
35019
  const result = await pollUntil(
34949
35020
  async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@f-o-h/cli",
3
- "version": "0.1.54",
3
+ "version": "0.1.55",
4
4
  "description": "FOH CLI - AI-operator provisioning tool for Front Of House",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {