@fonoster/ctl 0.27.0 → 0.30.0

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 (63) hide show
  1. package/README.md +586 -88
  2. package/dist/AuthenticatedCommand.d.ts +5 -0
  3. package/dist/AuthenticatedCommand.js +12 -1
  4. package/dist/commands/applications/create.d.ts +23 -0
  5. package/dist/commands/applications/create.js +68 -169
  6. package/dist/commands/applications/eval.d.ts +1 -1
  7. package/dist/commands/applications/eval.js +46 -33
  8. package/dist/commands/applications/get.d.ts +2 -0
  9. package/dist/commands/applications/get.js +55 -24
  10. package/dist/commands/applications/list.js +19 -3
  11. package/dist/commands/applications/rotate-secret.d.ts +9 -0
  12. package/dist/commands/applications/rotate-secret.js +97 -0
  13. package/dist/commands/applications/update.d.ts +22 -1
  14. package/dist/commands/applications/update.js +17 -168
  15. package/dist/commands/providers/catalog.d.ts +10 -0
  16. package/dist/commands/providers/catalog.js +128 -0
  17. package/dist/commands/providers/keys/delete.d.ts +9 -0
  18. package/dist/commands/providers/keys/delete.js +92 -0
  19. package/dist/commands/providers/keys/list.d.ts +6 -0
  20. package/dist/commands/providers/keys/list.js +97 -0
  21. package/dist/commands/providers/keys/set.d.ts +12 -0
  22. package/dist/commands/providers/keys/set.js +110 -0
  23. package/dist/commands/records/download.d.ts +15 -0
  24. package/dist/commands/records/download.js +132 -0
  25. package/dist/commands/records/get.d.ts +15 -0
  26. package/dist/commands/records/get.js +146 -0
  27. package/dist/commands/records/list.d.ts +15 -0
  28. package/dist/commands/records/list.js +136 -0
  29. package/dist/commands/sipnet/calls/create.d.ts +3 -3
  30. package/dist/commands/sipnet/calls/create.js +35 -52
  31. package/dist/commands/webhooks/create.d.ts +10 -0
  32. package/dist/commands/webhooks/create.js +104 -0
  33. package/dist/commands/webhooks/delete.d.ts +9 -0
  34. package/dist/commands/webhooks/delete.js +92 -0
  35. package/dist/commands/webhooks/deliveries.d.ts +12 -0
  36. package/dist/commands/webhooks/deliveries.js +119 -0
  37. package/dist/commands/webhooks/get.d.ts +9 -0
  38. package/dist/commands/webhooks/get.js +110 -0
  39. package/dist/commands/webhooks/list.d.ts +9 -0
  40. package/dist/commands/webhooks/list.js +104 -0
  41. package/dist/commands/webhooks/resend.d.ts +9 -0
  42. package/dist/commands/webhooks/resend.js +95 -0
  43. package/dist/commands/webhooks/rotate.d.ts +9 -0
  44. package/dist/commands/webhooks/rotate.js +98 -0
  45. package/dist/commands/webhooks/update.d.ts +13 -0
  46. package/dist/commands/webhooks/update.js +103 -0
  47. package/dist/commands/workspaces/login.d.ts +5 -0
  48. package/dist/commands/workspaces/login.js +27 -1
  49. package/dist/utils/applicationFlags.d.ts +25 -0
  50. package/dist/utils/applicationFlags.js +95 -0
  51. package/dist/utils/applicationRequest.d.ts +43 -0
  52. package/dist/utils/applicationRequest.js +209 -0
  53. package/dist/utils/createOrUpdateApplication.d.ts +26 -1
  54. package/dist/utils/createOrUpdateApplication.js +23 -27
  55. package/dist/utils/format.d.ts +20 -0
  56. package/dist/utils/format.js +31 -0
  57. package/dist/utils/index.d.ts +1 -0
  58. package/dist/utils/index.js +1 -0
  59. package/dist/utils/trackCallStatus.d.ts +4 -0
  60. package/dist/utils/trackCallStatus.js +67 -0
  61. package/dist/utils/webhookFlags.d.ts +3 -0
  62. package/dist/utils/webhookFlags.js +34 -0
  63. package/package.json +6 -6
