@getdial/cli 0.21.1 → 0.23.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.
package/dist/cli.js CHANGED
@@ -110,14 +110,33 @@ number
110
110
  .option("--inbound-instruction <text>", "new system prompt for inbound calls to this number")
111
111
  .option("--inbound-voice-gender <male|female>", 'voice gender for inbound calls; pass "" to clear (reverts to the default, female)')
112
112
  .option("--nickname <text>", 'human-readable label for the number, e.g. "Support line"; pass "" to clear')
113
+ .option("--max-call-duration <seconds>", "maximum inbound call duration cap for this number (seconds)", (v) => {
114
+ const n = parseInt(v, 10);
115
+ if (!Number.isInteger(n) || n <= 0 || String(n) !== v.trim()) {
116
+ console.error(`error: --max-call-duration must be a positive integer (seconds), got: ${v}`);
117
+ process.exit(2);
118
+ }
119
+ return n;
120
+ })
121
+ .option("--clear-max-call-duration", "remove the per-number inbound call duration cap")
113
122
  .option("--json", "machine-readable output")
114
- .action(async (numberArg, opts) => process.exit(await runNumberSet({
115
- number: numberArg,
116
- inboundInstruction: opts.inboundInstruction,
117
- inboundVoiceGender: opts.inboundVoiceGender,
118
- nickname: opts.nickname,
119
- json: !!opts.json,
120
- })));
123
+ .action(async (numberArg, opts) => {
124
+ let maxCallDurationSeconds;
125
+ if (opts.clearMaxCallDuration) {
126
+ maxCallDurationSeconds = null;
127
+ }
128
+ else if (opts.maxCallDuration !== undefined) {
129
+ maxCallDurationSeconds = opts.maxCallDuration;
130
+ }
131
+ process.exit(await runNumberSet({
132
+ number: numberArg,
133
+ inboundInstruction: opts.inboundInstruction,
134
+ inboundVoiceGender: opts.inboundVoiceGender,
135
+ nickname: opts.nickname,
136
+ maxCallDurationSeconds,
137
+ json: !!opts.json,
138
+ }));
139
+ });
121
140
  const message = program
122
141
  .command("message")
123
142
  .description("Send an SMS. POST /api/v1/messages.")
@@ -157,8 +176,17 @@ const call = program
157
176
  .option("--outbound-instruction <text>", "system prompt for the agent that will speak")
158
177
  .option("--language <bcp47>", "BCP-47 language tag for the call (default: auto-detect from the destination number's country, alongside en-US)")
159
178
  .option("--voice-gender <male|female>", "voice gender for the agent (default: female; pass male to override)")
179
+ .option("--transfer-to <e164>", "forward-to number, E.164: the agent waits for a real human (riding out hold/IVR) then cold-transfers the call here")
160
180
  .option("--idempotency-key <key>", "unique key (e.g. a UUID) making the placement idempotent: re-running with the same key returns the already-placed call instead of dialing again")
161
181
  .option("--from-number-id <id>", "phoneNumberId to call from (defaults to onboard's number)")
182
+ .option("--max-call-duration <seconds>", "maximum call duration cap (seconds); call is terminated when this limit is reached", (v) => {
183
+ const n = parseInt(v, 10);
184
+ if (!Number.isInteger(n) || n <= 0 || String(n) !== v.trim()) {
185
+ console.error(`error: --max-call-duration must be a positive integer (seconds), got: ${v}`);
186
+ process.exit(2);
187
+ }
188
+ return n;
189
+ })
162
190
  .option("--json", "machine-readable output")
163
191
  .action(async (opts) => {
164
192
  if (!opts.to || !opts.outboundInstruction) {
@@ -170,8 +198,10 @@ const call = program
170
198
  outboundInstruction: opts.outboundInstruction,
171
199
  language: opts.language,
172
200
  voiceGender: opts.voiceGender,
201
+ transferTo: opts.transferTo,
173
202
  idempotencyKey: opts.idempotencyKey,
174
203
  fromNumberId: opts.fromNumberId,
204
+ maxCallDurationSeconds: opts.maxCallDuration,
175
205
  json: !!opts.json,
176
206
  }));
177
207
  });
@@ -8,8 +8,10 @@ export async function runCallSend(opts) {
8
8
  outboundInstruction: opts.outboundInstruction,
9
9
  language: opts.language,
10
10
  voiceGender: opts.voiceGender,
11
+ transferTo: opts.transferTo,
11
12
  idempotencyKey: opts.idempotencyKey,
12
13
  fromNumberId: opts.fromNumberId,
14
+ maxCallDurationSeconds: opts.maxCallDurationSeconds,
13
15
  });
14
16
  const waitCmd = `dial wait-for call.ended -f callId=${c.id} --json`;
15
17
  const followUpQuestion = "Want me to wait for the call to finish and report back (duration, final status, transcript)?";
@@ -8,6 +8,7 @@ export async function runNumberSet(opts) {
8
8
  inboundInstruction: opts.inboundInstruction,
9
9
  ...(opts.inboundVoiceGender !== undefined ? { inboundVoiceGender: opts.inboundVoiceGender } : {}),
10
10
  ...(opts.nickname !== undefined ? { nickname: opts.nickname } : {}),
11
+ ...(opts.maxCallDurationSeconds !== undefined ? { maxCallDurationSeconds: opts.maxCallDurationSeconds } : {}),
11
12
  });
