@getdial/cli 0.13.1 → 0.14.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/README.md +13 -1
- package/dist/cli.js +5 -0
- package/dist/commands/call/get.js +28 -36
- package/dist/commands/call/list.js +20 -37
- package/dist/commands/call/send.js +52 -65
- package/dist/commands/doctor.js +2 -68
- package/dist/commands/mcp.js +17 -0
- package/dist/commands/message/list.js +20 -37
- package/dist/commands/message/send.js +22 -35
- package/dist/commands/number/list.js +21 -29
- package/dist/commands/number/purchase.js +23 -32
- package/dist/commands/number/set.js +19 -40
- package/dist/commands/onboard.js +36 -67
- package/dist/commands/signup.js +23 -24
- package/dist/commands/wait-for.js +33 -67
- package/dist/lib/cli-error.js +24 -0
- package/dist/lib/ops/account.js +136 -0
- package/dist/lib/ops/auth.js +18 -0
- package/dist/lib/ops/calls.js +33 -0
- package/dist/lib/ops/errors.js +23 -0
- package/dist/lib/ops/events.js +63 -0
- package/dist/lib/ops/listen.js +51 -0
- package/dist/lib/ops/local-targets.js +35 -0
- package/dist/lib/ops/messages.js +26 -0
- package/dist/lib/ops/numbers.js +39 -0
- package/dist/lib/supervisor/systemd.js +7 -23
- package/dist/mcp/register.js +27 -0
- package/dist/mcp/result.js +6 -0
- package/dist/mcp/server.js +20 -0
- package/dist/mcp/tool.js +1 -0
- package/dist/mcp/tools/add-command-target.js +22 -0
- package/dist/mcp/tools/add-url-target.js +26 -0
- package/dist/mcp/tools/get-account-status.js +13 -0
- package/dist/mcp/tools/get-call.js +16 -0
- package/dist/mcp/tools/index.js +41 -0
- package/dist/mcp/tools/list-calls.js +22 -0
- package/dist/mcp/tools/list-local-targets.js +12 -0
- package/dist/mcp/tools/list-messages.js +22 -0
- package/dist/mcp/tools/list-numbers.js +12 -0
- package/dist/mcp/tools/listen-install.js +13 -0
- package/dist/mcp/tools/listen-status.js +12 -0
- package/dist/mcp/tools/listen-uninstall.js +12 -0
- package/dist/mcp/tools/onboard.js +34 -0
- package/dist/mcp/tools/place-call.js +33 -0
- package/dist/mcp/tools/purchase-number.js +22 -0
- package/dist/mcp/tools/remove-local-target.js +16 -0
- package/dist/mcp/tools/send-message.js +22 -0
- package/dist/mcp/tools/set-number-properties.js +20 -0
- package/dist/mcp/tools/sign-up.js +18 -0
- package/dist/mcp/tools/wait-for-event.js +25 -0
- package/package.json +2 -1
- package/skills.tar.gz +0 -0
package/README.md
CHANGED
|
@@ -63,8 +63,9 @@ dial wait-for message.received --field to=+14155550123
|
|
|
63
63
|
| `dial local-target add cmd <path>` | Run an executable once per event. |
|
|
64
64
|
| `dial local-target list` | List registered fan-out targets. |
|
|
65
65
|
| `dial local-target remove <id>` | Unregister a fan-out target. |
|
|
66
|
+
| `dial mcp` | Run a local stdio MCP server exposing every command as an agent tool. |
|
|
66
67
|
|
|
67
|
-
Run `dial --help` for the full command tree, or `dial <command> --help` for a specific command's flags. Every command accepts `--json` for machine-readable output.
|
|
68
|
+
Run `dial --help` for the full command tree, or `dial <command> --help` for a specific command's flags. Every command accepts `--json` for machine-readable output (except `dial mcp`, which speaks JSON-RPC on stdout).
|
|
68
69
|
|
|
69
70
|
## Configuration
|
|
70
71
|
|
|
@@ -84,6 +85,17 @@ dial onboard --code 123456 --agent claude-code
|
|
|
84
85
|
|
|
85
86
|
Supported agents: `claude-code`, `cursor`, `codex`, `opencode`, `pi`, `openclaw`, `nanoclaw`, `hermes`.
|
|
86
87
|
|
|
88
|
+
## Local MCP server
|
|
89
|
+
|
|
90
|
+
`dial mcp` runs a local [Model Context Protocol](https://modelcontextprotocol.io) server over stdio, exposing every command as an agent tool. Point a local MCP client at `dial mcp` as the server command — it reuses the API key saved by `dial onboard` (no OAuth, no config). It's the local counterpart to the hosted [Remote MCP](https://docs.getdial.ai/integrations/tools/remote-mcp) server, with the same operational tools plus the local-only verbs (`signup`, `onboard`, `listen`, `local-target`).
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Claude Code, for example
|
|
94
|
+
claude mcp add dial -- dial mcp
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
See the [Local MCP](https://docs.getdial.ai/integrations/tools/local-mcp) docs for client setup.
|
|
98
|
+
|
|
87
99
|
## Documentation
|
|
88
100
|
|
|
89
101
|
Full documentation lives at **[docs.getdial.ai](https://docs.getdial.ai)** — including the [CLI reference](https://docs.getdial.ai/documentation/cli/commands) and the [listen service](https://docs.getdial.ai/documentation/cli/listen-service) guide.
|
package/dist/cli.js
CHANGED
|
@@ -21,6 +21,7 @@ import { runLocalTargetAddUrl } from "./commands/local-target/add-url.js";
|
|
|
21
21
|
import { runLocalTargetAddCmd } from "./commands/local-target/add-cmd.js";
|
|
22
22
|
import { runLocalTargetRemove } from "./commands/local-target/remove.js";
|
|
23
23
|
import { runLocalTargetList } from "./commands/local-target/list.js";
|
|
24
|
+
import { runMcp } from "./commands/mcp.js";
|
|
24
25
|
const program = new Command();
|
|
25
26
|
program
|
|
26
27
|
.name("dial")
|
|
@@ -234,6 +235,10 @@ program
|
|
|
234
235
|
timeoutSeconds: opts.timeout,
|
|
235
236
|
json: !!opts.json,
|
|
236
237
|
})));
|
|
238
|
+
program
|
|
239
|
+
.command("mcp")
|
|
240
|
+
.description("Run a local stdio MCP server exposing Dial as agent tools (reuses your saved API key).")
|
|
241
|
+
.action(async () => process.exit(await runMcp()));
|
|
237
242
|
program.parseAsync(process.argv).catch((err) => {
|
|
238
243
|
console.error(err instanceof Error ? err.message : String(err));
|
|
239
244
|
process.exit(2);
|
|
@@ -1,41 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getCall } from "../../lib/ops/calls.js";
|
|
2
|
+
import { isDialError } from "../../lib/ops/errors.js";
|
|
3
|
+
import { printDialError } from "../../lib/cli-error.js";
|
|
3
4
|
export async function runCallGet(opts) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
console.log(
|
|
5
|
+
try {
|
|
6
|
+
const c = await getCall(opts.callId);
|
|
7
|
+
if (opts.json) {
|
|
8
|
+
console.log(JSON.stringify({ ok: true, call: c }));
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
console.log(`id: ${c.id}`);
|
|
12
|
+
console.log(`direction: ${c.direction}`);
|
|
13
|
+
console.log(`from: ${c.from}`);
|
|
14
|
+
console.log(`to: ${c.to}`);
|
|
15
|
+
console.log(`status: ${c.status}`);
|
|
16
|
+
console.log(`duration: ${c.duration}s`);
|
|
17
|
+
console.log(`created: ${c.createdAt}`);
|
|
18
|
+
if (c.instruction) {
|
|
19
|
+
console.log(`instruction:`);
|
|
20
|
+
console.log(c.instruction);
|
|
21
|
+
}
|
|
22
|
+
if (c.transcript) {
|
|
23
|
+
console.log(`transcript:`);
|
|
24
|
+
console.log(c.transcript);
|
|
25
|
+
}
|
|
17
26
|
return 0;
|
|
18
27
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
console.log(`status: ${c.status}`);
|
|
24
|
-
console.log(`duration: ${c.duration}s`);
|
|
25
|
-
console.log(`created: ${c.createdAt}`);
|
|
26
|
-
if (c.instruction) {
|
|
27
|
-
console.log(`instruction:`);
|
|
28
|
-
console.log(c.instruction);
|
|
28
|
+
catch (e) {
|
|
29
|
+
if (isDialError(e))
|
|
30
|
+
return printDialError(opts.json, e);
|
|
31
|
+
throw e;
|
|
29
32
|
}
|
|
30
|
-
if (c.transcript) {
|
|
31
|
-
console.log(`transcript:`);
|
|
32
|
-
console.log(c.transcript);
|
|
33
|
-
}
|
|
34
|
-
return 0;
|
|
35
|
-
}
|
|
36
|
-
function fail(json, code, message, extra) {
|
|
37
|
-
if (json)
|
|
38
|
-
console.log(JSON.stringify({ ok: false, code, message, ...extra }));
|
|
39
|
-
else
|
|
40
|
-
console.error(message);
|
|
41
33
|
}
|
|
@@ -1,42 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { listCalls } from "../../lib/ops/calls.js";
|
|
2
|
+
import { isDialError } from "../../lib/ops/errors.js";
|
|
3
|
+
import { printDialError } from "../../lib/cli-error.js";
|
|
3
4
|
export async function runCallList(opts) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const path = qs ? `/api/v1/calls?${qs}` : "/api/v1/calls";
|
|
18
|
-
const res = await apiGet(path, auth.apiKey);
|
|
19
|
-
if (!res.ok) {
|
|
20
|
-
fail(opts.json, "list_failed", res.error, { status: res.status });
|
|
21
|
-
return 2;
|
|
22
|
-
}
|
|
23
|
-
const calls = res.data.calls ?? [];
|
|
24
|
-
if (opts.json) {
|
|
25
|
-
console.log(JSON.stringify({ ok: true, calls }));
|
|
5
|
+
try {
|
|
6
|
+
const calls = await listCalls({ numberId: opts.numberId, direction: opts.direction, since: opts.since });
|
|
7
|
+
if (opts.json) {
|
|
8
|
+
console.log(JSON.stringify({ ok: true, calls }));
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
if (calls.length === 0) {
|
|
12
|
+
console.log("no calls.");
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
for (const c of calls) {
|
|
16
|
+
console.log(`${c.createdAt} ${c.direction.padEnd(8)} ${c.from} -> ${c.to} ${c.status} ${c.duration}s id=${c.id}`);
|
|
17
|
+
}
|
|
26
18
|
return 0;
|
|
27
19
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
catch (e) {
|
|
21
|
+
if (isDialError(e))
|
|
22
|
+
return printDialError(opts.json, e);
|
|
23
|
+
throw e;
|
|
31
24
|
}
|
|
32
|
-
for (const c of calls) {
|
|
33
|
-
console.log(`${c.createdAt} ${c.direction.padEnd(8)} ${c.from} -> ${c.to} ${c.status} ${c.duration}s id=${c.id}`);
|
|
34
|
-
}
|
|
35
|
-
return 0;
|
|
36
|
-
}
|
|
37
|
-
function fail(json, code, message, extra) {
|
|
38
|
-
if (json)
|
|
39
|
-
console.log(JSON.stringify({ ok: false, code, message, ...extra }));
|
|
40
|
-
else
|
|
41
|
-
console.error(message);
|
|
42
25
|
}
|
|
@@ -1,69 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { placeCall } from "../../lib/ops/calls.js";
|
|
2
|
+
import { isDialError } from "../../lib/ops/errors.js";
|
|
3
|
+
import { printDialError } from "../../lib/cli-error.js";
|
|
3
4
|
export async function runCallSend(opts) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
try {
|
|
6
|
+
const c = await placeCall({
|
|
7
|
+
to: opts.to,
|
|
8
|
+
outboundInstruction: opts.outboundInstruction,
|
|
9
|
+
language: opts.language,
|
|
10
|
+
fromNumberId: opts.fromNumberId,
|
|
11
|
+
});
|
|
12
|
+
const waitCmd = `dial wait-for call.ended -f callId=${c.id} --json`;
|
|
13
|
+
const followUpQuestion = "Want me to wait for the call to finish and report back (duration, final status, transcript)?";
|
|
14
|
+
if (opts.json) {
|
|
15
|
+
console.log(JSON.stringify({
|
|
16
|
+
ok: true,
|
|
17
|
+
call: c,
|
|
18
|
+
agentHint: {
|
|
19
|
+
action: "ask_user_about_waiting",
|
|
20
|
+
kind: "post_call_followup",
|
|
21
|
+
question: followUpQuestion,
|
|
22
|
+
waitCommand: waitCmd,
|
|
23
|
+
onYes: waitCmd,
|
|
24
|
+
onNo: null,
|
|
25
|
+
useStructuredToolIfAvailable: true,
|
|
26
|
+
},
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.log(`call initiated.`);
|
|
31
|
+
console.log(` from: ${c.from}`);
|
|
32
|
+
console.log(` to: ${c.to}`);
|
|
33
|
+
console.log(` status: ${c.status}`);
|
|
34
|
+
console.log(` call id: ${c.id}`);
|
|
35
|
+
console.log(``);
|
|
36
|
+
console.log(`The call has been dispatched. To learn when it ends (duration, final`);
|
|
37
|
+
console.log(`status, transcript availability), wait for the call.ended event:`);
|
|
38
|
+
console.log(``);
|
|
39
|
+
console.log(` ${waitCmd}`);
|
|
40
|
+
console.log(``);
|
|
41
|
+
console.log(`Suggestion: ask the user whether they'd like you to wait for the call`);
|
|
42
|
+
console.log(`to finish and report back, e.g.`);
|
|
43
|
+
console.log(``);
|
|
44
|
+
console.log(` "${followUpQuestion}"`);
|
|
45
|
+
console.log(``);
|
|
46
|
+
console.log(`If yes → run the wait-for above and report when it returns.`);
|
|
47
|
+
console.log(`If no → you're done; they can run the wait-for themselves later.`);
|
|
48
|
+
}
|
|
49
|
+
return 0;
|
|
8
50
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
51
|
+
catch (e) {
|
|
52
|
+
if (isDialError(e))
|
|
53
|
+
return printDialError(opts.json, e);
|
|
54
|
+
throw e;
|
|
13
55
|
}
|
|
14
|
-
const res = await apiPost("/api/v1/calls", {
|
|
15
|
-
to: opts.to,
|
|
16
|
-
fromNumberId,
|
|
17
|
-
outboundInstruction: opts.outboundInstruction,
|
|
18
|
-
language: opts.language,
|
|
19
|
-
}, auth.apiKey);
|
|
20
|
-
if (!res.ok) {
|
|
21
|
-
fail(opts.json, "call_failed", res.error, { status: res.status });
|
|
22
|
-
return 2;
|
|
23
|
-
}
|
|
24
|
-
const c = res.data.call;
|
|
25
|
-
const waitCmd = `dial wait-for call.ended -f callId=${c.id} --json`;
|
|
26
|
-
const followUpQuestion = "Want me to wait for the call to finish and report back (duration, final status, transcript)?";
|
|
27
|
-
if (opts.json) {
|
|
28
|
-
console.log(JSON.stringify({
|
|
29
|
-
ok: true,
|
|
30
|
-
call: c,
|
|
31
|
-
agentHint: {
|
|
32
|
-
action: "ask_user_about_waiting",
|
|
33
|
-
kind: "post_call_followup",
|
|
34
|
-
question: followUpQuestion,
|
|
35
|
-
waitCommand: waitCmd,
|
|
36
|
-
onYes: waitCmd,
|
|
37
|
-
onNo: null,
|
|
38
|
-
useStructuredToolIfAvailable: true,
|
|
39
|
-
},
|
|
40
|
-
}));
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
console.log(`call initiated.`);
|
|
44
|
-
console.log(` from: ${c.from}`);
|
|
45
|
-
console.log(` to: ${c.to}`);
|
|
46
|
-
console.log(` status: ${c.status}`);
|
|
47
|
-
console.log(` call id: ${c.id}`);
|
|
48
|
-
console.log(``);
|
|
49
|
-
console.log(`The call has been dispatched. To learn when it ends (duration, final`);
|
|
50
|
-
console.log(`status, transcript availability), wait for the call.ended event:`);
|
|
51
|
-
console.log(``);
|
|
52
|
-
console.log(` ${waitCmd}`);
|
|
53
|
-
console.log(``);
|
|
54
|
-
console.log(`Suggestion: ask the user whether they'd like you to wait for the call`);
|
|
55
|
-
console.log(`to finish and report back, e.g.`);
|
|
56
|
-
console.log(``);
|
|
57
|
-
console.log(` "${followUpQuestion}"`);
|
|
58
|
-
console.log(``);
|
|
59
|
-
console.log(`If yes → run the wait-for above and report when it returns.`);
|
|
60
|
-
console.log(`If no → you're done; they can run the wait-for themselves later.`);
|
|
61
|
-
}
|
|
62
|
-
return 0;
|
|
63
|
-
}
|
|
64
|
-
function fail(json, code, message, extra) {
|
|
65
|
-
if (json)
|
|
66
|
-
console.log(JSON.stringify({ ok: false, code, message, ...extra }));
|
|
67
|
-
else
|
|
68
|
-
console.error(message);
|
|
69
56
|
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -1,70 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { apiGet, baseUrl, pingBackend } from "../lib/api.js";
|
|
3
|
-
import { supervisorStatus, lastEventAtFromLog } from "../lib/supervisor/index.js";
|
|
4
|
-
import { paths } from "../lib/paths.js";
|
|
5
|
-
import { VERSION } from "../lib/version.js";
|
|
6
|
-
const OTP_EXPIRY_MS = 10 * 60 * 1000;
|
|
7
|
-
async function buildReport() {
|
|
8
|
-
const ping = await pingBackend();
|
|
9
|
-
const auth = readAuth();
|
|
10
|
-
const pending = readPendingSignup();
|
|
11
|
-
let keyValid = null;
|
|
12
|
-
if (auth?.apiKey) {
|
|
13
|
-
const res = await apiGet("/api/v1/account", auth.apiKey);
|
|
14
|
-
keyValid = res.ok;
|
|
15
|
-
}
|
|
16
|
-
const pendingAgeMs = pending ? Date.now() - Date.parse(pending.createdAt) : null;
|
|
17
|
-
const pendingExpired = pendingAgeMs == null ? null : pendingAgeMs > OTP_EXPIRY_MS;
|
|
18
|
-
let listenState = { installed: false, running: false, lastEventAt: null };
|
|
19
|
-
try {
|
|
20
|
-
const s = supervisorStatus();
|
|
21
|
-
listenState = {
|
|
22
|
-
installed: s.installed,
|
|
23
|
-
running: s.running,
|
|
24
|
-
lastEventAt: lastEventAtFromLog(paths().listenLog),
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
// unsupported platform — leave defaults
|
|
29
|
-
}
|
|
30
|
-
let nextStep;
|
|
31
|
-
if (!auth) {
|
|
32
|
-
if (pending && pendingExpired === false)
|
|
33
|
-
nextStep = "onboard";
|
|
34
|
-
else if (pending && pendingExpired)
|
|
35
|
-
nextStep = "resend_otp";
|
|
36
|
-
else
|
|
37
|
-
nextStep = "signup";
|
|
38
|
-
}
|
|
39
|
-
else if (keyValid === false) {
|
|
40
|
-
nextStep = "signup";
|
|
41
|
-
}
|
|
42
|
-
else if (!listenState.installed || !listenState.running) {
|
|
43
|
-
nextStep = "install_listen";
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
nextStep = "ready";
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
cli: { version: VERSION, node: process.versions.node },
|
|
50
|
-
backend: { url: baseUrl(), reachable: ping.reachable, latencyMs: ping.latencyMs },
|
|
51
|
-
auth: {
|
|
52
|
-
signedIn: Boolean(auth),
|
|
53
|
-
email: auth?.email ?? null,
|
|
54
|
-
accountId: auth?.accountId ?? null,
|
|
55
|
-
apiKeyPresent: Boolean(auth?.apiKey),
|
|
56
|
-
apiKeyFingerprint: auth?.apiKey ? auth.apiKey.slice(-4) : null,
|
|
57
|
-
keyValid,
|
|
58
|
-
},
|
|
59
|
-
pendingOtp: {
|
|
60
|
-
verificationId: pending?.verificationId ?? null,
|
|
61
|
-
ageSeconds: pendingAgeMs == null ? null : Math.round(pendingAgeMs / 1000),
|
|
62
|
-
expired: pendingExpired,
|
|
63
|
-
},
|
|
64
|
-
listen: listenState,
|
|
65
|
-
nextStep,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
1
|
+
import { accountStatus } from "../lib/ops/account.js";
|
|
68
2
|
function humanRender(r) {
|
|
69
3
|
const lines = [];
|
|
70
4
|
lines.push(`dial ${r.cli.version} (node ${r.cli.node})`);
|
|
@@ -87,7 +21,7 @@ function humanRender(r) {
|
|
|
87
21
|
return lines.join("\n");
|
|
88
22
|
}
|
|
89
23
|
export async function runDoctor(opts) {
|
|
90
|
-
const report = await
|
|
24
|
+
const report = await accountStatus();
|
|
91
25
|
if (opts.json)
|
|
92
26
|
console.log(JSON.stringify(report, null, 2));
|
|
93
27
|
else
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2
|
+
import { buildServer } from "../mcp/server.js";
|
|
3
|
+
/**
|
|
4
|
+
* Run the local stdio MCP server. JSON-RPC travels over stdout; the pino logger is
|
|
5
|
+
* already pinned to stderr (see lib/log.ts), and ops/tools never write to stdout, so
|
|
6
|
+
* the protocol stream stays clean. Stays alive until the client disconnects / stdin closes.
|
|
7
|
+
*/
|
|
8
|
+
export async function runMcp() {
|
|
9
|
+
const server = buildServer();
|
|
10
|
+
const transport = new StdioServerTransport();
|
|
11
|
+
await server.connect(transport);
|
|
12
|
+
await new Promise((resolve) => {
|
|
13
|
+
transport.onclose = () => resolve();
|
|
14
|
+
process.stdin.on("close", resolve);
|
|
15
|
+
});
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
@@ -1,42 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { listMessages } from "../../lib/ops/messages.js";
|
|
2
|
+
import { isDialError } from "../../lib/ops/errors.js";
|
|
3
|
+
import { printDialError } from "../../lib/cli-error.js";
|
|
3
4
|
export async function runMessageList(opts) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const path = qs ? `/api/v1/messages?${qs}` : "/api/v1/messages";
|
|
18
|
-
const res = await apiGet(path, auth.apiKey);
|
|
19
|
-
if (!res.ok) {
|
|
20
|
-
fail(opts.json, "list_failed", res.error, { status: res.status });
|
|
21
|
-
return 2;
|
|
22
|
-
}
|
|
23
|
-
const messages = res.data.messages ?? [];
|
|
24
|
-
if (opts.json) {
|
|
25
|
-
console.log(JSON.stringify({ ok: true, messages }));
|
|
5
|
+
try {
|
|
6
|
+
const messages = await listMessages({ numberId: opts.numberId, direction: opts.direction, since: opts.since });
|
|
7
|
+
if (opts.json) {
|
|
8
|
+
console.log(JSON.stringify({ ok: true, messages }));
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
if (messages.length === 0) {
|
|
12
|
+
console.log("no messages.");
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
for (const m of messages) {
|
|
16
|
+
console.log(`${m.createdAt} ${(m.direction ?? "").padEnd(8)} ${m.from} -> ${m.to} ${m.body}`);
|
|
17
|
+
}
|
|
26
18
|
return 0;
|
|
27
19
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
catch (e) {
|
|
21
|
+
if (isDialError(e))
|
|
22
|
+
return printDialError(opts.json, e);
|
|
23
|
+
throw e;
|
|
31
24
|
}
|
|
32
|
-
for (const m of messages) {
|
|
33
|
-
console.log(`${m.createdAt} ${m.direction.padEnd(8)} ${m.from} -> ${m.to} ${m.body}`);
|
|
34
|
-
}
|
|
35
|
-
return 0;
|
|
36
|
-
}
|
|
37
|
-
function fail(json, code, message, extra) {
|
|
38
|
-
if (json)
|
|
39
|
-
console.log(JSON.stringify({ ok: false, code, message, ...extra }));
|
|
40
|
-
else
|
|
41
|
-
console.error(message);
|
|
42
25
|
}
|
|
@@ -1,39 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { sendMessage } from "../../lib/ops/messages.js";
|
|
2
|
+
import { isDialError } from "../../lib/ops/errors.js";
|
|
3
|
+
import { printDialError } from "../../lib/cli-error.js";
|
|
3
4
|
export async function runMessageSend(opts) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
try {
|
|
6
|
+
const m = await sendMessage({ to: opts.to, body: opts.body, fromNumberId: opts.fromNumberId });
|
|
7
|
+
if (opts.json) {
|
|
8
|
+
console.log(JSON.stringify({ ok: true, message: m }));
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
console.log(`sent.`);
|
|
12
|
+
console.log(` channel: ${m.channel}`);
|
|
13
|
+
console.log(` from: ${m.from}`);
|
|
14
|
+
console.log(` to: ${m.to}`);
|
|
15
|
+
console.log(` body: ${m.body}`);
|
|
16
|
+
console.log(` status: ${m.status}`);
|
|
17
|
+
console.log(` sid: ${m.sid}`);
|
|
18
|
+
}
|
|
19
|
+
return 0;
|
|
8
20
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
21
|
+
catch (e) {
|
|
22
|
+
if (isDialError(e))
|
|
23
|
+
return printDialError(opts.json, e);
|
|
24
|
+
throw e;
|
|
13
25
|
}
|
|
14
|
-
const res = await apiPost("/api/v1/messages", { to: opts.to, body: opts.body, channel: "sms", fromNumberId }, auth.apiKey);
|
|
15
|
-
if (!res.ok) {
|
|
16
|
-
fail(opts.json, "send_failed", res.error, { status: res.status });
|
|
17
|
-
return 2;
|
|
18
|
-
}
|
|
19
|
-
const m = res.data.message;
|
|
20
|
-
if (opts.json) {
|
|
21
|
-
console.log(JSON.stringify({ ok: true, message: m }));
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
console.log(`sent.`);
|
|
25
|
-
console.log(` channel: ${m.channel}`);
|
|
26
|
-
console.log(` from: ${m.from}`);
|
|
27
|
-
console.log(` to: ${m.to}`);
|
|
28
|
-
console.log(` body: ${m.body}`);
|
|
29
|
-
console.log(` status: ${m.status}`);
|
|
30
|
-
console.log(` sid: ${m.sid}`);
|
|
31
|
-
}
|
|
32
|
-
return 0;
|
|
33
|
-
}
|
|
34
|
-
function fail(json, code, message, extra) {
|
|
35
|
-
if (json)
|
|
36
|
-
console.log(JSON.stringify({ ok: false, code, message, ...extra }));
|
|
37
|
-
else
|
|
38
|
-
console.error(message);
|
|
39
26
|
}
|
|
@@ -1,34 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { listNumbers } from "../../lib/ops/numbers.js";
|
|
2
|
+
import { isDialError } from "../../lib/ops/errors.js";
|
|
3
|
+
import { printDialError } from "../../lib/cli-error.js";
|
|
3
4
|
export async function runNumberList(opts) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
try {
|
|
6
|
+
const { numbers, defaultNumberId } = await listNumbers();
|
|
7
|
+
if (opts.json) {
|
|
8
|
+
console.log(JSON.stringify({ ok: true, numbers, defaultNumberId }));
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
if (numbers.length === 0) {
|
|
12
|
+
console.log("no phone numbers. provision one with `dial number purchase`.");
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
for (const n of numbers) {
|
|
16
|
+
const tag = n.id === defaultNumberId ? " (default)" : "";
|
|
17
|
+
console.log(`${n.number} id=${n.id} ${n.country}${tag}`);
|
|
18
|
+
}
|
|
17
19
|
return 0;
|
|
18
20
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
catch (e) {
|
|
22
|
+
if (isDialError(e))
|
|
23
|
+
return printDialError(opts.json, e);
|
|
24
|
+
throw e;
|
|
22
25
|
}
|
|
23
|
-
for (const n of numbers) {
|
|
24
|
-
const tag = n.id === auth.phoneNumberId ? " (default)" : "";
|
|
25
|
-
console.log(`${n.number} id=${n.id} ${n.country}${tag}`);
|
|
26
|
-
}
|
|
27
|
-
return 0;
|
|
28
|
-
}
|
|
29
|
-
function fail(json, code, message, extra) {
|
|
30
|
-
if (json)
|
|
31
|
-
console.log(JSON.stringify({ ok: false, code, message, ...extra }));
|
|
32
|
-
else
|
|
33
|
-
console.error(message);
|
|
34
26
|
}
|
|
@@ -1,36 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { purchaseNumber } from "../../lib/ops/numbers.js";
|
|
2
|
+
import { isDialError } from "../../lib/ops/errors.js";
|
|
3
|
+
import { printDialError } from "../../lib/cli-error.js";
|
|
3
4
|
export async function runNumberPurchase(opts) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
try {
|
|
6
|
+
const n = await purchaseNumber({
|
|
7
|
+
inboundInstruction: opts.inboundInstruction,
|
|
8
|
+
country: opts.country,
|
|
9
|
+
areaCode: opts.areaCode,
|
|
10
|
+
});
|
|
11
|
+
if (opts.json) {
|
|
12
|
+
console.log(JSON.stringify({ ok: true, number: n }));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
console.log(`purchased.`);
|
|
16
|
+
console.log(` number: ${n.number}`);
|
|
17
|
+
console.log(` id: ${n.id}`);
|
|
18
|
+
console.log(` country: ${n.country}`);
|
|
19
|
+
}
|
|
20
|
+
return 0;
|
|
8
21
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
body.areaCode = opts.areaCode;
|
|
14
|
-
const res = await apiPost("/api/v1/numbers", body, auth.apiKey);
|
|
15
|
-
if (!res.ok) {
|
|
16
|
-
fail(opts.json, "purchase_failed", res.error, { status: res.status });
|
|
17
|
-
return 2;
|
|
22
|
+
catch (e) {
|
|
23
|
+
if (isDialError(e))
|
|
24
|
+
return printDialError(opts.json, e);
|
|
25
|
+
throw e;
|
|
18
26
|
}
|
|
19
|
-
const n = res.data.number;
|
|
20
|
-
if (opts.json) {
|
|
21
|
-
console.log(JSON.stringify({ ok: true, number: n }));
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
console.log(`purchased.`);
|
|
25
|
-
console.log(` number: ${n.number}`);
|
|
26
|
-
console.log(` id: ${n.id}`);
|
|
27
|
-
console.log(` country: ${n.country}`);
|
|
28
|
-
}
|
|
29
|
-
return 0;
|
|
30
|
-
}
|
|
31
|
-
function fail(json, code, message, extra) {
|
|
32
|
-
if (json)
|
|
33
|
-
console.log(JSON.stringify({ ok: false, code, message, ...extra }));
|
|
34
|
-
else
|
|
35
|
-
console.error(message);
|
|
36
27
|
}
|