@getdial/cli 0.23.0 → 0.24.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
@@ -2,6 +2,7 @@
2
2
  import { Command } from "commander";
3
3
  import { VERSION } from "./lib/version.js";
4
4
  import { runDoctor } from "./commands/doctor.js";
5
+ import { runBilling } from "./commands/billing.js";
5
6
  import { runSignup } from "./commands/signup.js";
6
7
  import { runOnboard } from "./commands/onboard.js";
7
8
  import { runListen } from "./commands/listen/index.js";
@@ -41,6 +42,11 @@ program
41
42
  .description("Report state and what to do next.")
42
43
  .option("--json", "machine-readable output")
43
44
  .action(async (opts) => process.exit(await runDoctor({ json: !!opts.json })));
45
+ program
46
+ .command("billing")
47
+ .description("Show account billing: balance, plan, per-number mode, recent activity. GET /api/v1/billing.")
48
+ .option("--json", "machine-readable output")
49
+ .action(async (opts) => process.exit(await runBilling({ json: !!opts.json })));
44
50
  program
45
51
  .command("signup <email>")
46
52
  .description("Request an email OTP for the given address.")
@@ -94,13 +100,11 @@ number
94
100
  .description("Purchase an additional phone number. POST /api/v1/numbers.")
95
101
  .requiredOption("--inbound-instruction <text>", "system prompt for inbound calls to this number")
96
102
  .option("--inbound-voice-gender <male|female>", "voice gender for inbound calls (default: female; pass male to override)")
97
- .option("--country <iso2>", "ISO-3166-1 alpha-2 country code (defaults to US server-side)")
98
- .option("--area-code <code>", "preferred area code (US/CA)")
103
+ .option("--area-code <code>", "preferred US area code (only US numbers can be provisioned)")
99
104
  .option("--json", "machine-readable output")
100
105
  .action(async (opts) => process.exit(await runNumberPurchase({
101
106
  inboundInstruction: opts.inboundInstruction,
102
107
  inboundVoiceGender: opts.inboundVoiceGender,
103
- country: opts.country,
104
108
  areaCode: opts.areaCode,
105
109
  json: !!opts.json,
106
110
  })));
@@ -110,7 +114,7 @@ number
110
114
  .option("--inbound-instruction <text>", "new system prompt for inbound calls to this number")
111
115
  .option("--inbound-voice-gender <male|female>", 'voice gender for inbound calls; pass "" to clear (reverts to the default, female)')