12
13
  if (opts.json) {
13
14
  console.log(JSON.stringify({ ok: true, number: n }));
@@ -11,6 +11,8 @@ export async function placeCall(opts) {
11
11
  ...(opts.language && { language: opts.language }),
12
12
  // Omitted → the server uses the default voice gender (female).
13
13
  ...(opts.voiceGender ? { voiceGender: opts.voiceGender } : {}),
14
+ ...(opts.transferTo ? { transferTo: opts.transferTo } : {}),
15
+ ...(opts.maxCallDurationSeconds !== undefined ? { maxCallDurationSeconds: opts.maxCallDurationSeconds } : {}),
14
16
  }, auth.apiKey, opts.idempotencyKey ? { "idempotency-key": opts.idempotencyKey } : undefined);
15
17
  if (!res.ok)
16
18
  throw new DialError("call_failed", res.error, res.status);
@@ -31,8 +31,10 @@ export async function setNumberProperties(opts) {
31
31
  body.inboundVoiceGender = opts.inboundVoiceGender || null;
32
32
  if (opts.nickname !== undefined)
33
33
  body.nickname = opts.nickname;
34
+ if (opts.maxCallDurationSeconds !== undefined)
35
+ body.maxCallDurationSeconds = opts.maxCallDurationSeconds;
34
36
  if (Object.keys(body).length === 0) {
35
- throw new DialError("bad_request", "Provide at least one property to update (inboundInstruction, inboundVoiceGender, or nickname).");
37
+ throw new DialError("bad_request", "Provide at least one property to update (inboundInstruction, inboundVoiceGender, nickname, or maxCallDurationSeconds).");
36
38
  }
37
39
  const auth = requireAuth();
38
40
  // The REST API keys numbers by id; the CLI/tool takes the E.164 number for ergonomics,
@@ -7,8 +7,10 @@ const inputSchema = {
7
7
  outboundInstruction: z.string().min(1).describe("System prompt for the AI voice agent on this call"),
8
8
  language: z.string().optional().describe("BCP-47 language tag for the call. Omit to auto-detect from the destination number's country (alongside en-US)."),
9
9
  voiceGender: z.enum(["male", "female"]).optional().describe("Voice gender for the agent; the default is female"),
10
+ transferTo: z.string().optional().describe("Forward-to number, E.164: the agent waits for a real human (riding out hold/IVR) then cold-transfers the call here. Must differ from `to` and the from number."),
10
11
  idempotencyKey: z.string().optional().describe("Unique key (e.g. a UUID) making the placement idempotent: retrying with the same key returns the already-placed call instead of dialing again"),
11
12
  fromNumberId: z.string().optional().describe("Number id to call from; defaults to your primary number"),
13
+ maxCallDurationSeconds: z.number().int().positive().optional().describe("Maximum call duration cap (seconds); the call is terminated when this limit is reached"),
12
14
  };
13
15
  export const placeCallTool = {
14
16
  name: "place_call",
@@ -26,8 +28,10 @@ export const placeCallTool = {
26
28
  outboundInstruction: args.outboundInstruction,
27
29
  language: args.language,
28
30
  voiceGender: args.voiceGender,
31
+ transferTo: args.transferTo,
29
32
  idempotencyKey: args.idempotencyKey,
30
33
  fromNumberId: args.fromNumberId,
34
+ maxCallDurationSeconds: args.maxCallDurationSeconds,
31
35
  });
32
36
  return jsonResult({
33
37
  call,
@@ -7,6 +7,7 @@ const inputSchema = {
7
7
  inboundInstruction: z.string().min(1).optional().describe("New system prompt for inbound calls to this number"),
8
8
  inboundVoiceGender: z.enum(["male", "female"]).optional().describe("Voice gender for inbound calls to this number; the default is female"),
9
9
  nickname: z.string().max(100).optional().describe('Human-readable label for the number, e.g. "Support line". Pass an empty string to clear it.'),
10
+ maxCallDurationSeconds: z.number().int().positive().nullable().optional().describe("Maximum inbound call duration cap for this number (seconds). Pass null to clear the cap; omit to leave it unchanged."),
10
11
  };
11
12
  export const setNumberPropertiesTool = {
12
13
  name: "set_number_properties",
@@ -23,6 +24,7 @@ export const setNumberPropertiesTool = {
23
24
  inboundInstruction: args.inboundInstruction,
24
25
  ...(args.inboundVoiceGender !== undefined ? { inboundVoiceGender: args.inboundVoiceGender } : {}),
25
26
  ...(args.nickname !== undefined ? { nickname: args.nickname } : {}),
27
+ ...(args.maxCallDurationSeconds !== undefined ? { maxCallDurationSeconds: args.maxCallDurationSeconds } : {}),
26
28
  }),
27
29
  }),
28
30
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getdial/cli",
3
- "version": "0.21.1",
3
+ "version": "0.23.0",
4
4
  "description": "Dial CLI — install, sign up, and run the local listen service.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/skills.tar.gz CHANGED
Binary file