convoai 1.6.2 → 1.8.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 (72) hide show
  1. package/README.md +38 -2
  2. package/dist/src/api/calls.d.ts +33 -36
  3. package/dist/src/api/calls.js +12 -7
  4. package/dist/src/api/calls.js.map +1 -1
  5. package/dist/src/api/numbers.d.ts +63 -0
  6. package/dist/src/api/numbers.js +27 -0
  7. package/dist/src/api/numbers.js.map +1 -0
  8. package/dist/src/api/types.d.ts +6 -0
  9. package/dist/src/commands/call/hangup.js +9 -16
  10. package/dist/src/commands/call/hangup.js.map +1 -1
  11. package/dist/src/commands/call/initiate.js +69 -112
  12. package/dist/src/commands/call/initiate.js.map +1 -1
  13. package/dist/src/commands/call/status.js +14 -32
  14. package/dist/src/commands/call/status.js.map +1 -1
  15. package/dist/src/commands/completion.js +2 -1
  16. package/dist/src/commands/completion.js.map +1 -1
  17. package/dist/src/commands/go.js +64 -0
  18. package/dist/src/commands/go.js.map +1 -1
  19. package/dist/src/commands/phone/_dashboard.d.ts +31 -0
  20. package/dist/src/commands/phone/_dashboard.js +127 -0
  21. package/dist/src/commands/phone/_dashboard.js.map +1 -0
  22. package/dist/src/commands/phone/_helpers.d.ts +30 -0
  23. package/dist/src/commands/phone/_helpers.js +133 -0
  24. package/dist/src/commands/phone/_helpers.js.map +1 -0
  25. package/dist/src/commands/phone/_modes/agent.d.ts +22 -0
  26. package/dist/src/commands/phone/_modes/agent.js +59 -0
  27. package/dist/src/commands/phone/_modes/agent.js.map +1 -0
  28. package/dist/src/commands/phone/_modes/free.d.ts +29 -0
  29. package/dist/src/commands/phone/_modes/free.js +44 -0
  30. package/dist/src/commands/phone/_modes/free.js.map +1 -0
  31. package/dist/src/commands/phone/_modes/translate.d.ts +30 -0
  32. package/dist/src/commands/phone/_modes/translate.js +89 -0
  33. package/dist/src/commands/phone/_modes/translate.js.map +1 -0
  34. package/dist/src/commands/phone/get.d.ts +2 -0
  35. package/dist/src/commands/phone/get.js +34 -0
  36. package/dist/src/commands/phone/get.js.map +1 -0
  37. package/dist/src/commands/phone/go.d.ts +2 -0
  38. package/dist/src/commands/phone/go.js +235 -0
  39. package/dist/src/commands/phone/go.js.map +1 -0
  40. package/dist/src/commands/phone/hangup.d.ts +2 -0
  41. package/dist/src/commands/phone/hangup.js +20 -0
  42. package/dist/src/commands/phone/hangup.js.map +1 -0
  43. package/dist/src/commands/phone/history.d.ts +2 -0
  44. package/dist/src/commands/phone/history.js +56 -0
  45. package/dist/src/commands/phone/history.js.map +1 -0
  46. package/dist/src/commands/phone/import.d.ts +2 -0
  47. package/dist/src/commands/phone/import.js +88 -0
  48. package/dist/src/commands/phone/import.js.map +1 -0
  49. package/dist/src/commands/phone/numbers.d.ts +2 -0
  50. package/dist/src/commands/phone/numbers.js +34 -0
  51. package/dist/src/commands/phone/numbers.js.map +1 -0
  52. package/dist/src/commands/phone/remove.d.ts +2 -0
  53. package/dist/src/commands/phone/remove.js +31 -0
  54. package/dist/src/commands/phone/remove.js.map +1 -0
  55. package/dist/src/commands/phone/send.d.ts +2 -0
  56. package/dist/src/commands/phone/send.js +228 -0
  57. package/dist/src/commands/phone/send.js.map +1 -0
  58. package/dist/src/commands/phone/status.d.ts +2 -0
  59. package/dist/src/commands/phone/status.js +34 -0
  60. package/dist/src/commands/phone/status.js.map +1 -0
  61. package/dist/src/commands/phone/update.d.ts +2 -0
  62. package/dist/src/commands/phone/update.js +41 -0
  63. package/dist/src/commands/phone/update.js.map +1 -0
  64. package/dist/src/commands/quickstart.js +85 -19
  65. package/dist/src/commands/quickstart.js.map +1 -1
  66. package/dist/src/config/schema.d.ts +23 -0
  67. package/dist/src/config/schema.js +6 -0
  68. package/dist/src/config/schema.js.map +1 -1
  69. package/dist/src/index.js +42 -3
  70. package/dist/src/index.js.map +1 -1
  71. package/package.json +1 -1
  72. package/src/web/phone-dashboard.html +180 -0