112
116
  .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) => {
117
+ .option("--max-call-duration <seconds>", "call duration cap for this number, in seconds, applied as a hard ceiling to both inbound and outbound calls (the smallest of the per-number, account, and per-call caps wins)", (v) => {
114
118
  const n = parseInt(v, 10);
115
119
  if (!Number.isInteger(n) || n <= 0 || String(n) !== v.trim()) {
116
120
  console.error(`error: --max-call-duration must be a positive integer (seconds), got: ${v}`);
@@ -118,7 +122,7 @@ number
118
122
  }
119
123
  return n;
120
124
  })
121
- .option("--clear-max-call-duration", "remove the per-number inbound call duration cap")
125
+ .option("--clear-max-call-duration", "remove the per-number call duration cap")
122
126
  .option("--json", "machine-readable output")
123
127
  .action(async (numberArg, opts) => {
124
128
  let maxCallDurationSeconds;
@@ -0,0 +1,56 @@
1
+ import { getBilling } from "../lib/ops/billing.js";
2
+ import { isDialError } from "../lib/ops/errors.js";
3
+ import { printDialError } from "../lib/cli-error.js";
4
+ const usd = (cents) => `$${(cents / 100).toFixed(2)}`;
5
+ export async function runBilling(opts) {
6
+ try {
7
+ const billing = await getBilling();
8
+ if (opts.json) {
9
+ console.log(JSON.stringify({ ok: true, ...billing }));
10
+ return 0;
11
+ }
12
+ console.log(`balance: ${usd(billing.balanceCents)}`);
13
+ if (billing.subscription) {
14
+ const s = billing.subscription;
15
+ const numbers = `${s.quantity} number${s.quantity === 1 ? "" : "s"}`;
16
+ const renewal = s.cancelAtPeriodEnd ? `cancels ${s.periodEnd}` : `renews ${s.periodEnd}`;
17
+ console.log(`plan: subscribed (${s.interval}, ${numbers}) — ${renewal}`);
18
+ }
19
+ else {
20
+ console.log(`plan: pay-as-you-go`);
21
+ }
22
+ if (billing.numbers.length > 0) {
23
+ console.log(`numbers:`);
24
+ for (const n of billing.numbers) {
25
+ const mode = n.mode === "FIXED" ? "subscription" : "pay-as-you-go";
26
+ const nick = n.nickname ? ` "${n.nickname}"` : "";
27
+ console.log(` ${n.number}${nick} ${mode} id=${n.id}`);
28
+ }
29
+ }
30
+ if (billing.deposits.length > 0) {
31
+ console.log(`recent credits:`);
32
+ for (const d of billing.deposits) {
33
+ console.log(` ${d.createdAt} +${usd(d.amountCents)} (${d.kind})`);
34
+ }
35
+ }
36
+ if (billing.paymentMethods.length > 0) {
37
+ console.log(`payment methods:`);
38
+ for (const p of billing.paymentMethods) {
39
+ const tag = p.isDefault ? " (default)" : "";
40
+ if (p.type === "card") {
41
+ const exp = `${String(p.expMonth).padStart(2, "0")}/${String(p.expYear).slice(-2)}`;
42
+ console.log(` ${p.brand} •••• ${p.last4} exp ${exp}${tag}`);
43
+ }
44
+ else {
45
+ console.log(` ${p.type}${p.email ? ` ${p.email}` : ""}${tag}`);
46
+ }
47
+ }
48
+ }
49
+ return 0;
50
+ }
51
+ catch (e) {
52
+ if (isDialError(e))
53
+ return printDialError(opts.json, e);
54
+ throw e;
55
+ }
56
+ }
@@ -6,7 +6,6 @@ export async function runNumberPurchase(opts) {
6
6
  const n = await purchaseNumber({
7
7
  inboundInstruction: opts.inboundInstruction,
8
8
  inboundVoiceGender: opts.inboundVoiceGender,
9
- country: opts.country,
10
9
  areaCode: opts.areaCode,
11
10
  });
12
11
  if (opts.json) {
@@ -0,0 +1,10 @@
1
+ import { apiGet } from "../api.js";
2
+ import { requireAuth } from "./auth.js";
3
+ import { DialError } from "./errors.js";
4
+ export async function getBilling() {
5
+ const auth = requireAuth();
6
+ const res = await apiGet("/api/v1/billing", auth.apiKey);
7
+ if (!res.ok)
8
+ throw new DialError("billing_failed", res.error, res.status);
9
+ return res.data;
10
+ }
@@ -13,8 +13,6 @@ export async function purchaseNumber(opts) {
13
13
  const body = { inboundInstruction: opts.inboundInstruction };
14
14
  if (opts.inboundVoiceGender)
15
15
  body.inboundVoiceGender = opts.inboundVoiceGender;
16
- if (opts.country)
17
- body.country = opts.country;
18
16
  if (opts.areaCode)
19
17
  body.areaCode = opts.areaCode;
20
18
  const res = await apiPost("/api/v1/numbers", body, auth.apiKey);
@@ -5,8 +5,7 @@ import { phoneNumberSchema } from "../schemas.js";
5
5
  const inputSchema = {
6
6
  inboundInstruction: z.string().min(1).describe("System prompt for inbound calls to this number"),
7
7
  inboundVoiceGender: z.enum(["male", "female"]).optional().describe("Voice gender for inbound calls to this number; the default is female"),
8
- country: z.string().optional().describe("ISO-3166-1 alpha-2 country code (defaults to US server-side)"),
9
- areaCode: z.string().optional().describe("Preferred area code (US/CA)"),
8
+ areaCode: z.string().optional().describe("Preferred US area code; omitted any available US number. Only US numbers can be provisioned at this time"),
10
9
  };
11
10
  export const purchaseNumberTool = {
12
11
  name: "purchase_number",
@@ -21,7 +20,6 @@ export const purchaseNumberTool = {
21
20
  number: await purchaseNumber({
22
21
  inboundInstruction: args.inboundInstruction,
23
22
  inboundVoiceGender: args.inboundVoiceGender,
24
- country: args.country,
25
23
  areaCode: args.areaCode,
26
24
  }),
27
25
  }),
@@ -7,7 +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
+ maxCallDurationSeconds: z.number().int().positive().nullable().optional().describe("Call duration cap for this number, in seconds, applied as a hard ceiling to both inbound and outbound calls (the smallest of the per-number, account, and per-call caps wins). Pass null to clear the cap; omit to leave it unchanged."),
11
11
  };
12
12
  export const setNumberPropertiesTool = {
13
13
  name: "set_number_properties",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getdial/cli",
3
- "version": "0.23.0",
3
+ "version": "0.24.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