@qcobro/ctl 1.27.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 (112) hide show
  1. package/README.md +290 -0
  2. package/bin/dev.js +7 -0
  3. package/bin/run.js +9 -0
  4. package/dist/AuthenticatedCommand.d.ts +13 -0
  5. package/dist/AuthenticatedCommand.d.ts.map +1 -0
  6. package/dist/AuthenticatedCommand.js +32 -0
  7. package/dist/AuthenticatedCommand.js.map +1 -0
  8. package/dist/BaseCommand.d.ts +22 -0
  9. package/dist/BaseCommand.d.ts.map +1 -0
  10. package/dist/BaseCommand.js +33 -0
  11. package/dist/BaseCommand.js.map +1 -0
  12. package/dist/commands/agents/create.d.ts +25 -0
  13. package/dist/commands/agents/create.d.ts.map +1 -0
  14. package/dist/commands/agents/create.js +96 -0
  15. package/dist/commands/agents/create.js.map +1 -0
  16. package/dist/commands/agents/eval.d.ts +15 -0
  17. package/dist/commands/agents/eval.d.ts.map +1 -0
  18. package/dist/commands/agents/eval.js +70 -0
  19. package/dist/commands/agents/eval.js.map +1 -0
  20. package/dist/commands/agents/preview.d.ts +12 -0
  21. package/dist/commands/agents/preview.d.ts.map +1 -0
  22. package/dist/commands/agents/preview.js +35 -0
  23. package/dist/commands/agents/preview.js.map +1 -0
  24. package/dist/commands/agents/sync.d.ts +10 -0
  25. package/dist/commands/agents/sync.d.ts.map +1 -0
  26. package/dist/commands/agents/sync.js +39 -0
  27. package/dist/commands/agents/sync.js.map +1 -0
  28. package/dist/commands/mcp/configure.d.ts +20 -0
  29. package/dist/commands/mcp/configure.d.ts.map +1 -0
  30. package/dist/commands/mcp/configure.js +75 -0
  31. package/dist/commands/mcp/configure.js.map +1 -0
  32. package/dist/commands/portfolios/get.d.ts +10 -0
  33. package/dist/commands/portfolios/get.d.ts.map +1 -0
  34. package/dist/commands/portfolios/get.js +28 -0
  35. package/dist/commands/portfolios/get.js.map +1 -0
  36. package/dist/commands/portfolios/list.d.ts +10 -0
  37. package/dist/commands/portfolios/list.d.ts.map +1 -0
  38. package/dist/commands/portfolios/list.js +30 -0
  39. package/dist/commands/portfolios/list.js.map +1 -0
  40. package/dist/commands/portfolios/sync.d.ts +12 -0
  41. package/dist/commands/portfolios/sync.d.ts.map +1 -0
  42. package/dist/commands/portfolios/sync.js +41 -0
  43. package/dist/commands/portfolios/sync.js.map +1 -0
  44. package/dist/commands/workspaces/active.d.ts +7 -0
  45. package/dist/commands/workspaces/active.d.ts.map +1 -0
  46. package/dist/commands/workspaces/active.js +24 -0
  47. package/dist/commands/workspaces/active.js.map +1 -0
  48. package/dist/commands/workspaces/list.d.ts +7 -0
  49. package/dist/commands/workspaces/list.d.ts.map +1 -0
  50. package/dist/commands/workspaces/list.js +18 -0
  51. package/dist/commands/workspaces/list.js.map +1 -0
  52. package/dist/commands/workspaces/login.d.ts +8 -0
  53. package/dist/commands/workspaces/login.d.ts.map +1 -0
  54. package/dist/commands/workspaces/login.js +64 -0
  55. package/dist/commands/workspaces/login.js.map +1 -0
  56. package/dist/commands/workspaces/logout.d.ts +10 -0
  57. package/dist/commands/workspaces/logout.d.ts.map +1 -0
  58. package/dist/commands/workspaces/logout.js +23 -0
  59. package/dist/commands/workspaces/logout.js.map +1 -0
  60. package/dist/commands/workspaces/use.d.ts +10 -0
  61. package/dist/commands/workspaces/use.d.ts.map +1 -0
  62. package/dist/commands/workspaces/use.js +29 -0
  63. package/dist/commands/workspaces/use.js.map +1 -0
  64. package/dist/config/addWorkspace.d.ts +21 -0
  65. package/dist/config/addWorkspace.d.ts.map +1 -0
  66. package/dist/config/addWorkspace.js +27 -0
  67. package/dist/config/addWorkspace.js.map +1 -0
  68. package/dist/config/getActiveWorkspace.d.ts +4 -0
  69. package/dist/config/getActiveWorkspace.d.ts.map +1 -0
  70. package/dist/config/getActiveWorkspace.js +5 -0
  71. package/dist/config/getActiveWorkspace.js.map +1 -0
  72. package/dist/config/getConfig.d.ts +4 -0
  73. package/dist/config/getConfig.d.ts.map +1 -0
  74. package/dist/config/getConfig.js +10 -0
  75. package/dist/config/getConfig.js.map +1 -0
  76. package/dist/config/index.d.ts +9 -0
  77. package/dist/config/index.d.ts.map +1 -0
  78. package/dist/config/index.js +9 -0
  79. package/dist/config/index.js.map +1 -0
  80. package/dist/config/removeWorkspace.d.ts +4 -0
  81. package/dist/config/removeWorkspace.d.ts.map +1 -0
  82. package/dist/config/removeWorkspace.js +5 -0
  83. package/dist/config/removeWorkspace.js.map +1 -0
  84. package/dist/config/saveConfig.d.ts +4 -0
  85. package/dist/config/saveConfig.d.ts.map +1 -0
  86. package/dist/config/saveConfig.js +10 -0
  87. package/dist/config/saveConfig.js.map +1 -0
  88. package/dist/config/schemas.d.ts +18 -0
  89. package/dist/config/schemas.d.ts.map +1 -0
  90. package/dist/config/schemas.js +22 -0
  91. package/dist/config/schemas.js.map +1 -0
  92. package/dist/config/setActiveWorkspace.d.ts +4 -0
  93. package/dist/config/setActiveWorkspace.d.ts.map +1 -0
  94. package/dist/config/setActiveWorkspace.js +8 -0
  95. package/dist/config/setActiveWorkspace.js.map +1 -0
  96. package/dist/config/types.d.ts +4 -0
  97. package/dist/config/types.d.ts.map +1 -0
  98. package/dist/config/types.js +2 -0
  99. package/dist/config/types.js.map +1 -0
  100. package/dist/constants.d.ts +9 -0
  101. package/dist/constants.d.ts.map +1 -0
  102. package/dist/constants.js +11 -0
  103. package/dist/constants.js.map +1 -0
  104. package/dist/mcpConfigure/paths.d.ts +9 -0
  105. package/dist/mcpConfigure/paths.d.ts.map +1 -0
  106. package/dist/mcpConfigure/paths.js +20 -0
  107. package/dist/mcpConfigure/paths.js.map +1 -0
  108. package/dist/mcpConfigure/writeClaudeConfig.d.ts +33 -0
  109. package/dist/mcpConfigure/writeClaudeConfig.d.ts.map +1 -0
  110. package/dist/mcpConfigure/writeClaudeConfig.js +44 -0
  111. package/dist/mcpConfigure/writeClaudeConfig.js.map +1 -0
  112. package/package.json +58 -0