@@ -0,0 +1,235 @@
1
+ import chalk from 'chalk';
2
+ import { getCallAPI, getNumberAPI, getConfig, pickOutboundNumber, buildChannelName, buildCallRequest, buildTTSConfig } from './_helpers.js';
3
+ import { generateRtcToken } from '../../utils/token.js';
4
+ import { printSuccess, printError, printHint } from '../../ui/output.js';
5
+ import { withSpinner } from '../../ui/spinner.js';
6
+ import { handleError } from '../../utils/errors.js';
7
+ import { track } from '../../utils/telemetry.js';
8
+ import { PhoneDashboard } from './_dashboard.js';
9
+ import { buildFreeCallConfig, collectFreeParams } from './_modes/free.js';
10
+ import { buildTranslateCallConfig, collectTranslateParams } from './_modes/translate.js';
11
+ import { buildAgentCallConfig, collectAgentParams } from './_modes/agent.js';
12
+ async function selectMode() {
13
+ const { default: inquirer } = await import('inquirer');
14
+ const { mode } = await inquirer.prompt([{
15
+ type: 'list',
16
+ name: 'mode',
17
+ message: 'Choose a mode:',
18
+ choices: [
19
+ { name: '🌐 Translate Call — real-time translation, each side speaks their own language', value: 'translate' },
20
+ { name: '🤖 Agent Outbound — AI completes a task autonomously', value: 'agent' },
21
+ { name: '📱 Free Call — quick dial with optional AI assistance', value: 'free' },
22
+ ],
23
+ }]);
24
+ return mode;
25
+ }
26
+ async function resolveFromNumber(opts) {
27
+ const numberApi = getNumberAPI(opts.profile);
28
+ let fromNumber = opts.from;
29
+ if (!fromNumber && process.stdin.isTTY) {
30
+ let numbers = await numberApi.list();
31
+ if (numbers.length === 0) {
32
+ // Inline import wizard
33
+ const { default: inquirer } = await import('inquirer');
34
+ console.log(chalk.yellow('\n No phone numbers found. Let\'s import one.\n'));
35
+ const ans = await inquirer.prompt([
36
+ { type: 'list', name: 'provider', message: 'Provider:', choices: ['twilio', 'byo'] },
37
+ { type: 'input', name: 'number', message: 'Phone number (E.164):', validate: (v) => /^\+[1-9]\d{1,14}$/.test(v.trim()) || 'Invalid format' },
38
+ { type: 'input', name: 'label', message: 'Label:', validate: (v) => v.trim().length > 0 || 'Required' },
39
+ { type: 'input', name: 'address', message: 'SIP address:', validate: (v) => v.trim().length > 0 || 'Required' },
40
+ { type: 'list', name: 'transport', message: 'Transport:', choices: ['tls', 'tcp', 'udp'], default: 'tls' },
41
+ { type: 'input', name: 'user', message: 'SIP username (optional):' },
42
+ { type: 'password', name: 'password', message: 'SIP password (optional):', mask: '*' },
43
+ ]);
44
+ await numberApi.import({
45
+ provider: ans.provider,
46
+ phone_number: ans.number.trim(),
47
+ label: ans.label,
48
+ outbound: true,
49
+ inbound: false,
50
+ outbound_config: { address: ans.address, transport: ans.transport, user: ans.user || undefined, password: ans.password || undefined },
51
+ });
52
+ printSuccess(`Number imported: ${ans.number}`);
53
+ console.log('');
54
+ numbers = await numberApi.list();
55
+ }
56
+ const picked = await pickOutboundNumber(numbers);
57
+ fromNumber = picked.phone_number;
58
+ }
59
+ if (!fromNumber) {
60
+ throw new Error('--from is required. Provide a caller number or run interactively.');
61
+ }
62
+ return fromNumber;
63
+ }
64
+ async function goAction(opts) {
65
+ const config = getConfig(opts.profile);
66
+ const callApi = getCallAPI(opts.profile);
67
+ console.log(chalk.bold('\n📞 ConvoAI Phone\n'));
68
+ // 1. Select mode
69
+ if (opts.mode && !['translate', 'agent', 'free'].includes(opts.mode)) {
70
+ throw new Error(`Invalid mode "${opts.mode}". Use: translate, agent, or free`);
71
+ }
72
+ const mode = opts.mode || (process.stdin.isTTY ? await selectMode() : (() => { throw new Error('--mode is required in non-TTY'); })());
73
+ // 2. Resolve from number
74
+ const fromNumber = await resolveFromNumber({ from: opts.from, profile: opts.profile });
75
+ // 3. Collect mode-specific params and build call config
76
+ let callConfig;
77
+ let dashboardConfig = {};
78
+ // Load root config to get voice_profile (which lives on ConvoAIConfig, not ProfileConfig)
79
+ const configObj = (await import('../../config/manager.js')).loadConfig();
80
+ const voiceProfile = configObj.voice_profile;
81
+ if (mode === 'translate') {
82
+ const params = await collectTranslateParams({ to: opts.to, lang: opts.lang });
83
+ callConfig = buildTranslateCallConfig({
84
+ ...params,
85
+ fromNumber,
86
+ llm: config.llm ?? {},
87
+ tts: buildTTSConfig(config.tts ?? {}, voiceProfile),
88
+ asr: config.asr ?? {},
89
+ });
90
+ dashboardConfig = { sourceLang: params.sourceLang, targetLang: params.targetLang };
91
+ }
92
+ else if (mode === 'agent') {
93
+ const params = await collectAgentParams({ to: opts.to, task: opts.task, taskLang: opts.taskLang });
94
+ callConfig = buildAgentCallConfig({
95
+ ...params,
96
+ fromNumber,
97
+ llm: config.llm ?? {},
98
+ tts: buildTTSConfig(config.tts ?? {}, voiceProfile),
99
+ asr: config.asr ?? {},
100
+ });
101
+ dashboardConfig = { task: params.task, taskLang: params.taskLang };
102
+ }
103
+ else {
104
+ const params = await collectFreeParams({ to: opts.to, task: opts.task });
105
+ callConfig = buildFreeCallConfig({
106
+ ...params,
107
+ fromNumber,
108
+ llm: config.llm ?? {},
109
+ tts: buildTTSConfig(config.tts ?? {}, voiceProfile),
110
+ asr: config.asr ?? {},
111
+ });
112
+ }
113
+ // 4. Generate tokens
114
+ const channelName = buildChannelName();
115
+ const appCert = process.env.AGORA_APP_CERTIFICATE ?? configObj.app_certificate;
116
+ const agentToken = await generateRtcToken(channelName, 0, 86400, config.app_id, appCert);
117
+ const sipToken = await generateRtcToken(channelName, 1, 86400, config.app_id, appCert);
118
+ if (!agentToken || !sipToken) {
119
+ printError('Token generation failed. Check app_certificate.');
120
+ process.exit(1);
121
+ }
122
+ // 5. Build API request
123
+ const request = buildCallRequest({
124
+ fromNumber: callConfig.fromNumber,
125
+ toNumber: callConfig.toNumber,
126
+ channelName,
127
+ agentToken,
128
+ sipToken,
129
+ llm: callConfig.llm,
130
+ tts: callConfig.tts,
131
+ asr: callConfig.asr,
132
+ idleTimeout: callConfig.idleTimeout,
133
+ });
134
+ if (opts.dryRun) {
135
+ console.log(JSON.stringify(request, null, 2));
136
+ return;
137
+ }
138
+ // 6. Initiate call
139
+ const result = await withSpinner('Starting call...', () => callApi.send(request));
140
+ track('phone_go');
141
+ if (opts.json) {
142
+ console.log(JSON.stringify({ agent_id: result.agent_id, mode, channel: channelName }, null, 2));
143
+ return;
144
+ }
145
+ printSuccess(`Call initiated (agent_id: ${result.agent_id})`);
146
+ // 7. Start dashboard (if enabled)
147
+ let dashboard = null;
148
+ if (opts.dashboard) {
149
+ dashboard = new PhoneDashboard({
150
+ mode,
151
+ label: callConfig.label,
152
+ agentId: result.agent_id,
153
+ callApi,
154
+ config: dashboardConfig,
155
+ });
156
+ const port = await dashboard.start();
157
+ console.log(chalk.dim(`📊 Dashboard: http://localhost:${port}/phone`));
158
+ // Auto-open browser
159
+ try {
160
+ const { findChrome } = await import('../../utils/find-chrome.js');
161
+ const chromePath = await findChrome();
162
+ if (chromePath) {
163
+ const { execFile } = await import('node:child_process');
164
+ execFile(chromePath, [`http://localhost:${port}/phone`]);
165
+ }
166
+ }
167
+ catch {
168
+ // Browser auto-open is best-effort
169
+ }
170
+ }
171
+ // 8. CLI status line + graceful shutdown
172
+ const { default: ora } = await import('ora');
173
+ const spinner = ora(callConfig.label).start();
174
+ const startTime = Date.now();
175
+ const cleanup = async () => {
176
+ spinner.stop();
177
+ running = false;
178
+ try {
179
+ await callApi.hangup(result.agent_id);
180
+ printSuccess('Call ended.');
181
+ }
182
+ catch {
183
+ printHint(`Call may still be active: convoai phone hangup ${result.agent_id}`);
184
+ }
185
+ };
186
+ process.on('SIGINT', cleanup);
187
+ // Poll until call ends
188
+ let running = true;
189
+ while (running) {
190
+ await new Promise(r => setTimeout(r, 2000));
191
+ try {
192
+ const status = await callApi.status(result.agent_id);
193
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
194
+ const mm = String(Math.floor(elapsed / 60)).padStart(2, '0');
195
+ const ss = String(elapsed % 60).padStart(2, '0');
196
+ if (status.status === 'STOPPED' || status.status === 'FAILED') {
197
+ running = false;
198
+ spinner.succeed(`Call ended (${mm}:${ss})`);
199
+ }
200
+ else {
201
+ spinner.text = `${callConfig.label} — ${mm}:${ss}`;
202
+ }
203
+ }
204
+ catch {
205
+ // Ignore poll errors
206
+ }
207
+ }
208
+ process.removeListener('SIGINT', cleanup);
209
+ if (dashboard)
210
+ await dashboard.stop();
211
+ }
212
+ export function registerPhoneGo(phone) {
213
+ phone
214
+ .command('go')
215
+ .description('One-command phone experience — translate, agent, or free call')
216
+ .option('--mode <mode>', 'Skip mode selection (translate|agent|free)')
217
+ .option('--to <number>', 'Target phone number (E.164)')
218
+ .option('--from <number>', 'Caller ID (E.164)')
219
+ .option('--lang <pair>', 'Language pair, e.g. "zh:ja" (translate mode)')
220
+ .option('--task <prompt>', 'Task description (agent/free mode)')
221
+ .option('--task-lang <lang>', 'Language for agent to speak (agent mode)')
222
+ .option('--no-dashboard', 'Skip browser dashboard')
223
+ .option('--profile <name>', 'Config profile')
224
+ .option('--json', 'JSON output, no dashboard')
225
+ .option('--dry-run', 'Show request payload without calling')
226
+ .action(async (opts) => {
227
+ try {
228
+ await goAction(opts);
229
+ }
230
+ catch (error) {
231
+ handleError(error, { json: opts.json });
232
+ }
233
+ });
234
+ }
235
+ //# sourceMappingURL=go.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"go.js","sourceRoot":"","sources":["../../../../src/commands/phone/go.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerPhoneHangup(phone: Command): void;
@@ -0,0 +1,20 @@
1
+ import { getCallAPI } from './_helpers.js';
2
+ import { printSuccess } from '../../ui/output.js';
3
+ import { handleError } from '../../utils/errors.js';
4
+ export function registerPhoneHangup(phone) {
5
+ phone
6
+ .command('hangup <agent-id>')
7
+ .description('End an active call')
8
+ .option('--profile <name>', 'Config profile')
9
+ .action(async (agentId, opts) => {
10
+ try {
11
+ const api = getCallAPI(opts.profile);
12
+ await api.hangup(agentId);
13
+ printSuccess('Call ended');
14
+ }
15
+ catch (error) {
16
+ handleError(error);
17
+ }
18
+ });
19
+ }
20
+ //# sourceMappingURL=hangup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hangup.js","sourceRoot":"","sources":["../../../../src/commands/phone/hangup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,KAAK;SACF,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,oBAAoB,CAAC;SACjC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC9B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACrC,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC1B,YAAY,CAAC,YAAY,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerPhoneHistory(phone: Command): void;
@@ -0,0 +1,56 @@
1
+ import chalk from 'chalk';
2
+ import { getCallAPI } from './_helpers.js';
3
+ import { handleError } from '../../utils/errors.js';
4
+ function timeSince(ts) {
5
+ const sec = Math.floor(Date.now() / 1000) - ts;
6
+ if (sec < 60)
7
+ return 'just now';
8
+ if (sec < 3600)
9
+ return `${Math.floor(sec / 60)} min ago`;
10
+ if (sec < 86400)
11
+ return `${Math.floor(sec / 3600)} hr ago`;
12
+ return `${Math.floor(sec / 86400)} days ago`;
13
+ }
14
+ export function registerPhoneHistory(phone) {
15
+ phone
16
+ .command('history')
17
+ .description('List recent calls')
18
+ .option('--limit <n>', 'Max results', '20')
19
+ .option('--profile <name>', 'Config profile')
20
+ .option('--json', 'JSON output')
21
+ .action(async (opts) => {
22
+ try {
23
+ const api = getCallAPI(opts.profile);
24
+ // Fetch more than requested — we filter client-side by channel prefix
25
+ const result = await api.list({ limit: (parseInt(opts.limit, 10) || 20) * 3 });
26
+ const allList = result.data?.list ?? [];
27
+ // Filter to telephony sessions (channel starts with "call-" or "qs-call-")
28
+ const list = allList
29
+ .filter(c => c.channel?.startsWith('call-') || c.channel?.startsWith('qs-call-'))
30
+ .slice(0, parseInt(opts.limit, 10) || 20);
31
+ if (opts.json) {
32
+ console.log(JSON.stringify(list, null, 2));
33
+ return;
34
+ }
35
+ if (list.length === 0) {
36
+ console.log(chalk.dim('\n No recent calls.\n'));
37
+ return;
38
+ }
39
+ console.log('');
40
+ for (const call of list) {
41
+ const id = call.agent_id.slice(0, 12);
42
+ const status = call.status === 'STOPPED' ? chalk.dim('completed') :
43
+ call.status === 'RUNNING' ? chalk.green('active') :
44
+ call.status === 'FAILED' ? chalk.red('failed') :
45
+ chalk.dim(call.status);
46
+ const ago = call.start_ts ? timeSince(call.start_ts) : '';
47
+ console.log(` ${chalk.cyan(id)} ${status} ${chalk.dim(ago)}`);
48
+ }
49
+ console.log('');
50
+ }
51
+ catch (error) {
52
+ handleError(error, { json: opts.json });
53
+ }
54
+ });
55
+ }
56
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../../../src/commands/phone/history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerPhoneImport(phone: Command): void;
@@ -0,0 +1,88 @@
1
+ import { getNumberAPI, validateE164 } from './_helpers.js';
2
+ import { printSuccess } from '../../ui/output.js';
3
+ import { handleError } from '../../utils/errors.js';
4
+ export function registerPhoneImport(phone) {
5
+ phone
6
+ .command('import')
7
+ .description('Import a new phone number')
8
+ .option('--number <number>', 'Phone number (E.164)')
9
+ .option('--provider <provider>', 'Provider (twilio / byo)')
10
+ .option('--label <label>', 'Label for this number')
11
+ .option('--sip-address <address>', 'SIP server address')
12
+ .option('--sip-transport <transport>', 'Transport (tls / tcp / udp)')
13
+ .option('--sip-user <user>', 'SIP username')
14
+ .option('--sip-password <password>', 'SIP password')
15
+ .option('--profile <name>', 'Config profile')
16
+ .option('--json', 'JSON output')
17
+ .action(async (opts) => {
18
+ try {
19
+ let phoneNumber = opts.number;
20
+ let provider = opts.provider;
21
+ let label = opts.label;
22
+ let sipAddress = opts.sipAddress;
23
+ let sipTransport = opts.sipTransport;
24
+ let sipUser = opts.sipUser;
25
+ let sipPassword = opts.sipPassword;
26
+ if (!phoneNumber || !provider || !label || !sipAddress) {
27
+ const { default: inquirer } = await import('inquirer');
28
+ if (!provider) {
29
+ const ans = await inquirer.prompt([{
30
+ type: 'list', name: 'provider', message: 'Provider:',
31
+ choices: [{ name: 'Twilio', value: 'twilio' }, { name: 'BYO (Bring Your Own)', value: 'byo' }],
32
+ }]);
33
+ provider = ans.provider;
34
+ }
35
+ if (!phoneNumber) {
36
+ const ans = await inquirer.prompt([{
37
+ type: 'input', name: 'number', message: 'Phone number (E.164):',
38
+ validate: (v) => /^\+[1-9]\d{1,14}$/.test(v.trim()) || 'Invalid E.164 format',
39
+ }]);
40
+ phoneNumber = ans.number;
41
+ }
42
+ if (!label) {
43
+ const ans = await inquirer.prompt([{
44
+ type: 'input', name: 'label', message: 'Label:',
45
+ validate: (v) => v.trim().length > 0 || 'Required',
46
+ }]);
47
+ label = ans.label;
48
+ }
49
+ if (!sipAddress) {
50
+ const ans = await inquirer.prompt([
51
+ { type: 'input', name: 'address', message: 'SIP address:', validate: (v) => v.trim().length > 0 || 'Required' },
52
+ { type: 'list', name: 'transport', message: 'Transport:', choices: ['tls', 'tcp', 'udp'], default: 'tls' },
53
+ { type: 'input', name: 'user', message: 'SIP username (optional):' },
54
+ { type: 'password', name: 'password', message: 'SIP password (optional):', mask: '*' },
55
+ ]);
56
+ sipAddress = ans.address;
57
+ sipTransport = ans.transport;
58
+ sipUser = ans.user || undefined;
59
+ sipPassword = ans.password || undefined;
60
+ }
61
+ }
62
+ phoneNumber = validateE164(phoneNumber);
63
+ const api = getNumberAPI(opts.profile);
64
+ const result = await api.import({
65
+ provider,
66
+ phone_number: phoneNumber,
67
+ label,
68
+ outbound: true,
69
+ inbound: false,
70
+ outbound_config: {
71
+ address: sipAddress,
72
+ transport: sipTransport || 'tls',
73
+ user: sipUser,
74
+ password: sipPassword,
75
+ },
76
+ });
77
+ if (opts.json) {
78
+ console.log(JSON.stringify(result, null, 2));
79
+ return;
80
+ }
81
+ printSuccess(`Number imported: ${result.phone_number}`);
82
+ }
83
+ catch (error) {
84
+ handleError(error, { json: opts.json });
85
+ }
86
+ });
87
+ }
88
+ //# sourceMappingURL=import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import.js","sourceRoot":"","sources":["../../../../src/commands/phone/import.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerPhoneNumbers(phone: Command): void;
@@ -0,0 +1,34 @@
1
+ import chalk from 'chalk';
2
+ import { getNumberAPI } from './_helpers.js';
3
+ import { handleError } from '../../utils/errors.js';
4
+ export function registerPhoneNumbers(phone) {
5
+ phone
6
+ .command('numbers')
7
+ .description('List imported phone numbers')
8
+ .option('--profile <name>', 'Config profile')
9
+ .option('--json', 'JSON output')
10
+ .action(async (opts) => {
11
+ try {
12
+ const api = getNumberAPI(opts.profile);
13
+ const numbers = await api.list();
14
+ if (opts.json) {
15
+ console.log(JSON.stringify(numbers, null, 2));
16
+ return;
17
+ }
18
+ if (numbers.length === 0) {
19
+ console.log(chalk.dim('\n No phone numbers. Run: convoai phone import\n'));
20
+ return;
21
+ }
22
+ console.log('');
23
+ for (const n of numbers) {
24
+ const dir = [n.outbound && 'outbound', n.inbound && 'inbound'].filter(Boolean).join('+');
25
+ console.log(` ${chalk.cyan(n.phone_number)} ${chalk.dim(dir)} ${n.label} ${chalk.dim(n.provider)}`);
26
+ }
27
+ console.log('');
28
+ }
29
+ catch (error) {
30
+ handleError(error, { json: opts.json });
31
+ }
32
+ });
33
+ }
34
+ //# sourceMappingURL=numbers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numbers.js","sourceRoot":"","sources":["../../../../src/commands/phone/numbers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,KAAK;SACF,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC;SAC/B,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvC,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAEjC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC,CAAC;gBAC5E,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,UAAU,EAAE,CAAC,CAAC,OAAO,IAAI,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACzF,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC1G,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerPhoneRemove(phone: Command): void;
@@ -0,0 +1,31 @@
1
+ import { getNumberAPI } from './_helpers.js';
2
+ import { printSuccess } from '../../ui/output.js';
3
+ import { handleError } from '../../utils/errors.js';
4
+ export function registerPhoneRemove(phone) {
5
+ phone
6
+ .command('remove <phone-number>')
7
+ .description('Remove a phone number')
8
+ .option('--force', 'Skip confirmation')
9
+ .option('--profile <name>', 'Config profile')
10
+ .action(async (phoneNumber, opts) => {
11
+ try {
12
+ if (!opts.force && process.stdin.isTTY) {
13
+ const { default: inquirer } = await import('inquirer');
14
+ const { confirm } = await inquirer.prompt([{
15
+ type: 'confirm', name: 'confirm',
16
+ message: `Remove ${phoneNumber}?`,
17
+ default: false,
18
+ }]);
19
+ if (!confirm)
20
+ return;
21
+ }
22
+ const api = getNumberAPI(opts.profile);
23
+ await api.delete(phoneNumber);
24
+ printSuccess(`Number removed: ${phoneNumber}`);
25
+ }
26
+ catch (error) {
27
+ handleError(error);
28
+ }
29
+ });
30
+ }
31
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../../../../src/commands/phone/remove.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,KAAK;SACF,OAAO,CAAC,uBAAuB,CAAC;SAChC,WAAW,CAAC,uBAAuB,CAAC;SACpC,MAAM,CAAC,SAAS,EAAE,mBAAmB,CAAC;SACtC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE;QAClC,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;gBACvC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;gBACvD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;wBACzC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS;wBAChC,OAAO,EAAE,UAAU,WAAW,GAAG;wBACjC,OAAO,EAAE,KAAK;qBACf,CAAC,CAAC,CAAC;gBACJ,IAAI,CAAC,OAAO;oBAAE,OAAO;YACvB,CAAC;YAED,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvC,MAAM,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAC9B,YAAY,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerPhoneSend(phone: Command): void;