@getdial/cli 0.15.0 → 0.15.3

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.
@@ -1,8 +1,5 @@
1
1
  import { readAuth } from "../../lib/state.js";
2
- import { installSupervised, supervisorAvailability } from "../../lib/supervisor/index.js";
3
- function resolveDialPath() {
4
- return process.env.DIAL_BIN_OVERRIDE ?? process.argv[1] ?? "dial";
5
- }
2
+ import { installSupervised, resolveListenCommand, supervisorAvailability } from "../../lib/supervisor/index.js";
6
3
  export async function runListenInstall(opts) {
7
4
  const auth = readAuth();
8
5
  if (!auth) {
@@ -21,7 +18,7 @@ export async function runListenInstall(opts) {
21
18
  return 2;
22
19
  }
23
20
  try {
24
- const result = installSupervised(resolveDialPath());
21
+ const result = installSupervised(resolveListenCommand());
25
22
  if (opts.json)
26
23
  console.log(JSON.stringify({ ok: true, changed: result.changed, unit_path: result.unitPath, warnings: result.warnings }));
27
24
  else {
@@ -1,11 +1,8 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { installSupervised, uninstallSupervised, supervisorStatus, supervisorAvailability, lastEventAtFromLog, } from "../supervisor/index.js";
2
+ import { installSupervised, uninstallSupervised, supervisorStatus, supervisorAvailability, lastEventAtFromLog, resolveListenCommand, } from "../supervisor/index.js";
3
3
  import { paths } from "../paths.js";
4
4
  import { requireAuth } from "./auth.js";
5
5
  import { DialError } from "./errors.js";
6
- function resolveDialPath() {
7
- return process.env.DIAL_BIN_OVERRIDE ?? process.argv[1] ?? "dial";
8
- }
9
6
  export function listenInstall() {
10
7
  requireAuth();
11
8
  const supervisor = supervisorAvailability();
@@ -13,7 +10,7 @@ export function listenInstall() {
13
10
  throw new DialError("supervisor_unavailable", supervisor.reason);
14
11
  }
15
12
  try {
16
- return installSupervised(resolveDialPath());
13
+ return installSupervised(resolveListenCommand());
17
14
  }
18
15
  catch (err) {
19
16
  throw new DialError("install_failed", err instanceof Error ? err.message : String(err));
@@ -1,5 +1,6 @@
1
1
  import { existsSync, readFileSync, statSync } from "node:fs";
2
2
  import { userInfo } from "node:os";
3
+ import { dirname, join } from "node:path";
3
4
  import { paths } from "../paths.js";
4
5
  import { logger } from "../log.js";
5
6
  import { LAUNCHD_LABEL, launchctlBootoutSilent, launchctlLoad, launchctlStatus, launchctlUnload, launchdPlistPath, renderLaunchdPlist, writeLaunchdPlist } from "./launchd.js";
@@ -33,13 +34,45 @@ export function supervisorAvailability() {
33
34
  }
34
35
  return { available: true };
35
36
  }
36
- export function installSupervised(programPath) {
37
+ /**
38
+ * Builds the argv the supervised listen daemon is launched with, baked into
39
+ * the launchd plist / systemd unit. Pure so it can be unit-tested without a
40
+ * real process or filesystem.
41
+ *
42
+ * - `override` (DIAL_BIN_OVERRIDE) always wins, for tests and packaging.
43
+ * - When the current process was launched from npm's ephemeral npx cache
44
+ * (`~/.npm/_npx/<hash>/…`, e.g. `npx @getdial/cli mcp`), baking that script
45
+ * path into a long-lived unit is fragile: the cache can be garbage-collected
46
+ * and the daemon would then point at a path that no longer exists. Re-invoke
47
+ * through `npx @getdial/cli listen` so each launch re-resolves the CLI.
48
+ * - Otherwise launch the running script directly (`<dial> listen`).
49
+ */
50
+ export function buildListenArgs(input) {
51
+ if (input.override)
52
+ return [input.override, "listen"];
53
+ if (/[/\\]_npx[/\\]/.test(input.scriptPath)) {
54
+ const npx = join(input.nodeDir, "npx");
55
+ return [input.npxExists ? npx : "npx", "-y", "@getdial/cli", "listen"];
56
+ }
57
+ return [input.scriptPath || "dial", "listen"];
58
+ }
59
+ /** Resolves {@link buildListenArgs} against the live process/environment. */
60
+ export function resolveListenCommand() {
61
+ const nodeDir = dirname(process.execPath);
62
+ return buildListenArgs({
63
+ override: process.env.DIAL_BIN_OVERRIDE,
64
+ scriptPath: process.argv[1] ?? "",
65
+ nodeDir,
66
+ npxExists: existsSync(join(nodeDir, "npx")),
67
+ });
68
+ }
69
+ export function installSupervised(programArgs) {
37
70
  const platform = currentPlatform();
38
71
  const p = paths();
39
72
  if (platform === "darwin") {
40
73
  const xml = renderLaunchdPlist({
41
74
  label: LAUNCHD_LABEL,
42
- programPath,
75
+ programArgs,
43
76
  stdoutPath: p.listenOutLog,
44
77
  stderrPath: p.listenErrLog,
45
78
  });
@@ -52,7 +85,7 @@ export function installSupervised(programPath) {
52
85
  return { changed, warnings: [], unitPath: path };
53
86
  }
54
87
  else {
55
- const unit = renderSystemdUnit({ programPath });
88
+ const unit = renderSystemdUnit({ programArgs });
56
89
  const { path, changed } = writeSystemdUnit(unit);
57
90
  systemctlEnableAndStart();
58
91
  const warnings = [];
@@ -35,6 +35,7 @@ export function renderLaunchdPlist(params) {
35
35
  // so we must prepend the directory of the currently running node (e.g. nvm's bin dir)
36
36
  // so the shebang can resolve. Falls back to /usr/local/bin which is where Homebrew puts node.
37
37
  const nodeDir = dirname(process.execPath);
38
+ const programArguments = params.programArgs.map((arg) => ` <string>${arg}</string>`).join("\n");
38
39
  return `<?xml version="1.0" encoding="UTF-8"?>
39
40
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
40
41
  <plist version="1.0">
@@ -43,8 +44,7 @@ export function renderLaunchdPlist(params) {
43
44
  <string>${params.label}</string>
44
45
  <key>ProgramArguments</key>
45
46
  <array>
46
- <string>${params.programPath}</string>
47
- <string>listen</string>
47
+ ${programArguments}
48
48
  </array>
49
49
  <key>RunAtLoad</key>
50
50
  <true/>
@@ -27,7 +27,7 @@ Wants=network-online.target
27
27
  [Service]
28
28
  Type=simple
29
29
  Environment="PATH=${nodeDir}:/usr/local/bin:/usr/bin:/bin"
30
- ExecStart=${params.programPath} listen
30
+ ExecStart=${params.programArgs.join(" ")}
31
31
  Restart=on-failure
32
32
  RestartSec=10
33
33
 
@@ -4,6 +4,20 @@ import { z } from "zod";
4
4
  * `.passthrough()` so extra fields aren't stripped from `structuredContent`.
5
5
  * Mirrors the remote server's schemas so the two surfaces stay aligned.
6
6
  */
7
+ // Status is either a simple string (e.g. a message's "queued"/"delivered") or a
8
+ // structured call-status object. `.passthrough()` tolerates extra provider fields.
9
+ const callStatusObjectSchema = z
10
+ .object({
11
+ state: z.string().nullish().describe('Lifecycle state, e.g. "Terminated", "Registered"'),
12
+ terminationType: z.string().nullish().describe('How it ended, e.g. "completed", "no-answer" (null until the call ends)'),
13
+ label: z.string().nullish().describe('Human-readable status, e.g. "Completed"'),
14
+ cancelRequested: z.boolean().nullish(),
15
+ cancelPending: z.boolean().nullish(),
16
+ })
17
+ .passthrough();
18
+ const statusSchema = z
19
+ .union([z.string(), callStatusObjectSchema])
20
+ .describe("Status — a plain string, or a structured call-status object");
7
21
  export const phoneNumberSchema = z
8
22
  .object({
9
23
  id: z.string().describe("Phone number id (pn_…)"),
@@ -20,7 +34,7 @@ export const messageSchema = z
20
34
  body: z.string(),
21
35
  channel: z.string().optional(),
22
36
  direction: z.string().optional(),
23
- status: z.string(),
37
+ status: statusSchema,
24
38
  createdAt: z.string().optional(),
25
39
  })
26
40
  .passthrough();
@@ -30,9 +44,9 @@ export const callSchema = z
30
44
  from: z.string(),
31
45
  to: z.string(),
32
46
  direction: z.string().optional(),
33
- status: z.string(),
34
- duration: z.number().optional(),
35
- transcript: z.string().nullable().optional(),
47
+ status: statusSchema,
48
+ duration: z.number().nullish(),
49
+ transcript: z.string().nullish(),
36
50
  instruction: z.string().nullable().optional(),
37
51
  createdAt: z.string().optional(),
38
52
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getdial/cli",
3
- "version": "0.15.0",
3
+ "version": "0.15.3",
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