@@ -19,6 +19,11 @@
19
19
  import * as SDK from "@fonoster/sdk";
20
20
  import { Command } from "@oclif/core";
21
21
  import { BaseCommand } from "./BaseCommand";
22
+ /**
23
+ * The HTTP API (call records, `/api/records`) sits behind the same host and port as gRPC:
24
+ * `http://` for an insecure (local) endpoint, `https://` otherwise (CLI-B3).
25
+ */
26
+ export declare function httpUrlFor(endpoint: string, insecure?: boolean): string;
22
27
  export declare abstract class AuthenticatedCommand<T extends typeof Command> extends BaseCommand<T> {
23
28
  protected createSdkClient(): Promise<SDK.Client>;
24
29
  }
@@ -43,6 +43,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
43
43
  };
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.AuthenticatedCommand = void 0;
46
+ exports.httpUrlFor = httpUrlFor;
46
47
  /**
47
48
  * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
48
49
  * http://github.com/fonoster/fonoster
@@ -65,6 +66,15 @@ const SDK = __importStar(require("@fonoster/sdk"));
65
66
  const BaseCommand_1 = require("./BaseCommand"); // Adjust the import based on your structure
66
67
  const config_1 = require("./config");
67
68
  const constants_1 = require("./constants");
69
+ /**
70
+ * The HTTP API (call records, `/api/records`) sits behind the same host and port as gRPC:
71
+ * `http://` for an insecure (local) endpoint, `https://` otherwise (CLI-B3).
72
+ */
73
+ function httpUrlFor(endpoint, insecure = false) {
74
+ if (/^https?:\/\//.test(endpoint))
75
+ return endpoint.replace(/\/+$/, "");
76
+ return `${insecure ? "http" : "https"}://${endpoint}`.replace(/\/+$/, "");
77
+ }
68
78
  class AuthenticatedCommand extends BaseCommand_1.BaseCommand {
69
79
  createSdkClient() {
70
80
  return __awaiter(this, void 0, void 0, function* () {
@@ -77,7 +87,8 @@ class AuthenticatedCommand extends BaseCommand_1.BaseCommand {
77
87
  const client = new SDK.Client({
78
88
  endpoint: activeWorkspace.endpoint,
79
89
  accessKeyId: activeWorkspace.workspaceAccessKeyId,
80
- allowInsecure: this.flags.insecure
90
+ allowInsecure: this.flags.insecure,
91
+ httpUrl: httpUrlFor(activeWorkspace.endpoint, this.flags.insecure)
81
92
  });
82
93
  yield client.loginWithApiKey(activeWorkspace.accessKeyId, activeWorkspace.accessKeySecret);
83
94
  return client;
@@ -4,6 +4,29 @@ export default class Create extends AuthenticatedCommand<typeof Create> {
4
4
  static readonly examples: string[];
5
5
  static readonly flags: {
6
6
  "from-file": import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ name: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ url: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ protocol: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ agent: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ flavor: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ assistant: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ voice: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ language: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ "stt-model": import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
16
+ "tts-model": import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ "silence-timeout": import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
18
+ patience: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
19
+ "audio-codec": import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
20
+ "audio-rate": import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
21
+ "fallback-app": import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
22
+ "fallback-message": import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ listener: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
24
+ "clear-listeners": import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
+ recording: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
26
+ amd: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
27
+ "amd-window": import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
7
28
  };
8
29
  run(): Promise<void>;
30
+ private printCreated;
31
+ private ask;
9
32
  }
@@ -1,37 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -45,160 +12,92 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
45
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
13
  };
47
14
  Object.defineProperty(exports, "__esModule", { value: true });
48
- /**
49
- * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
50
- * http://github.com/fonoster/fonoster
51
- *
52
- * This file is part of Fonoster
53
- *
54
- * Licensed under the MIT License (the "License");
55
- * you may not use this file except in compliance with
56
- * the License. You may obtain a copy of the License at
57
- *
58
- * https://opensource.org/licenses/MIT
59
- *
60
- * Unless required by applicable law or agreed to in writing, software
61
- * distributed under the License is distributed on an "AS IS" BASIS,
62
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
63
- * See the License for the specific language governing permissions and
64
- * limitations under the License.
65
- */
66
- const common_1 = require("@fonoster/common");
67
- const SDK = __importStar(require("@fonoster/sdk"));
68
15
  const prompts_1 = require("@inquirer/prompts");
69
- const core_1 = require("@oclif/core");
70
16
  const AuthenticatedCommand_1 = require("../../AuthenticatedCommand");
71
17
  const errorHandler_1 = __importDefault(require("../../errorHandler"));
18
+ const applicationFlags_1 = require("../../utils/applicationFlags");
72
19
  const createOrUpdateApplication_1 = require("../../utils/createOrUpdateApplication");
73
20
  class Create extends AuthenticatedCommand_1.AuthenticatedCommand {
74
21
  run() {
75
22
  return __awaiter(this, void 0, void 0, function* () {
76
23
  const { flags } = yield this.parse(Create);
77
- const client = yield this.createSdkClient();
78
- if (flags["from-file"]) {
79
- try {
80
- yield (0, createOrUpdateApplication_1.createOrUpdateApplication)(client, flags["from-file"]);
81
- this.log("Done!");
82
- return;
83
- }
84
- catch (e) {
85
- (0, errorHandler_1.default)(e, this.error.bind(this));
24
+ const interactive = !flags["from-file"] && !flags.name;
25
+ try {
26
+ const answers = interactive ? yield this.ask() : {};
27
+ if (!answers) {
28
+ this.log("Aborted!");
86
29
  return;
87
30
  }
31
+ const client = yield this.createSdkClient();
32
+ const response = yield (0, createOrUpdateApplication_1.createOrUpdateApplication)(client, flags["from-file"], undefined, false, Object.assign(Object.assign({}, flags), answers));
33
+ this.printCreated(response);
88
34
  }
35
+ catch (e) {
36
+ (0, errorHandler_1.default)(e, this.error.bind(this));
37
+ }
38
+ });
39
+ }
40
+ printCreated(response) {
41
+ this.log(`Application created: ${response.ref}`);
42
+ if (response.signingSecret) {
43
+ this.log(`Signing secret: ${response.signingSecret}\n` +
44
+ "Save it now: it is shown only once (rotate it with applications:rotate-secret).");
45
+ }
46
+ }
47
+ ask() {
48
+ return __awaiter(this, void 0, void 0, function* () {
89
49
  this.log("This utility will help you create an Application.");
90
50
  this.log("Press ^C at any time to quit.");
91
- const answers = {
92
- name: yield (0, prompts_1.input)({
93
- message: "Name",
94
- required: true
95
- }),
96
- type: yield (0, prompts_1.select)({
97
- message: "Type",
98
- choices: [{ name: "External", value: "External" }]
99
- }),
100
- endpoint: yield (0, prompts_1.input)({
101
- message: "Endpoint",
102
- default: common_1.WELCOME_DEMO_SPECIAL_LOCAL_ADDRESS,
103
- required: true
104
- }),
105
- speechToText: {
106
- productRef: yield (0, prompts_1.select)({
107
- message: "SST Vendor",
108
- choices: [{ name: "Deepgram", value: "stt.deepgram" }]
109
- }),
110
- config: {
111
- languageCode: yield (0, prompts_1.select)({
112
- message: "STT Language",
113
- choices: [
114
- { name: "English", value: "en-US" },
115
- { name: "Spanish", value: "es-ES" },
116
- { name: "Multilingual (Nova 3 or Nova 2)", value: "multi" }
117
- ]
118
- }),
119
- model: yield (0, prompts_1.select)({
120
- message: "STT Model",
121
- choices: [
122
- { name: "Nova 3", value: "nova-3" },
123
- { name: "Nova 2", value: "nova-2" },
124
- { name: "Nova 2 Phone Call", value: "nova-2-phonecall" },
125
- {
126
- name: "Nova 2 Conversational AI",
127
- value: "nova-2-conversationalai"
128
- }
129
- ],
130
- default: "nova-3"
131
- })
132
- }
133
- },
134
- textToSpeech: {
135
- productRef: yield (0, prompts_1.select)({
136
- message: "TTS Vendor",
137
- choices: [
138
- { name: "Deepgram", value: "tts.deepgram" },
139
- { name: "ElevenLabs", value: "tts.elevenlabs" },
140
- { name: "Google", value: "tts.google" },
141
- { name: "Azure", value: "tts.azure" }
142
- ]
143
- }),
144
- config: {}
145
- }
146
- };
147
- const answersPartTwo = {
148
- textToSpeech: {
149
- config: {
150
- model: answers.textToSpeech.productRef === "tts.elevenlabs"
151
- ? yield (0, prompts_1.select)({
152
- message: "TTS Model",
153
- choices: [
154
- {
155
- name: "Multilingual v2",
156
- value: "eleven_multilingual_v2"
157
- },
158
- { name: "Flash v2.5", value: "eleven_flash_v2_5" },
159
- { name: "Flash v2", value: "eleven_flash_v" },
160
- { name: "Turbo v2", value: "eleven_turbo_v2" },
161
- { name: "Turbo v2.5", value: "eleven_turbo_v2_5" },
162
- {
163
- name: "Multilingual Speech to Speech",
164
- value: "eleven_multilingual_sts_v2"
165
- }
166
- ],
167
- default: "eleven_flash_v2_5"
168
- })
169
- : null,
170
- voice: yield (0, prompts_1.input)({
171
- message: "TTS Voice",
172
- required: true
173
- })
51
+ const name = yield (0, prompts_1.input)({ message: "Name", required: true });
52
+ const kind = yield (0, prompts_1.select)({
53
+ message: "Kind",
54
+ choices: [
55
+ { name: "Stream (your WebSocket server)", value: "stream" },
56
+ {
57
+ name: "Autopilot agent (hosted, with an agent file)",
58
+ value: "autopilot"
174
59
  }
175
- },
176
- confirm: yield (0, prompts_1.confirm)({
177
- message: "Ready?"
178
- })
179
- };
180
- if (!answersPartTwo.confirm) {
181
- this.log("Aborted!");
182
- return;
183
- }
184
- answers.textToSpeech.config = Object.assign(Object.assign({}, answers.textToSpeech.config), answersPartTwo.textToSpeech.config);
185
- try {
186
- const applications = new SDK.Applications(client);
187
- yield applications.createApplication(answers);
188
- this.log("Done!");
60
+ ]
61
+ });
62
+ const answers = { name };
63
+ if (kind === "autopilot") {
64
+ answers.agent = yield (0, prompts_1.input)({
65
+ message: "Agent file (YAML or JSON)",
66
+ required: true
67
+ });
189
68
  }
190
- catch (e) {
191
- (0, errorHandler_1.default)(e, this.error.bind(this));
69
+ else {
70
+ answers.url = yield (0, prompts_1.input)({
71
+ message: "URL (ws:// or wss://)",
72
+ required: true
73
+ });
74
+ answers.protocol = yield (0, prompts_1.select)({
75
+ message: "Protocol",
76
+ choices: [
77
+ { name: "Fonoster", value: "fonoster" },
78
+ { name: "Twilio-compatible (Media Streams)", value: "twilio" }
79
+ ]
80
+ });
192
81
  }
82
+ const voice = yield (0, prompts_1.input)({
83
+ message: "Voice (catalog id, empty for the default)"
84
+ });
85
+ if (voice)
86
+ answers.voice = voice;
87
+ const language = yield (0, prompts_1.input)({ message: "Language", default: "en-US" });
88
+ if (language)
89
+ answers.language = language;
90
+ return (yield (0, prompts_1.confirm)({ message: "Ready?" })) ? answers : undefined;
193
91
  });
194
92
  }
195
93
  }
196
94
  Create.description = "add a new Application to the active Workspace";
197
- Create.examples = ["<%= config.bin %> <%= command.id %>"];
198
- Create.flags = {
199
- "from-file": core_1.Flags.string({
200
- char: "f",
201
- description: "create Application from YAML or JSON file"
202
- })
203
- };
95
+ Create.examples = [
96
+ "<%= config.bin %> <%= command.id %> --name Bot --url wss://bot.example.com/session",
97
+ "<%= config.bin %> <%= command.id %> --name Bot --url wss://bot.example.com/media --protocol twilio",
98
+ "<%= config.bin %> <%= command.id %> --name Receptionist --agent agent.yaml --voice deepgram/aura-2-thalia-en",
99
+ "<%= config.bin %> <%= command.id %> --from-file app.yaml",
100
+ "<%= config.bin %> <%= command.id %> # asks for the basics"
101
+ ];
102
+ Create.flags = applicationFlags_1.applicationFlags;
204
103
  exports.default = Create;
@@ -1,6 +1,6 @@
1
1
  import { AuthenticatedCommand } from "../../AuthenticatedCommand";
2
2
  export default class EvalIntelligence extends AuthenticatedCommand<typeof EvalIntelligence> {
3
- static readonly description = "experimental command to test an Autopilot application";
3
+ static readonly description = "experimental command to test an Autopilot agent";
4
4
  static readonly examples: string[];
5
5
  static readonly flags: {
6
6
  file: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -112,10 +112,12 @@ class EvalIntelligence extends AuthenticatedCommand_1.AuthenticatedCommand {
112
112
  });
113
113
  rawAutopilotApplication.intelligence.config.testCases.scenarios =
114
114
  mappedScenarios;
115
- const parsedAutopilotApplication = common_1.assistantSchema.parse(rawAutopilotApplication.intelligence.config);
115
+ // A session assistant (its catalog id names the provider; keys come from the workspace or
116
+ // the platform, never from the file).
117
+ const parsedAutopilotApplication = common_1.sessionAssistantSchema.parse(rawAutopilotApplication.intelligence.config);
116
118
  const autopilotApplication = {
117
119
  intelligence: {
118
- productRef: rawAutopilotApplication.intelligence.productRef,
120
+ productRef: `llm.${parsedAutopilotApplication.languageModel.model.split("/")[0]}`,
119
121
  config: parsedAutopilotApplication
120
122
  }
121
123
  };
@@ -127,38 +129,49 @@ class EvalIntelligence extends AuthenticatedCommand_1.AuthenticatedCommand {
127
129
  let currentScenarioRef = null;
128
130
  const stepIndexByScenario = new Map();
129
131
  try {
130
- for (var _e = true, stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = yield stream_1.next(), _a = stream_1_1.done, !_a; _e = true) {
131
- _c = stream_1_1.value;
132
- _e = false;
133
- const event = _c;
134
- if (collectEvents)
135
- events.push(event);
136
- if (outputJson)
137
- continue;
138
- if (event.type === "stepResult") {
139
- if (currentScenarioRef !== event.scenarioRef) {
140
- currentScenarioRef = event.scenarioRef;
141
- (0, printEval_1.printScenarioHeader)(event.scenarioRef);
142
- stepIndexByScenario.set(event.scenarioRef, 0);
132
+ try {
133
+ for (var _e = true, stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = yield stream_1.next(), _a = stream_1_1.done, !_a; _e = true) {
134
+ _c = stream_1_1.value;
135
+ _e = false;
136
+ const event = _c;
137
+ if (collectEvents)
138
+ events.push(event);
139
+ if (outputJson)
140
+ continue;
141
+ if (event.type === "stepResult") {
142
+ if (currentScenarioRef !== event.scenarioRef) {
143
+ currentScenarioRef = event.scenarioRef;
144
+ (0, printEval_1.printScenarioHeader)(event.scenarioRef);
145
+ stepIndexByScenario.set(event.scenarioRef, 0);
146
+ }
147
+ const stepIndex = (_d = stepIndexByScenario.get(event.scenarioRef)) !== null && _d !== void 0 ? _d : 0;
148
+ (0, printEval_1.printStepResult)(event.scenarioRef, stepIndex, event.stepResult);
149
+ stepIndexByScenario.set(event.scenarioRef, stepIndex + 1);
150
+ }
151
+ else if (event.type === "scenarioSummary") {
152
+ (0, printEval_1.printScenarioSummary)(event.scenarioRef, event.overallPassed);
153
+ }
154
+ else if (event.type === "evalError") {
155
+ (0, printEval_1.printEvalError)(event.message);
143
156
  }
144
- const stepIndex = (_d = stepIndexByScenario.get(event.scenarioRef)) !== null && _d !== void 0 ? _d : 0;
145
- (0, printEval_1.printStepResult)(event.scenarioRef, stepIndex, event.stepResult);
146
- stepIndexByScenario.set(event.scenarioRef, stepIndex + 1);
147
- }
148
- else if (event.type === "scenarioSummary") {
149
- (0, printEval_1.printScenarioSummary)(event.scenarioRef, event.overallPassed);
150
157
  }
151
- else if (event.type === "evalError") {
152
- (0, printEval_1.printEvalError)(event.message);
158
+ }
159
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
160
+ finally {
161
+ try {
162
+ if (!_e && !_a && (_b = stream_1.return)) yield _b.call(stream_1);
153
163
  }
164
+ finally { if (e_1) throw e_1.error; }
154
165
  }
155
166
  }
156
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
157
- finally {
158
- try {
159
- if (!_e && !_a && (_b = stream_1.return)) yield _b.call(stream_1);
167
+ catch (err) {
168
+ const message = err instanceof Error ? err.message : String(err);
169
+ if (collectEvents) {
170
+ events.push({ type: "evalError", message });
171
+ }
172
+ else {
173
+ (0, printEval_1.printEvalError)(message);
160
174
  }
161
- finally { if (e_1) throw e_1.error; }
162
175
  }
163
176
  if (!collectEvents)
164
177
  return;
@@ -178,12 +191,12 @@ class EvalIntelligence extends AuthenticatedCommand_1.AuthenticatedCommand {
178
191
  });
179
192
  }
180
193
  }
181
- EvalIntelligence.description = "experimental command to test an Autopilot application";
194
+ EvalIntelligence.description = "experimental command to test an Autopilot agent";
182
195
  EvalIntelligence.examples = [
183
- "<%= config.bin %> <%= command.id %> -f assistant.json",
184
- "<%= config.bin %> <%= command.id %> -f assistant.yaml",
185
- "<%= config.bin %> <%= command.id %> -f assistant.yaml -o json",
186
- "<%= config.bin %> <%= command.id %> -f assistant.yaml -o json --output-file results.json"
196
+ "<%= config.bin %> <%= command.id %> -f agent.json",
197
+ "<%= config.bin %> <%= command.id %> -f agent.yaml",
198
+ "<%= config.bin %> <%= command.id %> -f agent.yaml -o json",
199
+ "<%= config.bin %> <%= command.id %> -f agent.yaml -o json --output-file results.json"
187
200
  ];
188
201
  EvalIntelligence.flags = {
189
202
  file: core_1.Flags.string({
@@ -1,4 +1,6 @@
1
+ import { Application } from "@fonoster/types";
1
2
  import { AuthenticatedCommand } from "../../AuthenticatedCommand";
3
+ export declare function formatApplication(app: Application): string;
2
4
  export default class Get extends AuthenticatedCommand<typeof Get> {
3
5
  static readonly description = "retrieve details of an Application by reference";
4
6
  static readonly examples: string[];
@@ -45,6 +45,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
45
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.formatApplication = formatApplication;
48
49
  /**
49
50
  * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com)
50
51
  * http://github.com/fonoster/fonoster
@@ -68,38 +69,68 @@ const core_1 = require("@oclif/core");
68
69
  const cliui_1 = __importDefault(require("cliui"));
69
70
  const moment_1 = __importDefault(require("moment"));
70
71
  const AuthenticatedCommand_1 = require("../../AuthenticatedCommand");
72
+ const errorHandler_1 = __importDefault(require("../../errorHandler"));
73
+ const or = (value, fallback = "-") => value === undefined || value === null || value === "" || value === 0
74
+ ? fallback
75
+ : String(value);
76
+ function formatApplication(app) {
77
+ var _a, _b, _c, _d, _e, _f;
78
+ const speech = (_a = app.speech) !== null && _a !== void 0 ? _a : {};
79
+ const listeners = ((_b = app.listeners) !== null && _b !== void 0 ? _b : [])
80
+ .map((l) => { var _a; return `${l.url} (${(_a = l.tracks) !== null && _a !== void 0 ? _a : "both"})`; })
81
+ .join(", ");
82
+ const assistant = (_c = app.intelligence) === null || _c === void 0 ? void 0 : _c.config;
83
+ const lines = [
84
+ "APPLICATION DETAILS",
85
+ "------------------",
86
+ `NAME: \t${app.name}`,
87
+ `REF: \t${app.ref}`,
88
+ `KIND: \t${app.type === "AUTOPILOT" ? "Autopilot agent" : "Stream"}`,
89
+ `URL: \t${or(app.url || app.endpoint)}`,
90
+ `PROTOCOL: \t${or(app.protocol, "fonoster")}`,
91
+ ...(app.type === "AUTOPILOT"
92
+ ? [`MODEL: \t${or((_d = assistant === null || assistant === void 0 ? void 0 : assistant.languageModel) === null || _d === void 0 ? void 0 : _d.model)}`]
93
+ : []),
94
+ `VOICE: \t${or(speech.voice)}`,
95
+ `LANGUAGE: \t${or(speech.language)}`,
96
+ `STT MODEL: \t${or(speech.sttModel, "default")}`,
97
+ `TTS MODEL: \t${or(speech.ttsModel, "default")}`,
98
+ `SILENCE TIMEOUT: \t${or(speech.silenceTimeoutMs, "default")}`,
99
+ `PATIENCE: \t${or(speech.patience, "normal")}`,
100
+ `AUDIO: \t${((_e = app.audio) === null || _e === void 0 ? void 0 : _e.codec) ? `${app.audio.codec} ${app.audio.rate} Hz` : "default"}`,
101
+ `RECORDING: \t${or(app.recording, "off")}`,
102
+ `AMD: \t${((_f = app.amd) === null || _f === void 0 ? void 0 : _f.enabled) ? `on (${app.amd.windowMs || 4000} ms)` : "off"}`,
103
+ `FALLBACK APP: \t${or(app.fallbackAppRef)}`,
104
+ `FALLBACK MESSAGE: \t${or(app.fallbackMessage)}`,
105
+ `LISTENERS: \t${or(listeners)}`,
106
+ `SIGNING SECRET: \t${or(app.signingSecretHint)}`,
107
+ `CREATED: \t${(0, moment_1.default)(app.createdAt).format("YYYY-MM-DD HH:mm:ss")}`,
108
+ `UPDATED: \t${(0, moment_1.default)(app.updatedAt).format("YYYY-MM-DD HH:mm:ss")}`
109
+ ];
110
+ return lines.join("\n");
111
+ }
71
112
  class Get extends AuthenticatedCommand_1.AuthenticatedCommand {
72
113
  run() {
73
114
  return __awaiter(this, void 0, void 0, function* () {
74
- var _a, _b, _c, _d;
75
115
  const { args } = yield this.parse(Get);
76
- const client = yield this.createSdkClient();
77
- const applications = new SDK.Applications(client);
78
- const response = yield applications.getApplication(args.ref);
79
- const ui = (0, cliui_1.default)({ width: 200 });
80
- // STT or none of productRef is undefined
81
- const stt = ((_a = response.speechToText) === null || _a === void 0 ? void 0 : _a.productRef)
82
- ? (_b = response.speechToText) === null || _b === void 0 ? void 0 : _b.productRef.replace("stt.", "")
83
- : "none";
84
- const tts = ((_c = response.textToSpeech) === null || _c === void 0 ? void 0 : _c.productRef)
85
- ? (_d = response.textToSpeech) === null || _d === void 0 ? void 0 : _d.productRef.replace("tts.", "")
86
- : "none";
87
- ui.div("APPLICATION DETAILS\n" +
88
- "------------------\n" +
89
- `NAME: \t${response.name}\n` +
90
- `REF: \t${response.ref}\n` +
91
- `STT: \t${stt}\n` +
92
- `TTS: \t${tts}\n` +
93
- `TYPE: \t${response.type}\n` +
94
- `ENDPOINT: \t${response.endpoint}\n` +
95
- `CREATED: \t${(0, moment_1.default)(response.createdAt).format("YYYY-MM-DD HH:mm:ss")}\n` +
96
- `UPDATED: \t${(0, moment_1.default)(response.updatedAt).format("YYYY-MM-DD HH:mm:ss")}`);
97
- this.log(ui.toString());
116
+ try {
117
+ const client = yield this.createSdkClient();
118
+ const applications = new SDK.Applications(client);
119
+ const response = yield applications.getApplication(args.ref);
120
+ const ui = (0, cliui_1.default)({ width: 200 });
121
+ ui.div(formatApplication(response));
122
+ this.log(ui.toString());
123
+ }
124
+ catch (e) {
125
+ (0, errorHandler_1.default)(e, this.error.bind(this));
126
+ }
98
127
  });
99
128
  }
100
129
  }
101
130
  Get.description = "retrieve details of an Application by reference";
102
- Get.examples = ["<%= config.bin %> <%= command.id %>"];
131
+ Get.examples = [
132
+ "<%= config.bin %> <%= command.id %> <ref>"
133
+ ];
103
134
  Get.args = {
104
135
  ref: core_1.Args.string({
105
136
  description: "The Application to show details about",
@@ -76,10 +76,26 @@ class List extends AuthenticatedCommand_1.AuthenticatedCommand {
76
76
  const response = yield applications.listApplications({
77
77
  pageSize: parseInt(flags["page-size"])
78
78
  });
79
- const ui = (0, cliui_1.default)({ width: 170 });
80
- ui.div({ text: "REF", padding: [0, 0, 0, 0], width: 40 }, { text: "NAME", padding: [0, 0, 0, 0], width: 30 }, { text: "TYPE", padding: [0, 0, 0, 0], width: 10 }, { text: "ENDPOINT", padding: [0, 0, 0, 0] });
79
+ const ui = (0, cliui_1.default)({ width: 200 });
80
+ ui.div({ text: "REF", padding: [0, 0, 0, 0], width: 40 }, { text: "NAME", padding: [0, 0, 0, 0], width: 30 }, { text: "KIND", padding: [0, 0, 0, 0], width: 11 }, { text: "PROTOCOL", padding: [0, 0, 0, 0], width: 10 }, { text: "VOICE", padding: [0, 0, 0, 0], width: 34 }, { text: "URL", padding: [0, 0, 0, 0] });
81
81
  response.items.forEach((application) => {
82
- ui.div({ text: application.ref, padding: [0, 0, 0, 0], width: 40 }, { text: application.name, padding: [0, 0, 0, 0], width: 30 }, { text: application.type, padding: [0, 0, 0, 0], width: 10 }, { text: application.endpoint, padding: [0, 0, 0, 0] });
82
+ var _a;
83
+ ui.div({ text: application.ref, padding: [0, 0, 0, 0], width: 40 }, { text: application.name, padding: [0, 0, 0, 0], width: 30 }, {
84
+ text: application.type === "AUTOPILOT" ? "Autopilot" : "Stream",
85
+ padding: [0, 0, 0, 0],
86
+ width: 11
87
+ }, {
88
+ text: application.protocol || "fonoster",
89
+ padding: [0, 0, 0, 0],
90
+ width: 8
91
+ }, {
92
+ text: ((_a = application.speech) === null || _a === void 0 ? void 0 : _a.voice) || "-",
93
+ padding: [0, 0, 0, 0],
94
+ width: 34
95
+ }, {
96
+ text: application.url || application.endpoint || "-",
97
+ padding: [0, 0, 0, 0]
98
+ });
83
99
  });
84
100
  this.log(ui.toString());
85
101
  });
@@ -0,0 +1,9 @@
1
+ import { AuthenticatedCommand } from "../../AuthenticatedCommand";
2
+ export default class RotateSecret extends AuthenticatedCommand<typeof RotateSecret> {
3
+ static readonly description = "issue a new signing secret for an Application (the old one stops working)";
4
+ static readonly examples: string[];
5
+ static readonly args: {
6
+ ref: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ run(): Promise<void>;
9
+ }