package/README.md ADDED
@@ -0,0 +1,290 @@
1
+ # ctl
2
+
3
+ Command-Line for QCobro
4
+
5
+ [![Version](https://img.shields.io/npm/v/@qcobro/ctl.svg)](https://npmjs.org/package/@qcobro/ctl)
6
+ [![License](https://img.shields.io/npm/l/@qcobro/ctl.svg)](https://github.com/fonoster/qcobro/blob/main/package.json)
7
+
8
+ Use this tool to manage your QCobro resources from the command line, without going through
9
+ the operator console: sync a portfolio, create an agent template, or configure an MCP client
10
+ like Claude Desktop to use [`@qcobro/mcp`](../mcp).
11
+
12
+ It's built on [`@qcobro/sdk`](../sdk), so every command talks to the same QCobro API the SDK
13
+ and the console use, with the same client-side input validation.
14
+
15
+ ## Setup
16
+
17
+ Link a workspace before running any authenticated command. You'll need a workspace API key
18
+ (an `accessKeyId` + `accessKeySecret`) — create one from the QCobro console's API Keys page —
19
+ and the `accessKeyId` of the workspace that key acts in.
20
+
21
+ ```sh-session
22
+ $ qcobro workspaces:login
23
+ ```
24
+
25
+ <!-- toc -->
26
+
27
+ - [Usage](#usage)
28
+ - [Commands](#commands)
29
+ <!-- tocstop -->
30
+
31
+ # Usage
32
+
33
+ <!-- usage -->
34
+
35
+ ```sh-session
36
+ $ npm install -g @qcobro/ctl
37
+ $ qcobro COMMAND
38
+ running command...
39
+ $ qcobro (--version)
40
+ @qcobro/ctl/1.24.1 darwin-arm64 node-v22.17.0
41
+ $ qcobro --help [COMMAND]
42
+ USAGE
43
+ $ qcobro COMMAND
44
+ ...
45
+ ```
46
+
47
+ <!-- usagestop -->
48
+
49
+ # Commands
50
+
51
+ <!-- commands -->
52
+
53
+ - [`qcobro agents:create`](#qcobro-agentscreate)
54
+ - [`qcobro agents:eval TEMPLATEID`](#qcobro-agentseval-templateid)
55
+ - [`qcobro mcp:configure`](#qcobro-mcpconfigure)
56
+ - [`qcobro portfolios:get ID`](#qcobro-portfoliosget-id)
57
+ - [`qcobro portfolios:list`](#qcobro-portfolioslist)
58
+ - [`qcobro portfolios:sync`](#qcobro-portfoliossync)
59
+ - [`qcobro workspaces:active`](#qcobro-workspacesactive)
60
+ - [`qcobro workspaces:list`](#qcobro-workspaceslist)
61
+ - [`qcobro workspaces:login`](#qcobro-workspaceslogin)
62
+ - [`qcobro workspaces:logout WORKSPACEACCESSKEYID`](#qcobro-workspaceslogout-workspaceaccesskeyid)
63
+ - [`qcobro workspaces:use WORKSPACEACCESSKEYID`](#qcobro-workspacesuse-workspaceaccesskeyid)
64
+
65
+ ## `qcobro agents:create`
66
+
67
+ create an agent template in the active workspace
68
+
69
+ ```
70
+ USAGE
71
+ $ qcobro agents:create --type VOICE_AI|VOICE_PRERECORDED|SMS|EMAIL|WHATSAPP --name <value> [--voice <value>]
72
+ [--language <value>] [--system-prompt <value>] [--first-message <value>] [--script <value>] [--fonoster-app-name
73
+ <value>] [--message-body <value>] [--sender-id <value>] [--subject <value>] [--max-replies <value>] [--template-name
74
+ <value>]
75
+
76
+ FLAGS
77
+ --first-message=<value> opening line (VOICE_AI, optional)
78
+ --fonoster-app-name=<value> Fonoster application name (voice types)
79
+ --language=<value> language code (voice channel types)
80
+ --max-replies=<value> reply cap per gestión (EMAIL, WHATSAPP)
81
+ --message-body=<value> message text (SMS, EMAIL)
82
+ --name=<value> (required) template name
83
+ --script=<value> full TTS script (VOICE_PRERECORDED)
84
+ --sender-id=<value> sender identifier (SMS, optional)
85
+ --subject=<value> email subject (EMAIL)
86
+ --system-prompt=<value> AI persona/instructions (VOICE_AI, EMAIL, WHATSAPP)
87
+ --template-name=<value> Meta template name (WHATSAPP)
88
+ --type=<option> (required) agent channel type
89
+ <options: VOICE_AI|VOICE_PRERECORDED|SMS|EMAIL|WHATSAPP>
90
+ --voice=<value> voice identifier (voice channel types)
91
+
92
+ DESCRIPTION
93
+ create an agent template in the active workspace
94
+
95
+ EXAMPLES
96
+ $ qcobro agents:create --type VOICE_AI --name "Cobranza suave" --voice sofia --system-prompt "Sé amable y directo." --language es
97
+
98
+ $ qcobro agents:create --type SMS --name "Recordatorio" --message-body "Hola {{firstName}}, tienes un saldo pendiente."
99
+ ```
100
+
101
+ ## `qcobro agents:eval TEMPLATEID`
102
+
103
+ re-attempt an agent template's Fonoster sync and report the resulting status. This validates the template's configuration and its sync with Fonoster — QCobro has no conversational-intelligence evaluation feature today, so this does not test conversation behavior. Only VOICE_AI templates sync with Fonoster; other channel types are a no-op that leaves the template unchanged.
104
+
105
+ ```
106
+ USAGE
107
+ $ qcobro agents:eval TEMPLATEID
108
+
109
+ ARGUMENTS
110
+ TEMPLATEID the agent template id
111
+
112
+ DESCRIPTION
113
+ re-attempt an agent template's Fonoster sync and report the resulting status. This validates the template's
114
+ configuration and its sync with Fonoster — QCobro has no conversational-intelligence evaluation feature today, so this
115
+ does not test conversation behavior. Only VOICE_AI templates sync with Fonoster; other channel types are a no-op that
116
+ leaves the template unchanged.
117
+
118
+ EXAMPLES
119
+ $ qcobro agents:eval <templateId>
120
+ ```
121
+
122
+ ## `qcobro mcp:configure`
123
+
124
+ configure an MCP client to use @qcobro/mcp
125
+
126
+ ```
127
+ USAGE
128
+ $ qcobro mcp:configure [-c claude] [--url <value>] [--access-key-id <value>] [--access-key-secret <value>]
129
+ [--workspace <value>]
130
+
131
+ FLAGS
132
+ -c, --client=<option> [default: claude] MCP client to configure
133
+ <options: claude>
134
+ --access-key-id=<value> workspace API key id (overrides active workspace)
135
+ --access-key-secret=<value> workspace API key secret (overrides active workspace)
136
+ --url=<value> [default: https://api.qcobro.com] QCobro API base URL
137
+ --workspace=<value> workspace to act in, its accessKeyId (overrides active workspace)
138
+
139
+ DESCRIPTION
140
+ configure an MCP client to use @qcobro/mcp
141
+
142
+ EXAMPLES
143
+ $ qcobro mcp:configure
144
+
145
+ $ qcobro mcp:configure --client claude
146
+
147
+ $ qcobro mcp:configure --access-key-id <id> --access-key-secret <secret> --workspace <workspaceAccessKeyId>
148
+ ```
149
+
150
+ ## `qcobro portfolios:get ID`
151
+
152
+ display a single portfolio
153
+
154
+ ```
155
+ USAGE
156
+ $ qcobro portfolios:get ID
157
+
158
+ ARGUMENTS
159
+ ID the portfolio id
160
+
161
+ DESCRIPTION
162
+ display a single portfolio
163
+
164
+ EXAMPLES
165
+ $ qcobro portfolios:get <id>
166
+ ```
167
+
168
+ ## `qcobro portfolios:list`
169
+
170
+ display the active workspace's portfolios
171
+
172
+ ```
173
+ USAGE
174
+ $ qcobro portfolios:list [--include-archived]
175
+
176
+ FLAGS
177
+ --include-archived include archived portfolios
178
+
179
+ DESCRIPTION
180
+ display the active workspace's portfolios
181
+
182
+ EXAMPLES
183
+ $ qcobro portfolios:list
184
+
185
+ $ qcobro portfolios:list --include-archived
186
+ ```
187
+
188
+ ## `qcobro portfolios:sync`
189
+
190
+ synchronize a batch of account rows into a portfolio, from a JSON file
191
+
192
+ ```
193
+ USAGE
194
+ $ qcobro portfolios:sync --portfolio-id <value> --file <value> [--mode APPEND_ONLY|UPDATE_EXISTING|REPLACE]
195
+
196
+ FLAGS
197
+ --file=<value> (required) path to a JSON file containing an array of account rows
198
+ --mode=<option> [default: APPEND_ONLY] merge strategy
199
+ <options: APPEND_ONLY|UPDATE_EXISTING|REPLACE>
200
+ --portfolio-id=<value> (required) the portfolio id
201
+
202
+ DESCRIPTION
203
+ synchronize a batch of account rows into a portfolio, from a JSON file
204
+
205
+ EXAMPLES
206
+ $ qcobro portfolios:sync --portfolio-id <id> --file rows.json --mode APPEND_ONLY
207
+ ```
208
+
209
+ ## `qcobro workspaces:active`
210
+
211
+ display the active QCobro workspace
212
+
213
+ ```
214
+ USAGE
215
+ $ qcobro workspaces:active
216
+
217
+ DESCRIPTION
218
+ display the active QCobro workspace
219
+
220
+ EXAMPLES
221
+ $ qcobro workspaces:active
222
+ ```
223
+
224
+ ## `qcobro workspaces:list`
225
+
226
+ display all linked QCobro workspaces
227
+
228
+ ```
229
+ USAGE
230
+ $ qcobro workspaces:list
231
+
232
+ DESCRIPTION
233
+ display all linked QCobro workspaces
234
+
235
+ EXAMPLES
236
+ $ qcobro workspaces:list
237
+ ```
238
+
239
+ ## `qcobro workspaces:login`
240
+
241
+ link a QCobro workspace to the local environment
242
+
243
+ ```
244
+ USAGE
245
+ $ qcobro workspaces:login
246
+
247
+ DESCRIPTION
248
+ link a QCobro workspace to the local environment
249
+
250
+ EXAMPLES
251
+ $ qcobro workspaces:login
252
+ ```
253
+
254
+ ## `qcobro workspaces:logout WORKSPACEACCESSKEYID`
255
+
256
+ unlink a QCobro workspace from the local environment
257
+
258
+ ```
259
+ USAGE
260
+ $ qcobro workspaces:logout WORKSPACEACCESSKEYID
261
+
262
+ ARGUMENTS
263
+ WORKSPACEACCESSKEYID the workspace to unlink (its accessKeyId)
264
+
265
+ DESCRIPTION
266
+ unlink a QCobro workspace from the local environment
267
+
268
+ EXAMPLES
269
+ $ qcobro workspaces:logout WO6ueex0qan9ojhf820wgiae3qi5luy08y
270
+ ```
271
+
272
+ ## `qcobro workspaces:use WORKSPACEACCESSKEYID`
273
+
274
+ set a linked workspace as the active one
275
+
276
+ ```
277
+ USAGE
278
+ $ qcobro workspaces:use WORKSPACEACCESSKEYID
279
+
280
+ ARGUMENTS
281
+ WORKSPACEACCESSKEYID the workspace to activate (its accessKeyId)
282
+
283
+ DESCRIPTION
284
+ set a linked workspace as the active one
285
+
286
+ EXAMPLES
287
+ $ qcobro workspaces:use WO6ueex0qan9ojhf820wgiae3qi5luy08y
288
+ ```
289
+
290
+ <!-- commandsstop -->
package/bin/dev.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env -S node --import tsx
2
+
3
+ process.removeAllListeners("warning");
4
+ process.on("warning", () => {});
5
+
6
+ const { execute } = await import("@oclif/core");
7
+ await execute({ development: true, dir: import.meta.url });
package/bin/run.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ // The following code suppresses the warning about the punycode deprecated module.
4
+ // This is a temporary workaround until this get's fixed upstream.
5
+ process.removeAllListeners("warning");
6
+ process.on("warning", () => {});
7
+
8
+ const { execute } = await import("@oclif/core");
9
+ await execute({ dir: import.meta.url });
@@ -0,0 +1,13 @@
1
+ import { Command } from "@oclif/core";
2
+ import { Client } from "@qcobro/sdk";
3
+ import { BaseCommand } from "./BaseCommand.js";
4
+ /**
5
+ * Base class for commands that need an authenticated `@qcobro/sdk` `Client`.
6
+ * Constructs the client from the active workspace's stored credentials, the
7
+ * same way `@qcobro/mcp`'s `createClient` util does (`loginWithApiKey` then
8
+ * `useWorkspace`) — see `mods/mcp/src/utils/createClient.ts`.
9
+ */
10
+ export declare abstract class AuthenticatedCommand<T extends typeof Command> extends BaseCommand<T> {
11
+ protected createSdkClient(): Promise<Client>;
12
+ }
13
+ //# sourceMappingURL=AuthenticatedCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthenticatedCommand.d.ts","sourceRoot":"","sources":["../src/AuthenticatedCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAI/C;;;;;GAKG;AACH,8BAAsB,oBAAoB,CAAC,CAAC,SAAS,OAAO,OAAO,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAC;cACzE,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;CAyBnD"}
@@ -0,0 +1,32 @@
1
+ import { Client } from "@qcobro/sdk";
2
+ import { BaseCommand } from "./BaseCommand.js";
3
+ import { getActiveWorkspace, getConfig } from "./config/index.js";
4
+ import { CONFIG_FILE } from "./constants.js";
5
+ /**
6
+ * Base class for commands that need an authenticated `@qcobro/sdk` `Client`.
7
+ * Constructs the client from the active workspace's stored credentials, the
8
+ * same way `@qcobro/mcp`'s `createClient` util does (`loginWithApiKey` then
9
+ * `useWorkspace`) — see `mods/mcp/src/utils/createClient.ts`.
10
+ */
11
+ export class AuthenticatedCommand extends BaseCommand {
12
+ async createSdkClient() {
13
+ const workspaces = getConfig(CONFIG_FILE);
14
+ const activeWorkspace = getActiveWorkspace(workspaces);
15
+ if (!activeWorkspace) {
16
+ this.error("No active workspace found. Run `qcobro workspaces:login` first.", { exit: 1 });
17
+ }
18
+ try {
19
+ const client = new Client({ endpoint: activeWorkspace.endpoint });
20
+ await client.loginWithApiKey({
21
+ accessKeyId: activeWorkspace.accessKeyId,
22
+ accessKeySecret: activeWorkspace.accessKeySecret
23
+ });
24
+ client.useWorkspace(activeWorkspace.workspaceAccessKeyId);
25
+ return client;
26
+ }
27
+ catch {
28
+ return this.error("Failed to initialize the SDK client. Try `qcobro workspaces:login` again.", { exit: 1 });
29
+ }
30
+ }
31
+ }
32
+ //# sourceMappingURL=AuthenticatedCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthenticatedCommand.js","sourceRoot":"","sources":["../src/AuthenticatedCommand.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,OAAgB,oBAA+C,SAAQ,WAAc;IAC/E,KAAK,CAAC,eAAe;QAC7B,MAAM,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QAC1C,MAAM,eAAe,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAEvD,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,iEAAiE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7F,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,QAAQ,EAAE,eAAe,CAAC,QAAQ,EAAE,CAAC,CAAC;YAElE,MAAM,MAAM,CAAC,eAAe,CAAC;gBAC3B,WAAW,EAAE,eAAe,CAAC,WAAW;gBACxC,eAAe,EAAE,eAAe,CAAC,eAAe;aACjD,CAAC,CAAC;YACH,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,oBAAoB,CAAC,CAAC;YAE1D,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,KAAK,CACf,2EAA2E,EAC3E,EAAE,IAAI,EAAE,CAAC,EAAE,CACZ,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ import { Command, Interfaces } from "@oclif/core";
2
+ export type Args<T extends typeof Command> = Interfaces.InferredArgs<T["args"]>;
3
+ /**
4
+ * Base class every `@qcobro/ctl` command extends. Provides shared flag
5
+ * parsing (`baseFlags`, inherited by every command via `Flags<T>`) and a
6
+ * single place to hook error handling, mirroring `@fonoster/ctl`'s
7
+ * `BaseCommand`. QCobro's SDK talks tRPC over HTTPS with no insecure-channel
8
+ * concept, so — unlike Fonoster's version — no `--insecure` flag is defined
9
+ * here.
10
+ */
11
+ export declare abstract class BaseCommand<T extends typeof Command> extends Command {
12
+ static readonly baseFlags: {};
13
+ protected flags: Flags<T>;
14
+ protected args: Args<T>;
15
+ init(): Promise<void>;
16
+ protected catch(err: Error & {
17
+ exitCode?: number;
18
+ }): Promise<unknown>;
19
+ protected finally(err: Error | undefined): Promise<unknown>;
20
+ }
21
+ export type Flags<T extends typeof Command> = Interfaces.InferredFlags<(typeof BaseCommand)["baseFlags"] & T["flags"]>;
22
+ //# sourceMappingURL=BaseCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseCommand.d.ts","sourceRoot":"","sources":["../src/BaseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEhF;;;;;;;GAOG;AACH,8BAAsB,WAAW,CAAC,CAAC,SAAS,OAAO,OAAO,CAAE,SAAQ,OAAO;IACzE,MAAM,CAAC,QAAQ,CAAC,SAAS,KAAM;IAE/B,SAAS,CAAC,KAAK,EAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,SAAS,CAAC,IAAI,EAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAEZ,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;cAalB,KAAK,CAAC,GAAG,EAAE,KAAK,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;cAI3D,OAAO,CAAC,GAAG,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;CAGlE;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC,aAAa,CACpE,CAAC,OAAO,WAAW,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAC/C,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { Command } from "@oclif/core";
2
+ /**
3
+ * Base class every `@qcobro/ctl` command extends. Provides shared flag
4
+ * parsing (`baseFlags`, inherited by every command via `Flags<T>`) and a
5
+ * single place to hook error handling, mirroring `@fonoster/ctl`'s
6
+ * `BaseCommand`. QCobro's SDK talks tRPC over HTTPS with no insecure-channel
7
+ * concept, so — unlike Fonoster's version — no `--insecure` flag is defined
8
+ * here.
9
+ */
10
+ export class BaseCommand extends Command {
11
+ static baseFlags = {};
12
+ flags;
13
+ args;
14
+ async init() {
15
+ await super.init();
16
+ const { args, flags } = await this.parse({
17
+ flags: this.ctor.flags,
18
+ baseFlags: super.ctor.baseFlags,
19
+ enableJsonFlag: this.ctor.enableJsonFlag,
20
+ args: this.ctor.args,
21
+ strict: this.ctor.strict
22
+ });
23
+ this.flags = flags;
24
+ this.args = args;
25
+ }
26
+ async catch(err) {
27
+ return super.catch(err);
28
+ }
29
+ async finally(err) {
30
+ return super.finally(err);
31
+ }
32
+ }
33
+ //# sourceMappingURL=BaseCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseCommand.js","sourceRoot":"","sources":["../src/BaseCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAc,MAAM,aAAa,CAAC;AAIlD;;;;;;;GAOG;AACH,MAAM,OAAgB,WAAsC,SAAQ,OAAO;IACzE,MAAM,CAAU,SAAS,GAAG,EAAE,CAAC;IAErB,KAAK,CAAY;IACjB,IAAI,CAAW;IAElB,KAAK,CAAC,IAAI;QACf,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;YACvC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK;YACtB,SAAS,EAAG,KAAK,CAAC,IAA2B,CAAC,SAAS;YACvD,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc;YACxC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;YACpB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;SACzB,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,GAAG,KAAiB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAe,CAAC;IAC9B,CAAC;IAES,KAAK,CAAC,KAAK,CAAC,GAAkC;QACtD,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAES,KAAK,CAAC,OAAO,CAAC,GAAsB;QAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { Interfaces } from "@oclif/core";
2
+ import { AuthenticatedCommand } from "../../AuthenticatedCommand.js";
3
+ export default class Create extends AuthenticatedCommand<typeof Create> {
4
+ static readonly description = "create an agent template in the active workspace";
5
+ static readonly examples: string[];
6
+ static readonly flags: {
7
+ type: Interfaces.OptionFlag<string, Interfaces.CustomOptions>;
8
+ name: Interfaces.OptionFlag<string, Interfaces.CustomOptions>;
9
+ voice: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
10
+ language: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
11
+ "system-prompt": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
12
+ "first-message": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
13
+ script: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
14
+ "fonoster-app-name": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
15
+ "message-body": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
16
+ "sender-id": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
17
+ subject: Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
18
+ "max-replies": Interfaces.OptionFlag<number | undefined, Interfaces.CustomOptions>;
19
+ "template-name": Interfaces.OptionFlag<string | undefined, Interfaces.CustomOptions>;
20
+ };
21
+ run(): Promise<void>;
22
+ private buildPayload;
23
+ private required;
24
+ }
25
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/agents/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,oBAAoB,CAAC,OAAO,MAAM,CAAC;IACrE,gBAAyB,WAAW,sDAAsD;IAC1F,gBAAyB,QAAQ,WAG/B;IACF,gBAAyB,KAAK;;;;;;;;;;;;;;MAsB5B;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC,OAAO,CAAC,YAAY;IAuDpB,OAAO,CAAC,QAAQ;CAIjB"}
@@ -0,0 +1,96 @@
1
+ import { Flags } from "@oclif/core";
2
+ import { AuthenticatedCommand } from "../../AuthenticatedCommand.js";
3
+ export default class Create extends AuthenticatedCommand {
4
+ static description = "create an agent template in the active workspace";
5
+ static examples = [
6
+ '<%= config.bin %> <%= command.id %> --type VOICE_AI --name "Cobranza suave" --voice sofia --system-prompt "Sé amable y directo." --language es',
7
+ '<%= config.bin %> <%= command.id %> --type SMS --name "Recordatorio" --message-body "Hola {{firstName}}, tienes un saldo pendiente."'
8
+ ];
9
+ static flags = {
10
+ type: Flags.string({
11
+ description: "agent channel type",
12
+ options: ["VOICE_AI", "VOICE_PRERECORDED", "SMS", "EMAIL", "WHATSAPP"],
13
+ required: true
14
+ }),
15
+ name: Flags.string({ description: "template name", required: true }),
16
+ // Voice (VOICE_AI, VOICE_PRERECORDED)
17
+ voice: Flags.string({ description: "voice identifier (voice channel types)" }),
18
+ language: Flags.string({ description: "language code (voice channel types)" }),
19
+ "system-prompt": Flags.string({
20
+ description: "AI persona/instructions (VOICE_AI, EMAIL, WHATSAPP)"
21
+ }),
22
+ "first-message": Flags.string({ description: "opening line (VOICE_AI, optional)" }),
23
+ script: Flags.string({ description: "full TTS script (VOICE_PRERECORDED)" }),
24
+ "fonoster-app-name": Flags.string({ description: "Fonoster application name (voice types)" }),
25
+ // Text (SMS, EMAIL, WHATSAPP)
26
+ "message-body": Flags.string({ description: "message text (SMS, EMAIL)" }),
27
+ "sender-id": Flags.string({ description: "sender identifier (SMS, optional)" }),
28
+ subject: Flags.string({ description: "email subject (EMAIL)" }),
29
+ "max-replies": Flags.integer({ description: "reply cap per gestión (EMAIL, WHATSAPP)" }),
30
+ "template-name": Flags.string({ description: "Meta template name (WHATSAPP)" })
31
+ };
32
+ async run() {
33
+ const { flags } = await this.parse(Create);
34
+ const client = await this.createSdkClient();
35
+ const payload = this.buildPayload(flags);
36
+ const created = await client.agentTemplates.create(payload);
37
+ this.log(`Created agent template ${created.id} (${created.type}) "${created.name}".`);
38
+ }
39
+ buildPayload(flags) {
40
+ const base = { name: flags.name };
41
+ switch (flags.type) {
42
+ case "VOICE_AI":
43
+ return {
44
+ ...base,
45
+ type: "VOICE_AI",
46
+ voice: this.required(flags.voice, "--voice"),
47
+ systemPrompt: this.required(flags["system-prompt"], "--system-prompt"),
48
+ firstMessage: flags["first-message"],
49
+ language: this.required(flags.language, "--language"),
50
+ fonosterAppName: flags["fonoster-app-name"]
51
+ };
52
+ case "VOICE_PRERECORDED":
53
+ return {
54
+ ...base,
55
+ type: "VOICE_PRERECORDED",
56
+ voice: this.required(flags.voice, "--voice"),
57
+ script: this.required(flags.script, "--script"),
58
+ language: this.required(flags.language, "--language"),
59
+ fonosterAppName: flags["fonoster-app-name"]
60
+ };
61
+ case "SMS":
62
+ return {
63
+ ...base,
64
+ type: "SMS",
65
+ messageBody: this.required(flags["message-body"], "--message-body"),
66
+ senderId: flags["sender-id"]
67
+ };
68
+ case "EMAIL":
69
+ return {
70
+ ...base,
71
+ type: "EMAIL",
72
+ subject: this.required(flags.subject, "--subject"),
73
+ messageBody: this.required(flags["message-body"], "--message-body"),
74
+ systemPrompt: this.required(flags["system-prompt"], "--system-prompt"),
75
+ maxReplies: flags["max-replies"]
76
+ };
77
+ case "WHATSAPP":
78
+ return {
79
+ ...base,
80
+ type: "WHATSAPP",
81
+ templateName: this.required(flags["template-name"], "--template-name"),
82
+ messageBody: this.required(flags["message-body"], "--message-body"),
83
+ systemPrompt: this.required(flags["system-prompt"], "--system-prompt"),
84
+ maxReplies: flags["max-replies"]
85
+ };
86
+ default:
87
+ return this.error(`Unknown agent type: ${flags.type}`, { exit: 1 });
88
+ }
89
+ }
90
+ required(value, flagName) {
91
+ if (!value)
92
+ this.error(`Missing required flag ${flagName} for this agent type.`, { exit: 1 });
93
+ return value;
94
+ }
95
+ }
96
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/agents/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { AuthenticatedCommand } from "../../AuthenticatedCommand.js";
2
+ export default class Eval extends AuthenticatedCommand<typeof Eval> {
3
+ static readonly description: string;
4
+ static readonly examples: string[];
5
+ static readonly flags: {
6
+ "template-id": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ scenarios: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ private buildInput;
12
+ /** Prints one evaluation event; returns true if it signals a failure. */
13
+ private printEvent;
14
+ }
15
+ //# sourceMappingURL=eval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../../src/commands/agents/eval.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,oBAAoB,CAAC,OAAO,IAAI,CAAC;IACjE,gBAAyB,WAAW,SAKqD;IACzF,gBAAyB,QAAQ,WAG/B;IACF,gBAAyB,KAAK;;;;MAQ5B;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC,OAAO,CAAC,UAAU;IAqBlB,yEAAyE;IACzE,OAAO,CAAC,UAAU;CAkBnB"}
@@ -0,0 +1,70 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { Flags } from "@oclif/core";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { AuthenticatedCommand } from "../../AuthenticatedCommand.js";
5
+ export default class Eval extends AuthenticatedCommand {
6
+ static description = "evaluate a VOICE_AI/EMAIL/WHATSAPP agent's conversation logic — either an existing " +
7
+ "template plus a scenarios file, or a standalone YAML eval template (agent definition " +
8
+ "plus its own embedded scenarios) that is never created. Streams each turn's result as " +
9
+ "it happens, then a final pass/fail summary; exits non-zero when the run fails. For a " +
10
+ "static SMS/VOICE_PRERECORDED render (no conversation), use `agents:preview` instead.";
11
+ static examples = [
12
+ "<%= config.bin %> <%= command.id %> --template-id <id> --scenarios scenarios.yaml",
13
+ "<%= config.bin %> <%= command.id %> --file eval-template.yaml"
14
+ ];
15
+ static flags = {
16
+ "template-id": Flags.string({ description: "an existing agent template id" }),
17
+ scenarios: Flags.string({
18
+ description: "path to a YAML file with the scenarios to run (used with --template-id)"
19
+ }),
20
+ file: Flags.string({
21
+ description: "path to a standalone YAML eval template (agent definition + embedded scenarios)"
22
+ })
23
+ };
24
+ async run() {
25
+ const { flags } = await this.parse(Eval);
26
+ const client = await this.createSdkClient();
27
+ let anyFailed = false;
28
+ for await (const event of client.agentEvaluations.evaluate(this.buildInput(flags))) {
29
+ anyFailed = this.printEvent(event) || anyFailed;
30
+ }
31
+ if (anyFailed)
32
+ this.exit(1);
33
+ }
34
+ buildInput(flags) {
35
+ if (flags.file) {
36
+ return { yaml: readFileSync(flags.file, "utf8") };
37
+ }
38
+ if (flags["template-id"] && flags.scenarios) {
39
+ const parsed = parseYaml(readFileSync(flags.scenarios, "utf8"));
40
+ const scenarios = Array.isArray(parsed)
41
+ ? parsed
42
+ : (parsed.scenarios ?? parsed);
43
+ return {
44
+ agentTemplateId: flags["template-id"],
45
+ scenarios: scenarios
46
+ };
47
+ }
48
+ return this.error("Provide --file, or both --template-id and --scenarios.", { exit: 1 });
49
+ }
50
+ /** Prints one evaluation event; returns true if it signals a failure. */
51
+ printEvent(event) {
52
+ if (event.type === "turn") {
53
+ const verdict = event.result.passed === undefined ? "" : event.result.passed ? " ✓" : " ✗";
54
+ const detail = event.result.action ?? event.result.aiResponse ?? event.result.input;
55
+ this.log(`[${event.scenarioRef}] turn ${event.result.turnIndex}: ${detail}${verdict}`);
56
+ return event.result.passed === false;
57
+ }
58
+ if (event.type === "scenarioSummary") {
59
+ this.log(`[${event.scenarioRef}] scenario ${event.overallPassed ? "PASSED" : "FAILED"}`);
60
+ return !event.overallPassed;
61
+ }
62
+ if (event.type === "summary") {
63
+ this.log(`Overall: ${event.verdict.toUpperCase()} (${event.scenarios.length} scenario(s))`);
64
+ return event.verdict === "fail";
65
+ }
66
+ this.log(`Error: ${event.message}`);
67
+ return true;
68
+ }
69
+ }
70
+ //# sourceMappingURL=eval.js.map