imsg-mcp 1.5.0 → 1.6.1

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/CHANGELOG.md CHANGED
@@ -3,6 +3,27 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and follows [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [1.6.1](https://github.com/george43g/imsg-mcp/compare/v1.6.0...v1.6.1) (2026-07-19)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **test:** strip a stray NUL byte that made a test file binary + guard it ([535b413](https://github.com/george43g/imsg-mcp/commit/535b413c361410337a58b040fc7ceb0983959b99)), closes [#20](https://github.com/george43g/imsg-mcp/issues/20)
12
+
13
+ # [1.6.0](https://github.com/george43g/imsg-mcp/compare/v1.5.0...v1.6.0) (2026-07-19)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * **cli:** friendlier windowDays + humans usage; add `resolve` console verb ([4a5f389](https://github.com/george43g/imsg-mcp/commit/4a5f3892d6ca9d0683c49c44b9052190552bc7f9))
19
+ * **db:** detect unsent messages via content-absence, not the lying date columns ([8a2c5e2](https://github.com/george43g/imsg-mcp/commit/8a2c5e2544f5393f7380a1fb4126e782e81e111c))
20
+ * **tui:** filter-commit (Enter) loads the matched thread, not just the cursor ([3666d4a](https://github.com/george43g/imsg-mcp/commit/3666d4a1a6febbdae935fb1406fcf4a39cd9f1ab))
21
+
22
+
23
+ ### Features
24
+
25
+ * **mcp:** resolve_conversation — free-form name → ranked threads in one call ([68485ab](https://github.com/george43g/imsg-mcp/commit/68485ab470b7b7a555719769169107d17c94a1cd))
26
+
6
27
  # [1.5.0](https://github.com/george43g/imsg-mcp/compare/v1.4.0...v1.5.0) (2026-07-19)
7
28
 
8
29
 
package/README.md CHANGED
@@ -58,6 +58,14 @@ imsg export weekend-crew~imsg~d4e5 \
58
58
  --output ~/weekend-crew.md
59
59
  ```
60
60
 
61
+ Relationship analytics from the CLI (all 7 types; add `--json` / `--yaml` to script them):
62
+
63
+ ```bash
64
+ imsg analytics relationship_leaderboard # top relationships by volume × reciprocity × recency
65
+ imsg analytics daily_heatmap # ASCII 7×24 activity grid
66
+ imsg analytics messaging_streaks --json # machine-readable for pipelines
67
+ ```
68
+
61
69
  Full walkthrough with screenshots: [**docs/WORKFLOWS.md**](docs/WORKFLOWS.md).
62
70
 
63
71
  ---
@@ -65,7 +73,7 @@ Full walkthrough with screenshots: [**docs/WORKFLOWS.md**](docs/WORKFLOWS.md).
65
73
  ## MCP tools
66
74
 
67
75
  <details>
68
- <summary><b>16 tools shipped (click to expand)</b></summary>
76
+ <summary><b>17 tools shipped (click to expand)</b></summary>
69
77
 
70
78
  | Tool | Purpose |
71
79
  |------|---------|
@@ -82,12 +90,13 @@ Full walkthrough with screenshots: [**docs/WORKFLOWS.md**](docs/WORKFLOWS.md).
82
90
  | `chat_analytics` | Pre-aggregated stats (heatmaps, leaderboards, etc). |
83
91
  | `list_contacts` / `search_contacts` | Browse/search contacts (name, phone, email). |
84
92
  | `get_contact` | One contact with all handles **+ the thread slug per handle**. |
93
+ | `resolve_conversation` | Free-form name/phrase → ranked threads (contacts + thread names + message content) in one call. |
85
94
  | `resolve_handle` | Phone/email → contact name. |
86
95
  | `init_human` | Scaffold a [humans/v1 relationship file](skills/humans/SKILL.md) for a contact or your top N relationships. |
87
96
 
88
97
  </details>
89
98
 
90
- Contacts are also on the CLI: `imsg contacts search <query>`, `imsg contacts show <handle-or-id>` (handles → thread slugs), `imsg contacts resolve <handle>`, `imsg contacts list`.
99
+ Contacts are also on the CLI: `imsg contacts search <query>`, `imsg contacts show <handle-or-id>` (handles → thread slugs), `imsg contacts resolve <handle>`, `imsg contacts list`. Turn a name into a thread in one shot with `imsg resolve "selena"` (add `--json`/`--yaml` to script it).
91
100
 
92
101
  Full reference (CLI subcommands + MCP tools + every flag): [**docs/TOOLS.md**](docs/TOOLS.md).
93
102
 
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { createInterface } from "node:readline";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { Command } from "commander";
6
6
  import { c as checkLocalAccess, f as formatAccessReport, I as IMPLEMENTED_TYPES, J as ANALYTIC_INFO, v as installShutdownHandlers, w as registerCleanup, K as looksLikeThreadSlug } from "./shutdown-Vh0gjb6m.js";
7
- import { A as APP_VERSION, t as toYaml } from "./meta-E4VgVmPs.js";
7
+ import { A as APP_VERSION, t as toYaml } from "./meta-f-cQuGK3.js";
8
8
  import { spawn } from "node:child_process";
9
9
  import { join, dirname } from "node:path";
10
10
  function distRoot() {
@@ -165,6 +165,14 @@ function pickFormat(opts) {
165
165
  if (opts.yaml) return "yaml";
166
166
  return "pretty";
167
167
  }
168
+ function parseWindowDays(value, fallback) {
169
+ if (value === void 0 || value === "") return fallback;
170
+ const n = Number(value);
171
+ if (!Number.isFinite(n) || n <= 0) {
172
+ throw new Error(`windowDays must be a positive number of days, got "${value}".`);
173
+ }
174
+ return n;
175
+ }
168
176
  function parseConsoleInput(line) {
169
177
  const parts = [];
170
178
  let current = "";
@@ -222,6 +230,13 @@ async function runConsoleCommand(cmd, args, client) {
222
230
  limit: Number(args[1] ?? 20)
223
231
  });
224
232
  return;
233
+ case "resolve":
234
+ if (!args[0]) throw new Error("Usage: resolve <name-or-phrase> [limit]");
235
+ await printToolResult(client, "resolve_conversation", {
236
+ query: args[0],
237
+ limit: Number(args[1] ?? 10)
238
+ });
239
+ return;
225
240
  case "wait":
226
241
  if (!args[0]) throw new Error("Usage: wait <chat> [timeoutSeconds]");
227
242
  await printToolResult(
@@ -281,10 +296,17 @@ async function runConsoleCommand(cmd, args, client) {
281
296
  } else if (verb === "top") {
282
297
  await printToolResult(client, "chat_analytics", {
283
298
  type: "relationship_leaderboard",
284
- windowDays: Number(args[1] ?? 1825)
299
+ windowDays: parseWindowDays(args[1], 1825)
285
300
  });
286
301
  } else {
287
- throw new Error(`Unknown humans verb: ${verb}. Use init|top.`);
302
+ const prefix = verb && verb !== "help" ? `Unknown humans verb: ${verb}.
303
+ ` : "";
304
+ throw new Error(
305
+ `${prefix}Usage:
306
+ humans init <contact|slug>
307
+ humans init top [n]
308
+ humans top [days]`
309
+ );
288
310
  }
289
311
  return;
290
312
  }
@@ -344,6 +366,7 @@ Available commands:
344
366
  messages [chat] [n] Show recent messages
345
367
  unread [n] Show unread messages
346
368
  search <query> [n] Search messages
369
+ resolve <name> [n] Resolve a name/phrase to ranked conversations
347
370
  wait <chat> [secs] Wait for a reply (default 60s)
348
371
  send <target> <msg> Send a message
349
372
  contacts [verb] Contacts: list [n] [offset] | search <q> [n] | resolve <handle> | show <handle-or-id>
@@ -424,7 +447,7 @@ async function runExportCommand(target, opts) {
424
447
  const { homedir } = await import("node:os");
425
448
  const { dirname: dirname2, join: join2, isAbsolute, resolve } = await import("node:path");
426
449
  const { getContactsDbPaths, getImsgDbPath, getSlugsDbPath } = await import("./shutdown-Vh0gjb6m.js").then((n) => n.$);
427
- const { IMessageDB } = await import("./imessage-db-BrHJPOq7.js").then((n) => n.i);
450
+ const { IMessageDB } = await import("./imessage-db-Dg_EPYPC.js").then((n) => n.i);
428
451
  const { streamExport } = await import("./exportStream-BCoZYUUZ.js");
429
452
  const { parseUserDate } = await import("./dateParse-DJXMfq3a.js");
430
453
  const format = normalizeFormat(opts.format ?? "md");
@@ -558,6 +581,17 @@ program.command("unread").description("Show unread messages across all conversat
558
581
  program.command("search").description("Search messages by text content").argument("<query>", "Search query").argument("[limit]", "Number of results", "20").action(async (query, limit) => {
559
582
  await withClient((c) => printToolResult(c, "search_messages", { query, limit: Number(limit) }));
560
583
  });
584
+ program.command("resolve").description("Resolve a free-form name/phrase to ranked conversations (contacts + threads)").argument("<query>", 'Name or phrase, e.g. "Selena"').argument("[limit]", "Max ranked matches", "10").option("--json", "Output structured JSON").option("--yaml", "Output structured YAML").action(async (query, limit, opts) => {
585
+ await withClient(
586
+ (c) => printToolResult(
587
+ c,
588
+ "resolve_conversation",
589
+ { query, limit: Number(limit) },
590
+ void 0,
591
+ pickFormat(opts)
592
+ )
593
+ );
594
+ });
561
595
  program.command("wait").description("Wait for a reply in a conversation").argument("<chat>", "Phone number, email, or thread slug").argument("[timeout]", "Timeout in seconds", "60").action(async (chat, timeout) => {
562
596
  await withClient(
563
597
  (c) => printToolResult(
@@ -616,7 +650,7 @@ humansCommand.command("top").description("Show the relationship leaderboard (vol
616
650
  (c) => printToolResult(
617
651
  c,
618
652
  "chat_analytics",
619
- { type: "relationship_leaderboard", windowDays: Number(windowDays) },
653
+ { type: "relationship_leaderboard", windowDays: parseWindowDays(windowDays, 1825) },
620
654
  void 0,
621
655
  pickFormat(opts)
622
656
  )
@@ -630,7 +664,7 @@ for (const type of IMPLEMENTED_TYPES) {
630
664
  (c) => printToolResult(
631
665
  c,
632
666
  "chat_analytics",
633
- { type, windowDays: Number(windowDays) },
667
+ { type, windowDays: parseWindowDays(windowDays, info.defaultWindowDays) },
634
668
  void 0,
635
669
  pickFormat(opts)
636
670
  )
@@ -753,6 +787,7 @@ if (invokedAsScript) {
753
787
  }
754
788
  export {
755
789
  parseConsoleInput,
790
+ parseWindowDays,
756
791
  runConsoleCommand,
757
792
  runExportCommand
758
793
  };
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sources":["../src/mcp-client.ts","../src/cli.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { APP_VERSION } from \"./meta.js\";\n\nexport interface ToolCallResult {\n content?: { type: string; text?: string }[];\n isError?: boolean;\n}\n\nfunction distRoot(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\nexport class LocalMcpClient {\n private proc: ReturnType<typeof spawn>;\n private requestId = 0;\n private pending = new Map<\n number,\n { resolve: (value: unknown) => void; reject: (error: Error) => void }\n >();\n private outBuf = \"\";\n private closed = false;\n\n constructor(private readonly onStderr?: (line: string) => void) {\n const entry = join(distRoot(), \"cli.js\");\n if (!existsSync(entry)) {\n throw new Error(\"dist/cli.js not found. Run `pnpm build` first.\");\n }\n\n this.proc = spawn(process.execPath, [entry, \"mcp\"], {\n cwd: process.cwd(),\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n this.proc.stderr!.on(\"data\", (chunk: Buffer) => {\n this.onStderr?.(chunk.toString(\"utf8\"));\n });\n\n this.proc.stdout!.on(\"data\", (chunk: Buffer) => {\n this.outBuf += chunk.toString(\"utf8\");\n const lines = this.outBuf.split(\"\\n\");\n this.outBuf = lines.pop() ?? \"\";\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const message = JSON.parse(line) as { id?: number };\n if (message.id != null && this.pending.has(message.id)) {\n const pending = this.pending.get(message.id);\n this.pending.delete(message.id);\n pending?.resolve(message);\n }\n } catch {\n // Ignore non-JSON lines on stdout.\n }\n }\n });\n\n // Handle unexpected child exit — reject all pending requests\n this.proc.on(\"exit\", (code) => {\n if (this.closed) return;\n for (const [, p] of this.pending) {\n p.reject(new Error(`MCP child exited unexpectedly with code ${code}`));\n }\n this.pending.clear();\n });\n }\n\n async start(): Promise<void> {\n const response = (await this.call(\"initialize\", {\n protocolVersion: \"2024-11-05\",\n capabilities: {},\n clientInfo: { name: \"imsg\", version: APP_VERSION },\n })) as { result?: unknown };\n\n if (response.result) {\n this.proc.stdin!.write(\n `${JSON.stringify({ jsonrpc: \"2.0\", method: \"notifications/initialized\", params: {} })}\\n`,\n );\n }\n }\n\n async callTool(name: string, args: object, timeoutMs = 30_000): Promise<ToolCallResult> {\n const response = (await this.call(\"tools/call\", { name, arguments: args }, timeoutMs)) as {\n result?: ToolCallResult;\n error?: { message: string };\n };\n if (response.error) {\n throw new Error(response.error.message);\n }\n return response.result ?? {};\n }\n\n async listTools(timeoutMs = 15_000): Promise<{ name: string; description?: string }[]> {\n const response = (await this.call(\"tools/list\", {}, timeoutMs)) as {\n result?: { tools?: { name: string; description?: string }[] };\n error?: { message: string };\n };\n if (response.error) {\n throw new Error(response.error.message);\n }\n return response.result?.tools ?? [];\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n\n // Close stdin to signal the child\n this.proc.stdin!.end();\n\n // Give child 2s to exit gracefully, then force kill\n const killTimer = setTimeout(() => {\n if (!this.proc.killed) {\n this.proc.kill(\"SIGKILL\");\n }\n }, 2000);\n killTimer.unref();\n\n this.proc.on(\"exit\", () => clearTimeout(killTimer));\n this.proc.kill(\"SIGTERM\");\n\n // Reject any remaining pending requests\n for (const [, p] of this.pending) {\n p.reject(new Error(\"MCP client closed\"));\n }\n this.pending.clear();\n }\n\n private call(method: string, params: object, timeoutMs = 15_000): Promise<unknown> {\n return new Promise((resolve, reject) => {\n if (this.closed) {\n reject(new Error(\"MCP client is closed\"));\n return;\n }\n\n const id = ++this.requestId;\n this.pending.set(id, { resolve, reject });\n this.proc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\n const timer = setTimeout(() => {\n if (!this.pending.has(id)) return;\n this.pending.delete(id);\n reject(new Error(`Request timeout after ${timeoutMs}ms.`));\n }, timeoutMs);\n timer.unref(); // Don't prevent process exit\n\n const original = this.pending.get(id);\n if (!original) return;\n this.pending.set(id, {\n resolve: (value) => {\n clearTimeout(timer);\n original.resolve(value);\n },\n reject: (error) => {\n clearTimeout(timer);\n original.reject(error);\n },\n });\n });\n }\n}\n","import { realpathSync } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport { pathToFileURL } from \"node:url\";\nimport { Command } from \"commander\";\nimport { checkLocalAccess, formatAccessReport } from \"./access-check.js\";\nimport { ANALYTIC_INFO, type AnalyticType, IMPLEMENTED_TYPES } from \"./analytics.js\";\nimport { toYaml } from \"./analytics-render.js\";\nimport { LocalMcpClient } from \"./mcp-client.js\";\nimport { APP_VERSION } from \"./meta.js\";\nimport { installShutdownHandlers, registerCleanup } from \"./shutdown.js\";\nimport { looksLikeThreadSlug } from \"./thread-slug.js\";\n\n// ── Colour helpers ─────────────────────────────────────────────────────\n\nconst color = {\n dim: (v: string) => `\\x1b[2m${v}\\x1b[0m`,\n cyan: (v: string) => `\\x1b[36m${v}\\x1b[0m`,\n green: (v: string) => `\\x1b[32m${v}\\x1b[0m`,\n yellow: (v: string) => `\\x1b[33m${v}\\x1b[0m`,\n red: (v: string) => `\\x1b[31m${v}\\x1b[0m`,\n};\n\nfunction log(message: string, style: \"dim\" | \"ok\" | \"warn\" | \"err\" = \"dim\") {\n const fn =\n style === \"ok\"\n ? color.green\n : style === \"warn\"\n ? color.yellow\n : style === \"err\"\n ? color.red\n : color.dim;\n console.log(fn(message));\n}\n\n// ── MCP client helpers ─────────────────────────────────────────────────\n\nasync function withClient<T>(run: (client: LocalMcpClient) => Promise<T>): Promise<T> {\n const client = new LocalMcpClient((line) => process.stderr.write(color.dim(`[server] ${line}`)));\n try {\n await client.start();\n return await run(client);\n } finally {\n client.close();\n }\n}\n\nasync function printToolResult(\n client: LocalMcpClient,\n name: string,\n args: object,\n timeoutMs?: number,\n format?: \"pretty\" | \"json\" | \"yaml\",\n) {\n const result = await client.callTool(name, args, timeoutMs);\n const text = result.content?.[0]?.text ?? JSON.stringify(result, null, 2);\n if (result.isError) throw new Error(text);\n if (format === \"json\" || format === \"yaml\") {\n // Structured output for scripting. Prefer the tool's structuredContent\n // (the machine-readable payload) over the human text block.\n const payload = (result as { structuredContent?: unknown }).structuredContent ?? result;\n console.log(format === \"json\" ? JSON.stringify(payload, null, 2) : toYaml(payload));\n return;\n }\n console.log(text);\n}\n\n/** Resolve a commander --json/--yaml option pair to a format. */\nfunction pickFormat(opts: { json?: boolean; yaml?: boolean }): \"pretty\" | \"json\" | \"yaml\" {\n if (opts.json) return \"json\";\n if (opts.yaml) return \"yaml\";\n return \"pretty\";\n}\n\n// ── Interactive console ────────────────────────────────────────────────\n\nexport function parseConsoleInput(line: string): { cmd: string; args: string[] } {\n const parts: string[] = [];\n let current = \"\";\n let quote: string | null = null;\n\n for (const char of line) {\n if ((char === '\"' || char === \"'\") && quote == null) {\n quote = char;\n continue;\n }\n if (char === quote) {\n quote = null;\n continue;\n }\n if (char === \" \" && quote == null) {\n if (current) {\n parts.push(current);\n current = \"\";\n }\n continue;\n }\n current += char;\n }\n if (current) parts.push(current);\n return { cmd: parts[0]?.toLowerCase() ?? \"\", args: parts.slice(1) };\n}\n\nexport async function runConsoleCommand(\n cmd: string,\n args: string[],\n client: LocalMcpClient,\n): Promise<void> {\n switch (cmd) {\n case \"conversations\":\n case \"list\":\n await printToolResult(client, \"list_conversations\", { limit: Number(args[0] ?? 20) });\n return;\n case \"messages\":\n case \"msg\": {\n const first = args[0];\n const firstIsLimit = first != null && /^\\d+$/.test(first);\n const chatIdentifier = firstIsLimit ? undefined : first;\n const limit = Number(firstIsLimit ? first : (args[1] ?? 20));\n await printToolResult(client, \"get_messages\", {\n ...(chatIdentifier\n ? looksLikeThreadSlug(chatIdentifier)\n ? { threadSlug: chatIdentifier }\n : { chatIdentifier }\n : {}),\n limit,\n });\n return;\n }\n case \"unread\":\n await printToolResult(\n client,\n \"get_unread_messages\",\n args[0] ? { limit: Number(args[0]) } : {},\n );\n return;\n case \"search\":\n if (!args[0]) throw new Error(\"Usage: search <query> [limit]\");\n await printToolResult(client, \"search_messages\", {\n query: args[0],\n limit: Number(args[1] ?? 20),\n });\n return;\n case \"wait\":\n if (!args[0]) throw new Error(\"Usage: wait <chat> [timeoutSeconds]\");\n await printToolResult(\n client,\n \"wait_for_reply\",\n {\n ...(looksLikeThreadSlug(args[0]) ? { threadSlug: args[0] } : { chatIdentifier: args[0] }),\n timeoutSeconds: Number(args[1] ?? 60),\n pollIntervalSeconds: 5,\n },\n 70_000,\n );\n return;\n case \"send\":\n if (args.length < 2) throw new Error(\"Usage: send <target> <message>\");\n await printToolResult(client, \"send_message\", {\n ...(looksLikeThreadSlug(args[0]) ? { threadSlug: args[0] } : { recipient: args[0] }),\n message: args.slice(1).join(\" \"),\n });\n return;\n case \"contacts\": {\n const verb = args[0];\n if (verb === \"list\" || verb === undefined) {\n await printToolResult(client, \"list_contacts\", {\n limit: Number(args[1] ?? 20),\n offset: Number(args[2] ?? 0),\n });\n } else if (verb === \"search\") {\n if (!args[1]) throw new Error(\"Usage: contacts search <query> [limit]\");\n await printToolResult(client, \"search_contacts\", {\n query: args[1],\n limit: Number(args[2] ?? 20),\n });\n } else if (verb === \"resolve\") {\n if (!args[1]) throw new Error(\"Usage: contacts resolve <handle>\");\n await printToolResult(client, \"resolve_handle\", { handle: args[1] });\n } else if (verb === \"show\") {\n if (!args[1]) throw new Error(\"Usage: contacts show <handle-or-id>\");\n const params = /^\\d+$/.test(args[1]) ? { id: Number(args[1]) } : { handle: args[1] };\n await printToolResult(client, \"get_contact\", params);\n } else {\n throw new Error(`Unknown contacts verb: ${verb}. Use list|search|resolve|show.`);\n }\n return;\n }\n case \"humans\": {\n const verb = args[0];\n if (verb === \"init\") {\n if (!args[1]) throw new Error(\"Usage: humans init <contact|slug|top N>\");\n if (args[1] === \"top\") {\n await printToolResult(client, \"init_human\", { top: Number(args[2] ?? 10) });\n } else if (args[1].includes(\"~\")) {\n await printToolResult(client, \"init_human\", { threadSlug: args[1] });\n } else {\n await printToolResult(client, \"init_human\", { contact: args.slice(1).join(\" \") });\n }\n } else if (verb === \"top\") {\n await printToolResult(client, \"chat_analytics\", {\n type: \"relationship_leaderboard\",\n windowDays: Number(args[1] ?? 1825),\n });\n } else {\n throw new Error(`Unknown humans verb: ${verb}. Use init|top.`);\n }\n return;\n }\n case \"analytics\":\n case \"stats\": {\n const type = args[0] as AnalyticType | undefined;\n if (!type || !IMPLEMENTED_TYPES.includes(type)) {\n throw new Error(`Usage: analytics <${IMPLEMENTED_TYPES.join(\"|\")}> [windowDays]`);\n }\n // Trailing `json`/`yaml` token picks the output format in the console.\n const fmtArg = args[args.length - 1];\n const format = fmtArg === \"json\" ? \"json\" : fmtArg === \"yaml\" ? \"yaml\" : \"pretty\";\n const windowDays =\n args[1] && /^\\d+$/.test(args[1]) ? Number(args[1]) : ANALYTIC_INFO[type].defaultWindowDays;\n await printToolResult(client, \"chat_analytics\", { type, windowDays }, undefined, format);\n return;\n }\n case \"logs\":\n await printToolResult(client, \"get_logs\", args[0] ? { tail: Number(args[0]) } : {});\n return;\n case \"last-error\":\n case \"lasterror\":\n await printToolResult(client, \"get_last_send_error\", {});\n return;\n case \"tools\":\n for (const tool of await client.listTools()) {\n console.log(`${tool.name}${tool.description ? ` - ${tool.description}` : \"\"}`);\n }\n return;\n case \"raw\":\n if (!args[0]) throw new Error(\"Usage: raw '<json>'\");\n {\n const parsed = JSON.parse(args.join(\" \")) as { name?: string; arguments?: object };\n if (!parsed.name)\n throw new Error('Expected JSON like {\"name\":\"tool_name\",\"arguments\":{...}}.');\n await printToolResult(client, parsed.name, parsed.arguments ?? {});\n }\n return;\n case \"tui\": {\n const { runTui } = await import(\"./tui/index.js\");\n await runTui();\n return;\n }\n case \"help\":\n case \"?\":\n console.log(CONSOLE_HELP);\n return;\n case \"quit\":\n case \"exit\":\n process.exit(0);\n return;\n default:\n throw new Error(`Unknown command: ${cmd}. Type \"help\" for available commands.`);\n }\n}\n\nconst CONSOLE_HELP = `\nAvailable commands:\n conversations [n] List recent conversations (default 20)\n messages [chat] [n] Show recent messages\n unread [n] Show unread messages\n search <query> [n] Search messages\n wait <chat> [secs] Wait for a reply (default 60s)\n send <target> <msg> Send a message\n contacts [verb] Contacts: list [n] [offset] | search <q> [n] | resolve <handle> | show <handle-or-id>\n humans <verb> Relationship files: init <contact|slug> | init top [n] | top [days]\n analytics <type> [days] [json|yaml]\n Analytics: ${IMPLEMENTED_TYPES.join(\" | \")}\n logs [tail] Show server debug logs\n last-error Show last send failure\n tools List available MCP tools\n raw <json> Send raw JSON-RPC to tools/call\n tui Launch the read-only TUI\n help Show this help\n quit Exit\n`.trim();\n\nasync function runInteractiveConsole(): Promise<void> {\n log(\"Starting local MCP server...\", \"dim\");\n const client = new LocalMcpClient((line) => process.stderr.write(color.dim(`[server] ${line}`)));\n await client.start();\n log(\"Console ready.\\n\", \"ok\");\n // Show the full help text on launch so the user doesn't have to type `help`\n // to discover what's available.\n console.log(CONSOLE_HELP);\n console.log(\"\");\n\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n // Event-driven line loop (not recursive rl.question): each command is async\n // (an MCP round-trip), so lines are queued and processed one at a time. This\n // is what makes piped/scripted input reliable — with recursive rl.question,\n // EOF (\"close\") raced the in-flight await and killed the command before its\n // output printed. Here EOF only exits AFTER the queue has drained.\n const queue: string[] = [];\n let processing = false;\n let closed = false;\n\n const finish = () => {\n client.close();\n process.exit(0);\n };\n\n const drain = async () => {\n if (processing) return;\n processing = true;\n while (queue.length > 0) {\n const line = queue.shift()!;\n const trimmed = line.trim();\n if (!trimmed) continue;\n const { cmd, args } = parseConsoleInput(trimmed);\n try {\n await runConsoleCommand(cmd, args, client);\n } catch (error) {\n log(error instanceof Error ? error.message : String(error), \"err\");\n }\n console.log(\"\");\n }\n processing = false;\n if (closed) finish();\n else rl.prompt();\n };\n\n rl.setPrompt(color.cyan(\"imsg> \"));\n rl.prompt();\n rl.on(\"line\", (line) => {\n queue.push(line);\n void drain();\n });\n // Ctrl-D / EOF (or a piped script running out of lines): exit once any\n // in-flight command and the queue have drained. Without this the MCP server\n // subprocess keeps the event loop alive and the console would hang.\n rl.on(\"close\", () => {\n closed = true;\n if (!processing && queue.length === 0) finish();\n });\n\n installShutdownHandlers();\n registerCleanup(() => client.close());\n}\n\n// ── Export command ─────────────────────────────────────────────────────\n\ninterface ExportOpts {\n format?: string;\n since?: string;\n until?: string;\n output?: string;\n includeAttachments?: boolean;\n attachmentsDir?: string;\n pageSize?: string;\n}\n\nfunction normalizeFormat(raw: string): \"markdown\" | \"csv\" | \"json\" | \"ndjson\" {\n const v = raw.toLowerCase();\n if (v === \"md\" || v === \"markdown\") return \"markdown\";\n if (v === \"csv\") return \"csv\";\n if (v === \"json\") return \"json\";\n if (v === \"ndjson\") return \"ndjson\";\n throw new Error(`Unknown format: ${raw}. Expected md, csv, json, or ndjson.`);\n}\n\nfunction extForFormat(fmt: \"markdown\" | \"csv\" | \"json\" | \"ndjson\"): string {\n return fmt === \"markdown\" ? \"md\" : fmt;\n}\n\nfunction sanitizeForFilename(s: string): string {\n return s.replace(/[^A-Za-z0-9._~-]+/g, \"_\").replace(/^_+|_+$/g, \"\") || \"chat\";\n}\n\nexport async function runExportCommand(target: string, opts: ExportOpts): Promise<void> {\n const { existsSync, mkdirSync, copyFileSync, statSync } = await import(\"node:fs\");\n const { homedir } = await import(\"node:os\");\n const { dirname, join, isAbsolute, resolve } = await import(\"node:path\");\n const { getContactsDbPaths, getImsgDbPath, getSlugsDbPath } = await import(\"./config.js\");\n const { IMessageDB } = await import(\"./imessage-db.js\");\n const { streamExport } = await import(\"./exportStream.js\");\n const { parseUserDate } = await import(\"./tui/dateParse.js\");\n\n const format = normalizeFormat(opts.format ?? \"md\");\n const ext = extForFormat(format);\n\n const pageSize = Number(opts.pageSize ?? \"1000\");\n if (!Number.isFinite(pageSize) || pageSize < 100 || pageSize > 5000) {\n throw new Error(\"--page-size must be between 100 and 5000.\");\n }\n\n const since = opts.since ? parseUserDate(opts.since) : null;\n if (opts.since && !since) throw new Error(`Could not parse --since: ${opts.since}`);\n const until = opts.until ? parseUserDate(opts.until) : null;\n if (opts.until && !until) throw new Error(`Could not parse --until: ${opts.until}`);\n\n const db = new IMessageDB(getImsgDbPath(), getContactsDbPaths(), getSlugsDbPath());\n try {\n // Resolve target → chatIdentifier + display slug for filename\n let chatIdentifier = target;\n let displayHandle = target;\n if (looksLikeThreadSlug(target)) {\n const rec = db.getSlugRecord(target);\n if (!rec) throw new Error(`Unknown thread slug: ${target}`);\n chatIdentifier = rec.chatIdentifier;\n displayHandle = rec.slug;\n }\n\n // Default output path: ~/imsg-export-<sanitized>-<YYYY-MM-DD>.<ext>\n let outputPath: string;\n if (opts.output) {\n outputPath = isAbsolute(opts.output) ? opts.output : resolve(opts.output);\n } else {\n const today = new Date().toISOString().slice(0, 10);\n outputPath = join(\n homedir(),\n `imsg-export-${sanitizeForFilename(displayHandle)}-${today}.${ext}`,\n );\n }\n\n const parent = dirname(outputPath);\n if (!existsSync(parent)) mkdirSync(parent, { recursive: true });\n\n log(`Exporting ${displayHandle} → ${outputPath} (${format})`, \"dim\");\n\n const result = await streamExport({\n db,\n chatIdentifier,\n format,\n outputPath,\n since,\n until,\n pageSize,\n });\n\n let attachmentSummary = \"\";\n if (opts.includeAttachments) {\n const dir = opts.attachmentsDir\n ? isAbsolute(opts.attachmentsDir)\n ? opts.attachmentsDir\n : resolve(opts.attachmentsDir)\n : `${outputPath}.attachments`;\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n\n const filters: Parameters<typeof db.searchAttachments>[0] = {\n chatIdentifier,\n limit: 0,\n };\n if (since) filters.sinceMs = since.getTime();\n if (until) filters.untilMs = until.getTime();\n const attachments = db.searchAttachments(filters);\n\n let copied = 0;\n let totalBytes = 0;\n const seen = new Set<string>();\n for (const a of attachments) {\n if (!a.filename) continue;\n const src = a.filename.replace(/^~/, homedir());\n if (!existsSync(src)) continue;\n const baseName = a.transferName || src.split(\"/\").pop() || `att-${a.rowId}`;\n let destName = `${a.rowId}-${sanitizeForFilename(baseName)}`;\n if (seen.has(destName)) destName = `${a.rowId}-${Date.now()}-${baseName}`;\n seen.add(destName);\n const dest = join(dir, destName);\n try {\n copyFileSync(src, dest);\n copied++;\n totalBytes += statSync(dest).size;\n } catch (err) {\n log(\n ` warn: copy failed for ${src}: ${err instanceof Error ? err.message : String(err)}`,\n \"warn\",\n );\n }\n }\n attachmentSummary = `\\nAttachments: ${copied} file(s), ${(totalBytes / 1024).toFixed(1)} KB → ${dir}`;\n }\n\n log(\n [\n \"\",\n `✓ Exported ${result.count} message(s) to ${result.savedTo}`,\n ` Format: ${format}`,\n ` Range: ${result.oldest?.toISOString() ?? \"(none)\"} → ${result.newest?.toISOString() ?? \"(none)\"}`,\n ` Size: ${(result.sizeBytes / 1024).toFixed(1)} KB${attachmentSummary}`,\n ].join(\"\\n\"),\n \"ok\",\n );\n } finally {\n await db.close();\n }\n}\n\n// ── CLI program (Commander) ────────────────────────────────────────────\n\nconst program = new Command()\n .name(\"imsg\")\n .version(APP_VERSION, \"-v, --version\")\n .description(\"CLI for the imsg-mcp iMessage MCP server\")\n .addHelpText(\n \"after\",\n `\nNotes:\n Use \"imsg doctor\" on a new machine.\n Run the MCP stdio server with \"imsg mcp\".\n Launch the read-only TUI with \"imsg tui\".`,\n );\n\nprogram\n .command(\"mcp\")\n .description(\"Run the MCP stdio server\")\n .action(async () => {\n const { runMcpServer } = await import(\"./index.js\");\n await runMcpServer();\n });\n\nprogram\n .command(\"cli\")\n .alias(\"console\")\n .description(\"Launch interactive console\")\n .action(runInteractiveConsole);\n\nprogram\n .command(\"doctor\")\n .description(\"Check local permissions and database access\")\n .action(async () => {\n const report = await checkLocalAccess();\n console.log(formatAccessReport(report));\n process.exitCode = report.ok ? 0 : 1;\n });\n\nprogram\n .command(\"conversations\")\n .alias(\"list\")\n .description(\"List recent conversations\")\n .argument(\"[limit]\", \"Number of conversations\", \"20\")\n .action(async (limit: string) => {\n await withClient((c) => printToolResult(c, \"list_conversations\", { limit: Number(limit) }));\n });\n\nprogram\n .command(\"messages\")\n .alias(\"msg\")\n .description(\"Show recent messages from a conversation\")\n .argument(\"[chat]\", \"Phone number, email, or thread slug\")\n .argument(\"[limit]\", \"Number of messages\", \"20\")\n .action(async (chat: string | undefined, limit: string) => {\n const firstIsLimit = chat != null && /^\\d+$/.test(chat);\n const chatIdentifier = firstIsLimit ? undefined : chat;\n const finalLimit = Number(firstIsLimit ? chat : limit);\n await withClient((c) =>\n printToolResult(c, \"get_messages\", {\n ...(chatIdentifier\n ? looksLikeThreadSlug(chatIdentifier)\n ? { threadSlug: chatIdentifier }\n : { chatIdentifier }\n : {}),\n limit: finalLimit,\n }),\n );\n });\n\nprogram\n .command(\"unread\")\n .description(\"Show unread messages across all conversations\")\n .argument(\"[limit]\", \"Number of messages\", \"100\")\n .action(async (limit: string) => {\n await withClient((c) => printToolResult(c, \"get_unread_messages\", { limit: Number(limit) }));\n });\n\nprogram\n .command(\"search\")\n .description(\"Search messages by text content\")\n .argument(\"<query>\", \"Search query\")\n .argument(\"[limit]\", \"Number of results\", \"20\")\n .action(async (query: string, limit: string) => {\n await withClient((c) => printToolResult(c, \"search_messages\", { query, limit: Number(limit) }));\n });\n\nprogram\n .command(\"wait\")\n .description(\"Wait for a reply in a conversation\")\n .argument(\"<chat>\", \"Phone number, email, or thread slug\")\n .argument(\"[timeout]\", \"Timeout in seconds\", \"60\")\n .action(async (chat: string, timeout: string) => {\n await withClient((c) =>\n printToolResult(\n c,\n \"wait_for_reply\",\n {\n ...(looksLikeThreadSlug(chat) ? { threadSlug: chat } : { chatIdentifier: chat }),\n timeoutSeconds: Number(timeout),\n pollIntervalSeconds: 5,\n },\n 70_000,\n ),\n );\n });\n\nprogram\n .command(\"send\")\n .description(\"Send a message via Messages.app\")\n .argument(\n \"<target>\",\n \"Recipient: thread slug, E.164 phone (+61401990797), local phone (0401 990 797), iMessage email, or contact name\",\n )\n .argument(\"<message...>\", \"Message text\")\n .action(async (target: string, messageParts: string[]) => {\n await withClient((c) =>\n printToolResult(c, \"send_message\", {\n ...(looksLikeThreadSlug(target) ? { threadSlug: target } : { recipient: target }),\n message: messageParts.join(\" \"),\n }),\n );\n });\n\nconst contactsCommand = program\n .command(\"contacts\")\n .description(\"Search and inspect macOS contacts (read-only)\");\n\ncontactsCommand\n .command(\"list\")\n .description(\"List contacts, sorted by name\")\n .argument(\"[limit]\", \"Number of contacts\", \"20\")\n .argument(\"[offset]\", \"Skip this many (pagination)\", \"0\")\n .action(async (limit: string, offset: string) => {\n await withClient((c) =>\n printToolResult(c, \"list_contacts\", { limit: Number(limit), offset: Number(offset) }),\n );\n });\n\ncontactsCommand\n .command(\"search\")\n .description(\"Search contacts by name, phone, or email\")\n .argument(\"<query>\", \"Substring to match\")\n .argument(\"[limit]\", \"Number of results\", \"20\")\n .action(async (query: string, limit: string) => {\n await withClient((c) => printToolResult(c, \"search_contacts\", { query, limit: Number(limit) }));\n });\n\ncontactsCommand\n .command(\"resolve\")\n .description(\"Resolve a phone number or email to its contact name\")\n .argument(\"<handle>\", \"Phone number or email\")\n .action(async (handle: string) => {\n await withClient((c) => printToolResult(c, \"resolve_handle\", { handle }));\n });\n\ncontactsCommand\n .command(\"show\")\n .description(\"Show a contact's handles and the thread slug for each\")\n .argument(\"<handleOrId>\", \"Phone, email, or numeric contact id\")\n .action(async (handleOrId: string) => {\n const args = /^\\d+$/.test(handleOrId) ? { id: Number(handleOrId) } : { handle: handleOrId };\n await withClient((c) => printToolResult(c, \"get_contact\", args));\n });\n\nconst humansCommand = program\n .command(\"humans\")\n .description(\"Scaffold humans/v1 relationship files (~/.agents/humans) — see the humans skill\");\n\nhumansCommand\n .command(\"init\")\n .description(\n \"Scaffold a relationship file for a contact/slug, or --top N for your top relationships\",\n )\n .argument(\"[contact]\", \"Contact name, phone, email, or thread slug\")\n .option(\"--top <n>\", \"Scaffold the top N relationships (by the relationship leaderboard)\")\n .action(async (contact: string | undefined, opts: { top?: string }) => {\n if (!contact && !opts.top) {\n console.error(\"Provide a contact/slug or --top N.\");\n process.exitCode = 1;\n return;\n }\n const args = opts.top\n ? { top: Number(opts.top) }\n : contact?.includes(\"~\")\n ? { threadSlug: contact }\n : { contact };\n await withClient((c) => printToolResult(c, \"init_human\", args));\n });\n\nhumansCommand\n .command(\"top\")\n .description(\"Show the relationship leaderboard (volume × reciprocity × recency, last 5 years)\")\n .argument(\"[windowDays]\", \"Days of history to rank\", \"1825\")\n .option(\"--json\", \"Output structured JSON\")\n .option(\"--yaml\", \"Output structured YAML\")\n .action(async (windowDays: string, opts: { json?: boolean; yaml?: boolean }) => {\n await withClient((c) =>\n printToolResult(\n c,\n \"chat_analytics\",\n { type: \"relationship_leaderboard\", windowDays: Number(windowDays) },\n undefined,\n pickFormat(opts),\n ),\n );\n });\n\n// `imsg analytics <type> [windowDays] [--json|--yaml]` — every implemented\n// analytic, not just the leaderboard. Each type gets its own subcommand so\n// `--help` and shell completion enumerate them.\nconst analyticsCommand = program\n .command(\"analytics\")\n .alias(\"stats\")\n .description(\"Run chat analytics (streaks, response times, heatmap, tapbacks, wrapped, …)\");\n\nfor (const type of IMPLEMENTED_TYPES) {\n const info = ANALYTIC_INFO[type];\n analyticsCommand\n .command(type)\n .description(info.description)\n .argument(\"[windowDays]\", \"Days of history to analyze\", String(info.defaultWindowDays))\n .option(\"--json\", \"Output structured JSON\")\n .option(\"--yaml\", \"Output structured YAML\")\n .action(async (windowDays: string, opts: { json?: boolean; yaml?: boolean }) => {\n await withClient((c) =>\n printToolResult(\n c,\n \"chat_analytics\",\n { type, windowDays: Number(windowDays) },\n undefined,\n pickFormat(opts),\n ),\n );\n });\n}\n\nprogram\n .command(\"logs\")\n .description(\"Show server debug logs\")\n .argument(\"[tail]\", \"Show only last N lines\")\n .action(async (tail: string | undefined) => {\n await withClient((c) => printToolResult(c, \"get_logs\", tail ? { tail: Number(tail) } : {}));\n });\n\nprogram\n .command(\"last-error\")\n .description(\"Show last send_message failure details\")\n .action(async () => {\n await withClient((c) => printToolResult(c, \"get_last_send_error\", {}));\n });\n\nprogram\n .command(\"tools\")\n .description(\"List available MCP tools\")\n .action(async () => {\n await withClient(async (c) => {\n for (const tool of await c.listTools()) {\n console.log(`${tool.name}${tool.description ? ` - ${tool.description}` : \"\"}`);\n }\n });\n });\n\nprogram\n .command(\"raw\")\n .description(\"Send raw JSON-RPC params to tools/call\")\n .argument(\"<json>\", 'JSON like {\"name\":\"tool_name\",\"arguments\":{...}}')\n .action(async (json: string) => {\n const parsed = JSON.parse(json) as { name?: string; arguments?: object };\n if (!parsed.name) throw new Error('Expected JSON like {\"name\":\"tool_name\",\"arguments\":{...}}.');\n await withClient((c) => printToolResult(c, parsed.name!, parsed.arguments ?? {}));\n });\n\nprogram\n .command(\"tui\")\n .description(\"Launch the read-only terminal UI\")\n .option(\"--theme <theme>\", 'TUI theme: \"safe\" or \"powerline\"')\n .option(\"--accent <hex>\", \"TUI accent color as #RRGGBB\")\n .action(async () => {\n const { runTui } = await import(\"./tui/index.js\");\n await runTui();\n });\n\n// ── Export ───────────────────────────────────────────────────────────────\n\nprogram\n .command(\"export <target>\")\n .description(\"Export a conversation to a file (md/csv/json/ndjson)\")\n .option(\"-f, --format <fmt>\", \"Output format: md (default), csv, json, ndjson\", \"md\")\n .option(\"--since <date>\", \"Earliest date (ISO or relative, e.g. '3 months ago')\")\n .option(\"--until <date>\", \"Latest date (ISO or relative)\")\n .option(\"-o, --output <path>\", \"Output path (default: ~/imsg-export-<target>-<YYYY-MM-DD>.<ext>)\")\n .option(\"--include-attachments\", \"Copy attachments next to the export\")\n .option(\"--attachments-dir <path>\", \"Where to copy attachments (default: <output>.attachments/)\")\n .option(\"--page-size <n>\", \"Messages per DB page (100-5000)\", \"1000\")\n .action(runExportCommand);\n\n// ── Setup ────────────────────────────────────────────────────────────────\n\nprogram\n .command(\"setup\")\n .description(\"Autodetect DB paths and emit an MCP host config snippet\")\n .option(\"-w, --write <host>\", 'Write into a host config: \"claude\" or \"cursor\"')\n .option(\"-r, --runtime <runtime>\", 'Runtime command: \"npx\" (default), \"bunx\", or \"global\"')\n .option(\"--print-only\", \"Just print the snippet (default behaviour)\")\n .action(async (opts: { write?: string; runtime?: string; printOnly?: boolean }) => {\n const { probeMachine, buildMcpSnippet, writeHostConfig } = await import(\"./setup.js\");\n const report = probeMachine();\n\n if (!report.imsgDb.readable) {\n log(`✗ Messages DB is not readable: ${report.imsgDb.path}`, \"err\");\n log(` ${report.imsgDb.error ?? \"\"}`, \"err\");\n log(\n \" Grant Full Disk Access to the running app: System Settings → Privacy & Security → Full Disk Access\",\n \"warn\",\n );\n process.exitCode = 1;\n return;\n }\n\n log(`✓ Messages DB readable: ${report.imsgDb.path}`, \"ok\");\n log(\n `✓ Address Book: ${report.contactsDbs.length} source(s), ${report.contactsDbs.filter((p) => p.readable).length} readable`,\n \"ok\",\n );\n log(\n ` slugs.db: ${report.slugsDb.path} ${report.slugsDb.exists ? \"(exists)\" : \"(will be created on first run)\"}`,\n );\n\n const runtime = opts.runtime === \"bunx\" || opts.runtime === \"global\" ? opts.runtime : \"npx\";\n const snippet = buildMcpSnippet(report, { runtime });\n\n if (opts.write) {\n if (opts.write !== \"claude\" && opts.write !== \"cursor\") {\n log(`✗ unknown host: ${opts.write} (expected \"claude\" or \"cursor\")`, \"err\");\n process.exitCode = 1;\n return;\n }\n const result = writeHostConfig(opts.write, report, { runtime });\n log(\n `✓ wrote ${opts.write} config to ${result.path}${result.replaced ? \" (replaced existing imessage entry)\" : \"\"}`,\n \"ok\",\n );\n log(` backup of any prior file at ${result.path}.bak`);\n return;\n }\n\n log(\"--- snippet ---\", \"dim\");\n process.stdout.write(snippet);\n });\n\n// ── Config ───────────────────────────────────────────────────────────────\n\nconst configCmd = program\n .command(\"config\")\n .description(\"Manage TUI settings (theme, accent color)\");\n\nconfigCmd\n .command(\"show\")\n .description(\"Print resolved TUI settings and where each value came from\")\n .action(async () => {\n const { resolveTuiConfig, defaultTuiConfigPath } = await import(\"./tui-config.js\");\n const cfg = resolveTuiConfig();\n log(\n `config file : ${cfg.configPath ?? `(none — defaults; would write to ${defaultTuiConfigPath()})`}`,\n );\n log(`theme : ${cfg.theme} (from ${cfg.origin.theme})`);\n log(`accentColor : ${cfg.accentColor} (from ${cfg.origin.accentColor})`);\n if (cfg.theme === \"powerline\") {\n log(\" — powerline theme requires a Nerd Font (https://www.nerdfonts.com)\", \"warn\");\n }\n for (const w of cfg.warnings) log(w, \"warn\");\n });\n\nconfigCmd\n .command(\"edit\")\n .description(\"Open the TUI config file in $EDITOR (creates it if missing)\")\n .action(async () => {\n const { defaultTuiConfigPath, findTuiConfigPath, writeTuiConfig, DEFAULT_TUI_CONFIG } =\n await import(\"./tui-config.js\");\n const path = findTuiConfigPath() ?? defaultTuiConfigPath();\n const { existsSync } = await import(\"node:fs\");\n if (!existsSync(path)) {\n writeTuiConfig(DEFAULT_TUI_CONFIG, path);\n log(`created ${path}`, \"ok\");\n }\n const editor = process.env.EDITOR ?? \"vi\";\n const { spawn } = await import(\"node:child_process\");\n const child = spawn(editor, [path], { stdio: \"inherit\" });\n await new Promise<void>((resolve, reject) => {\n child.on(\"exit\", (code) =>\n code === 0 ? resolve() : reject(new Error(`editor exited ${code}`)),\n );\n child.on(\"error\", reject);\n });\n });\n\nprogram.action(() => {\n program.outputHelp();\n});\n\n// Only auto-parse when invoked as a script (not when imported from tests).\nconst invokedAsScript = (() => {\n try {\n const entry = process.argv[1];\n if (!entry) return false;\n return import.meta.url === pathToFileURL(realpathSync(entry)).href;\n } catch {\n return false;\n }\n})();\n\nif (invokedAsScript) {\n program.parseAsync(process.argv).catch((error) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n });\n}\n"],"names":["existsSync","dirname","join","spawn"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sources":["../src/mcp-client.ts","../src/cli.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { APP_VERSION } from \"./meta.js\";\n\nexport interface ToolCallResult {\n content?: { type: string; text?: string }[];\n isError?: boolean;\n}\n\nfunction distRoot(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\nexport class LocalMcpClient {\n private proc: ReturnType<typeof spawn>;\n private requestId = 0;\n private pending = new Map<\n number,\n { resolve: (value: unknown) => void; reject: (error: Error) => void }\n >();\n private outBuf = \"\";\n private closed = false;\n\n constructor(private readonly onStderr?: (line: string) => void) {\n const entry = join(distRoot(), \"cli.js\");\n if (!existsSync(entry)) {\n throw new Error(\"dist/cli.js not found. Run `pnpm build` first.\");\n }\n\n this.proc = spawn(process.execPath, [entry, \"mcp\"], {\n cwd: process.cwd(),\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n this.proc.stderr!.on(\"data\", (chunk: Buffer) => {\n this.onStderr?.(chunk.toString(\"utf8\"));\n });\n\n this.proc.stdout!.on(\"data\", (chunk: Buffer) => {\n this.outBuf += chunk.toString(\"utf8\");\n const lines = this.outBuf.split(\"\\n\");\n this.outBuf = lines.pop() ?? \"\";\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const message = JSON.parse(line) as { id?: number };\n if (message.id != null && this.pending.has(message.id)) {\n const pending = this.pending.get(message.id);\n this.pending.delete(message.id);\n pending?.resolve(message);\n }\n } catch {\n // Ignore non-JSON lines on stdout.\n }\n }\n });\n\n // Handle unexpected child exit — reject all pending requests\n this.proc.on(\"exit\", (code) => {\n if (this.closed) return;\n for (const [, p] of this.pending) {\n p.reject(new Error(`MCP child exited unexpectedly with code ${code}`));\n }\n this.pending.clear();\n });\n }\n\n async start(): Promise<void> {\n const response = (await this.call(\"initialize\", {\n protocolVersion: \"2024-11-05\",\n capabilities: {},\n clientInfo: { name: \"imsg\", version: APP_VERSION },\n })) as { result?: unknown };\n\n if (response.result) {\n this.proc.stdin!.write(\n `${JSON.stringify({ jsonrpc: \"2.0\", method: \"notifications/initialized\", params: {} })}\\n`,\n );\n }\n }\n\n async callTool(name: string, args: object, timeoutMs = 30_000): Promise<ToolCallResult> {\n const response = (await this.call(\"tools/call\", { name, arguments: args }, timeoutMs)) as {\n result?: ToolCallResult;\n error?: { message: string };\n };\n if (response.error) {\n throw new Error(response.error.message);\n }\n return response.result ?? {};\n }\n\n async listTools(timeoutMs = 15_000): Promise<{ name: string; description?: string }[]> {\n const response = (await this.call(\"tools/list\", {}, timeoutMs)) as {\n result?: { tools?: { name: string; description?: string }[] };\n error?: { message: string };\n };\n if (response.error) {\n throw new Error(response.error.message);\n }\n return response.result?.tools ?? [];\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n\n // Close stdin to signal the child\n this.proc.stdin!.end();\n\n // Give child 2s to exit gracefully, then force kill\n const killTimer = setTimeout(() => {\n if (!this.proc.killed) {\n this.proc.kill(\"SIGKILL\");\n }\n }, 2000);\n killTimer.unref();\n\n this.proc.on(\"exit\", () => clearTimeout(killTimer));\n this.proc.kill(\"SIGTERM\");\n\n // Reject any remaining pending requests\n for (const [, p] of this.pending) {\n p.reject(new Error(\"MCP client closed\"));\n }\n this.pending.clear();\n }\n\n private call(method: string, params: object, timeoutMs = 15_000): Promise<unknown> {\n return new Promise((resolve, reject) => {\n if (this.closed) {\n reject(new Error(\"MCP client is closed\"));\n return;\n }\n\n const id = ++this.requestId;\n this.pending.set(id, { resolve, reject });\n this.proc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\n const timer = setTimeout(() => {\n if (!this.pending.has(id)) return;\n this.pending.delete(id);\n reject(new Error(`Request timeout after ${timeoutMs}ms.`));\n }, timeoutMs);\n timer.unref(); // Don't prevent process exit\n\n const original = this.pending.get(id);\n if (!original) return;\n this.pending.set(id, {\n resolve: (value) => {\n clearTimeout(timer);\n original.resolve(value);\n },\n reject: (error) => {\n clearTimeout(timer);\n original.reject(error);\n },\n });\n });\n }\n}\n","import { realpathSync } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport { pathToFileURL } from \"node:url\";\nimport { Command } from \"commander\";\nimport { checkLocalAccess, formatAccessReport } from \"./access-check.js\";\nimport { ANALYTIC_INFO, type AnalyticType, IMPLEMENTED_TYPES } from \"./analytics.js\";\nimport { toYaml } from \"./analytics-render.js\";\nimport { LocalMcpClient } from \"./mcp-client.js\";\nimport { APP_VERSION } from \"./meta.js\";\nimport { installShutdownHandlers, registerCleanup } from \"./shutdown.js\";\nimport { looksLikeThreadSlug } from \"./thread-slug.js\";\n\n// ── Colour helpers ─────────────────────────────────────────────────────\n\nconst color = {\n dim: (v: string) => `\\x1b[2m${v}\\x1b[0m`,\n cyan: (v: string) => `\\x1b[36m${v}\\x1b[0m`,\n green: (v: string) => `\\x1b[32m${v}\\x1b[0m`,\n yellow: (v: string) => `\\x1b[33m${v}\\x1b[0m`,\n red: (v: string) => `\\x1b[31m${v}\\x1b[0m`,\n};\n\nfunction log(message: string, style: \"dim\" | \"ok\" | \"warn\" | \"err\" = \"dim\") {\n const fn =\n style === \"ok\"\n ? color.green\n : style === \"warn\"\n ? color.yellow\n : style === \"err\"\n ? color.red\n : color.dim;\n console.log(fn(message));\n}\n\n// ── MCP client helpers ─────────────────────────────────────────────────\n\nasync function withClient<T>(run: (client: LocalMcpClient) => Promise<T>): Promise<T> {\n const client = new LocalMcpClient((line) => process.stderr.write(color.dim(`[server] ${line}`)));\n try {\n await client.start();\n return await run(client);\n } finally {\n client.close();\n }\n}\n\nasync function printToolResult(\n client: LocalMcpClient,\n name: string,\n args: object,\n timeoutMs?: number,\n format?: \"pretty\" | \"json\" | \"yaml\",\n) {\n const result = await client.callTool(name, args, timeoutMs);\n const text = result.content?.[0]?.text ?? JSON.stringify(result, null, 2);\n if (result.isError) throw new Error(text);\n if (format === \"json\" || format === \"yaml\") {\n // Structured output for scripting. Prefer the tool's structuredContent\n // (the machine-readable payload) over the human text block.\n const payload = (result as { structuredContent?: unknown }).structuredContent ?? result;\n console.log(format === \"json\" ? JSON.stringify(payload, null, 2) : toYaml(payload));\n return;\n }\n console.log(text);\n}\n\n/** Resolve a commander --json/--yaml option pair to a format. */\nfunction pickFormat(opts: { json?: boolean; yaml?: boolean }): \"pretty\" | \"json\" | \"yaml\" {\n if (opts.json) return \"json\";\n if (opts.yaml) return \"yaml\";\n return \"pretty\";\n}\n\n/**\n * Parse a `windowDays` CLI/console arg. Absent → fallback. A non-numeric value\n * gives a clear error instead of the cryptic \"Expected number, received null\"\n * that `Number(\"abc\")` → NaN → JSON `null` produced downstream.\n */\nexport function parseWindowDays(value: string | undefined, fallback: number): number {\n if (value === undefined || value === \"\") return fallback;\n const n = Number(value);\n if (!Number.isFinite(n) || n <= 0) {\n throw new Error(`windowDays must be a positive number of days, got \"${value}\".`);\n }\n return n;\n}\n\n// ── Interactive console ────────────────────────────────────────────────\n\nexport function parseConsoleInput(line: string): { cmd: string; args: string[] } {\n const parts: string[] = [];\n let current = \"\";\n let quote: string | null = null;\n\n for (const char of line) {\n if ((char === '\"' || char === \"'\") && quote == null) {\n quote = char;\n continue;\n }\n if (char === quote) {\n quote = null;\n continue;\n }\n if (char === \" \" && quote == null) {\n if (current) {\n parts.push(current);\n current = \"\";\n }\n continue;\n }\n current += char;\n }\n if (current) parts.push(current);\n return { cmd: parts[0]?.toLowerCase() ?? \"\", args: parts.slice(1) };\n}\n\nexport async function runConsoleCommand(\n cmd: string,\n args: string[],\n client: LocalMcpClient,\n): Promise<void> {\n switch (cmd) {\n case \"conversations\":\n case \"list\":\n await printToolResult(client, \"list_conversations\", { limit: Number(args[0] ?? 20) });\n return;\n case \"messages\":\n case \"msg\": {\n const first = args[0];\n const firstIsLimit = first != null && /^\\d+$/.test(first);\n const chatIdentifier = firstIsLimit ? undefined : first;\n const limit = Number(firstIsLimit ? first : (args[1] ?? 20));\n await printToolResult(client, \"get_messages\", {\n ...(chatIdentifier\n ? looksLikeThreadSlug(chatIdentifier)\n ? { threadSlug: chatIdentifier }\n : { chatIdentifier }\n : {}),\n limit,\n });\n return;\n }\n case \"unread\":\n await printToolResult(\n client,\n \"get_unread_messages\",\n args[0] ? { limit: Number(args[0]) } : {},\n );\n return;\n case \"search\":\n if (!args[0]) throw new Error(\"Usage: search <query> [limit]\");\n await printToolResult(client, \"search_messages\", {\n query: args[0],\n limit: Number(args[1] ?? 20),\n });\n return;\n case \"resolve\":\n if (!args[0]) throw new Error(\"Usage: resolve <name-or-phrase> [limit]\");\n await printToolResult(client, \"resolve_conversation\", {\n query: args[0],\n limit: Number(args[1] ?? 10),\n });\n return;\n case \"wait\":\n if (!args[0]) throw new Error(\"Usage: wait <chat> [timeoutSeconds]\");\n await printToolResult(\n client,\n \"wait_for_reply\",\n {\n ...(looksLikeThreadSlug(args[0]) ? { threadSlug: args[0] } : { chatIdentifier: args[0] }),\n timeoutSeconds: Number(args[1] ?? 60),\n pollIntervalSeconds: 5,\n },\n 70_000,\n );\n return;\n case \"send\":\n if (args.length < 2) throw new Error(\"Usage: send <target> <message>\");\n await printToolResult(client, \"send_message\", {\n ...(looksLikeThreadSlug(args[0]) ? { threadSlug: args[0] } : { recipient: args[0] }),\n message: args.slice(1).join(\" \"),\n });\n return;\n case \"contacts\": {\n const verb = args[0];\n if (verb === \"list\" || verb === undefined) {\n await printToolResult(client, \"list_contacts\", {\n limit: Number(args[1] ?? 20),\n offset: Number(args[2] ?? 0),\n });\n } else if (verb === \"search\") {\n if (!args[1]) throw new Error(\"Usage: contacts search <query> [limit]\");\n await printToolResult(client, \"search_contacts\", {\n query: args[1],\n limit: Number(args[2] ?? 20),\n });\n } else if (verb === \"resolve\") {\n if (!args[1]) throw new Error(\"Usage: contacts resolve <handle>\");\n await printToolResult(client, \"resolve_handle\", { handle: args[1] });\n } else if (verb === \"show\") {\n if (!args[1]) throw new Error(\"Usage: contacts show <handle-or-id>\");\n const params = /^\\d+$/.test(args[1]) ? { id: Number(args[1]) } : { handle: args[1] };\n await printToolResult(client, \"get_contact\", params);\n } else {\n throw new Error(`Unknown contacts verb: ${verb}. Use list|search|resolve|show.`);\n }\n return;\n }\n case \"humans\": {\n const verb = args[0];\n if (verb === \"init\") {\n if (!args[1]) throw new Error(\"Usage: humans init <contact|slug|top N>\");\n if (args[1] === \"top\") {\n await printToolResult(client, \"init_human\", { top: Number(args[2] ?? 10) });\n } else if (args[1].includes(\"~\")) {\n await printToolResult(client, \"init_human\", { threadSlug: args[1] });\n } else {\n await printToolResult(client, \"init_human\", { contact: args.slice(1).join(\" \") });\n }\n } else if (verb === \"top\") {\n await printToolResult(client, \"chat_analytics\", {\n type: \"relationship_leaderboard\",\n windowDays: parseWindowDays(args[1], 1825),\n });\n } else {\n // No verb, `help`, or an unknown verb: show usage without leaking\n // \"undefined\" (the old `humans` / `humans help` output).\n const prefix = verb && verb !== \"help\" ? `Unknown humans verb: ${verb}.\\n` : \"\";\n throw new Error(\n `${prefix}Usage:\\n humans init <contact|slug>\\n humans init top [n]\\n humans top [days]`,\n );\n }\n return;\n }\n case \"analytics\":\n case \"stats\": {\n const type = args[0] as AnalyticType | undefined;\n if (!type || !IMPLEMENTED_TYPES.includes(type)) {\n throw new Error(`Usage: analytics <${IMPLEMENTED_TYPES.join(\"|\")}> [windowDays]`);\n }\n // Trailing `json`/`yaml` token picks the output format in the console.\n const fmtArg = args[args.length - 1];\n const format = fmtArg === \"json\" ? \"json\" : fmtArg === \"yaml\" ? \"yaml\" : \"pretty\";\n const windowDays =\n args[1] && /^\\d+$/.test(args[1]) ? Number(args[1]) : ANALYTIC_INFO[type].defaultWindowDays;\n await printToolResult(client, \"chat_analytics\", { type, windowDays }, undefined, format);\n return;\n }\n case \"logs\":\n await printToolResult(client, \"get_logs\", args[0] ? { tail: Number(args[0]) } : {});\n return;\n case \"last-error\":\n case \"lasterror\":\n await printToolResult(client, \"get_last_send_error\", {});\n return;\n case \"tools\":\n for (const tool of await client.listTools()) {\n console.log(`${tool.name}${tool.description ? ` - ${tool.description}` : \"\"}`);\n }\n return;\n case \"raw\":\n if (!args[0]) throw new Error(\"Usage: raw '<json>'\");\n {\n const parsed = JSON.parse(args.join(\" \")) as { name?: string; arguments?: object };\n if (!parsed.name)\n throw new Error('Expected JSON like {\"name\":\"tool_name\",\"arguments\":{...}}.');\n await printToolResult(client, parsed.name, parsed.arguments ?? {});\n }\n return;\n case \"tui\": {\n const { runTui } = await import(\"./tui/index.js\");\n await runTui();\n return;\n }\n case \"help\":\n case \"?\":\n console.log(CONSOLE_HELP);\n return;\n case \"quit\":\n case \"exit\":\n process.exit(0);\n return;\n default:\n throw new Error(`Unknown command: ${cmd}. Type \"help\" for available commands.`);\n }\n}\n\nconst CONSOLE_HELP = `\nAvailable commands:\n conversations [n] List recent conversations (default 20)\n messages [chat] [n] Show recent messages\n unread [n] Show unread messages\n search <query> [n] Search messages\n resolve <name> [n] Resolve a name/phrase to ranked conversations\n wait <chat> [secs] Wait for a reply (default 60s)\n send <target> <msg> Send a message\n contacts [verb] Contacts: list [n] [offset] | search <q> [n] | resolve <handle> | show <handle-or-id>\n humans <verb> Relationship files: init <contact|slug> | init top [n] | top [days]\n analytics <type> [days] [json|yaml]\n Analytics: ${IMPLEMENTED_TYPES.join(\" | \")}\n logs [tail] Show server debug logs\n last-error Show last send failure\n tools List available MCP tools\n raw <json> Send raw JSON-RPC to tools/call\n tui Launch the read-only TUI\n help Show this help\n quit Exit\n`.trim();\n\nasync function runInteractiveConsole(): Promise<void> {\n log(\"Starting local MCP server...\", \"dim\");\n const client = new LocalMcpClient((line) => process.stderr.write(color.dim(`[server] ${line}`)));\n await client.start();\n log(\"Console ready.\\n\", \"ok\");\n // Show the full help text on launch so the user doesn't have to type `help`\n // to discover what's available.\n console.log(CONSOLE_HELP);\n console.log(\"\");\n\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n // Event-driven line loop (not recursive rl.question): each command is async\n // (an MCP round-trip), so lines are queued and processed one at a time. This\n // is what makes piped/scripted input reliable — with recursive rl.question,\n // EOF (\"close\") raced the in-flight await and killed the command before its\n // output printed. Here EOF only exits AFTER the queue has drained.\n const queue: string[] = [];\n let processing = false;\n let closed = false;\n\n const finish = () => {\n client.close();\n process.exit(0);\n };\n\n const drain = async () => {\n if (processing) return;\n processing = true;\n while (queue.length > 0) {\n const line = queue.shift()!;\n const trimmed = line.trim();\n if (!trimmed) continue;\n const { cmd, args } = parseConsoleInput(trimmed);\n try {\n await runConsoleCommand(cmd, args, client);\n } catch (error) {\n log(error instanceof Error ? error.message : String(error), \"err\");\n }\n console.log(\"\");\n }\n processing = false;\n if (closed) finish();\n else rl.prompt();\n };\n\n rl.setPrompt(color.cyan(\"imsg> \"));\n rl.prompt();\n rl.on(\"line\", (line) => {\n queue.push(line);\n void drain();\n });\n // Ctrl-D / EOF (or a piped script running out of lines): exit once any\n // in-flight command and the queue have drained. Without this the MCP server\n // subprocess keeps the event loop alive and the console would hang.\n rl.on(\"close\", () => {\n closed = true;\n if (!processing && queue.length === 0) finish();\n });\n\n installShutdownHandlers();\n registerCleanup(() => client.close());\n}\n\n// ── Export command ─────────────────────────────────────────────────────\n\ninterface ExportOpts {\n format?: string;\n since?: string;\n until?: string;\n output?: string;\n includeAttachments?: boolean;\n attachmentsDir?: string;\n pageSize?: string;\n}\n\nfunction normalizeFormat(raw: string): \"markdown\" | \"csv\" | \"json\" | \"ndjson\" {\n const v = raw.toLowerCase();\n if (v === \"md\" || v === \"markdown\") return \"markdown\";\n if (v === \"csv\") return \"csv\";\n if (v === \"json\") return \"json\";\n if (v === \"ndjson\") return \"ndjson\";\n throw new Error(`Unknown format: ${raw}. Expected md, csv, json, or ndjson.`);\n}\n\nfunction extForFormat(fmt: \"markdown\" | \"csv\" | \"json\" | \"ndjson\"): string {\n return fmt === \"markdown\" ? \"md\" : fmt;\n}\n\nfunction sanitizeForFilename(s: string): string {\n return s.replace(/[^A-Za-z0-9._~-]+/g, \"_\").replace(/^_+|_+$/g, \"\") || \"chat\";\n}\n\nexport async function runExportCommand(target: string, opts: ExportOpts): Promise<void> {\n const { existsSync, mkdirSync, copyFileSync, statSync } = await import(\"node:fs\");\n const { homedir } = await import(\"node:os\");\n const { dirname, join, isAbsolute, resolve } = await import(\"node:path\");\n const { getContactsDbPaths, getImsgDbPath, getSlugsDbPath } = await import(\"./config.js\");\n const { IMessageDB } = await import(\"./imessage-db.js\");\n const { streamExport } = await import(\"./exportStream.js\");\n const { parseUserDate } = await import(\"./tui/dateParse.js\");\n\n const format = normalizeFormat(opts.format ?? \"md\");\n const ext = extForFormat(format);\n\n const pageSize = Number(opts.pageSize ?? \"1000\");\n if (!Number.isFinite(pageSize) || pageSize < 100 || pageSize > 5000) {\n throw new Error(\"--page-size must be between 100 and 5000.\");\n }\n\n const since = opts.since ? parseUserDate(opts.since) : null;\n if (opts.since && !since) throw new Error(`Could not parse --since: ${opts.since}`);\n const until = opts.until ? parseUserDate(opts.until) : null;\n if (opts.until && !until) throw new Error(`Could not parse --until: ${opts.until}`);\n\n const db = new IMessageDB(getImsgDbPath(), getContactsDbPaths(), getSlugsDbPath());\n try {\n // Resolve target → chatIdentifier + display slug for filename\n let chatIdentifier = target;\n let displayHandle = target;\n if (looksLikeThreadSlug(target)) {\n const rec = db.getSlugRecord(target);\n if (!rec) throw new Error(`Unknown thread slug: ${target}`);\n chatIdentifier = rec.chatIdentifier;\n displayHandle = rec.slug;\n }\n\n // Default output path: ~/imsg-export-<sanitized>-<YYYY-MM-DD>.<ext>\n let outputPath: string;\n if (opts.output) {\n outputPath = isAbsolute(opts.output) ? opts.output : resolve(opts.output);\n } else {\n const today = new Date().toISOString().slice(0, 10);\n outputPath = join(\n homedir(),\n `imsg-export-${sanitizeForFilename(displayHandle)}-${today}.${ext}`,\n );\n }\n\n const parent = dirname(outputPath);\n if (!existsSync(parent)) mkdirSync(parent, { recursive: true });\n\n log(`Exporting ${displayHandle} → ${outputPath} (${format})`, \"dim\");\n\n const result = await streamExport({\n db,\n chatIdentifier,\n format,\n outputPath,\n since,\n until,\n pageSize,\n });\n\n let attachmentSummary = \"\";\n if (opts.includeAttachments) {\n const dir = opts.attachmentsDir\n ? isAbsolute(opts.attachmentsDir)\n ? opts.attachmentsDir\n : resolve(opts.attachmentsDir)\n : `${outputPath}.attachments`;\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n\n const filters: Parameters<typeof db.searchAttachments>[0] = {\n chatIdentifier,\n limit: 0,\n };\n if (since) filters.sinceMs = since.getTime();\n if (until) filters.untilMs = until.getTime();\n const attachments = db.searchAttachments(filters);\n\n let copied = 0;\n let totalBytes = 0;\n const seen = new Set<string>();\n for (const a of attachments) {\n if (!a.filename) continue;\n const src = a.filename.replace(/^~/, homedir());\n if (!existsSync(src)) continue;\n const baseName = a.transferName || src.split(\"/\").pop() || `att-${a.rowId}`;\n let destName = `${a.rowId}-${sanitizeForFilename(baseName)}`;\n if (seen.has(destName)) destName = `${a.rowId}-${Date.now()}-${baseName}`;\n seen.add(destName);\n const dest = join(dir, destName);\n try {\n copyFileSync(src, dest);\n copied++;\n totalBytes += statSync(dest).size;\n } catch (err) {\n log(\n ` warn: copy failed for ${src}: ${err instanceof Error ? err.message : String(err)}`,\n \"warn\",\n );\n }\n }\n attachmentSummary = `\\nAttachments: ${copied} file(s), ${(totalBytes / 1024).toFixed(1)} KB → ${dir}`;\n }\n\n log(\n [\n \"\",\n `✓ Exported ${result.count} message(s) to ${result.savedTo}`,\n ` Format: ${format}`,\n ` Range: ${result.oldest?.toISOString() ?? \"(none)\"} → ${result.newest?.toISOString() ?? \"(none)\"}`,\n ` Size: ${(result.sizeBytes / 1024).toFixed(1)} KB${attachmentSummary}`,\n ].join(\"\\n\"),\n \"ok\",\n );\n } finally {\n await db.close();\n }\n}\n\n// ── CLI program (Commander) ────────────────────────────────────────────\n\nconst program = new Command()\n .name(\"imsg\")\n .version(APP_VERSION, \"-v, --version\")\n .description(\"CLI for the imsg-mcp iMessage MCP server\")\n .addHelpText(\n \"after\",\n `\nNotes:\n Use \"imsg doctor\" on a new machine.\n Run the MCP stdio server with \"imsg mcp\".\n Launch the read-only TUI with \"imsg tui\".`,\n );\n\nprogram\n .command(\"mcp\")\n .description(\"Run the MCP stdio server\")\n .action(async () => {\n const { runMcpServer } = await import(\"./index.js\");\n await runMcpServer();\n });\n\nprogram\n .command(\"cli\")\n .alias(\"console\")\n .description(\"Launch interactive console\")\n .action(runInteractiveConsole);\n\nprogram\n .command(\"doctor\")\n .description(\"Check local permissions and database access\")\n .action(async () => {\n const report = await checkLocalAccess();\n console.log(formatAccessReport(report));\n process.exitCode = report.ok ? 0 : 1;\n });\n\nprogram\n .command(\"conversations\")\n .alias(\"list\")\n .description(\"List recent conversations\")\n .argument(\"[limit]\", \"Number of conversations\", \"20\")\n .action(async (limit: string) => {\n await withClient((c) => printToolResult(c, \"list_conversations\", { limit: Number(limit) }));\n });\n\nprogram\n .command(\"messages\")\n .alias(\"msg\")\n .description(\"Show recent messages from a conversation\")\n .argument(\"[chat]\", \"Phone number, email, or thread slug\")\n .argument(\"[limit]\", \"Number of messages\", \"20\")\n .action(async (chat: string | undefined, limit: string) => {\n const firstIsLimit = chat != null && /^\\d+$/.test(chat);\n const chatIdentifier = firstIsLimit ? undefined : chat;\n const finalLimit = Number(firstIsLimit ? chat : limit);\n await withClient((c) =>\n printToolResult(c, \"get_messages\", {\n ...(chatIdentifier\n ? looksLikeThreadSlug(chatIdentifier)\n ? { threadSlug: chatIdentifier }\n : { chatIdentifier }\n : {}),\n limit: finalLimit,\n }),\n );\n });\n\nprogram\n .command(\"unread\")\n .description(\"Show unread messages across all conversations\")\n .argument(\"[limit]\", \"Number of messages\", \"100\")\n .action(async (limit: string) => {\n await withClient((c) => printToolResult(c, \"get_unread_messages\", { limit: Number(limit) }));\n });\n\nprogram\n .command(\"search\")\n .description(\"Search messages by text content\")\n .argument(\"<query>\", \"Search query\")\n .argument(\"[limit]\", \"Number of results\", \"20\")\n .action(async (query: string, limit: string) => {\n await withClient((c) => printToolResult(c, \"search_messages\", { query, limit: Number(limit) }));\n });\n\nprogram\n .command(\"resolve\")\n .description(\"Resolve a free-form name/phrase to ranked conversations (contacts + threads)\")\n .argument(\"<query>\", 'Name or phrase, e.g. \"Selena\"')\n .argument(\"[limit]\", \"Max ranked matches\", \"10\")\n .option(\"--json\", \"Output structured JSON\")\n .option(\"--yaml\", \"Output structured YAML\")\n .action(async (query: string, limit: string, opts: { json?: boolean; yaml?: boolean }) => {\n await withClient((c) =>\n printToolResult(\n c,\n \"resolve_conversation\",\n { query, limit: Number(limit) },\n undefined,\n pickFormat(opts),\n ),\n );\n });\n\nprogram\n .command(\"wait\")\n .description(\"Wait for a reply in a conversation\")\n .argument(\"<chat>\", \"Phone number, email, or thread slug\")\n .argument(\"[timeout]\", \"Timeout in seconds\", \"60\")\n .action(async (chat: string, timeout: string) => {\n await withClient((c) =>\n printToolResult(\n c,\n \"wait_for_reply\",\n {\n ...(looksLikeThreadSlug(chat) ? { threadSlug: chat } : { chatIdentifier: chat }),\n timeoutSeconds: Number(timeout),\n pollIntervalSeconds: 5,\n },\n 70_000,\n ),\n );\n });\n\nprogram\n .command(\"send\")\n .description(\"Send a message via Messages.app\")\n .argument(\n \"<target>\",\n \"Recipient: thread slug, E.164 phone (+61401990797), local phone (0401 990 797), iMessage email, or contact name\",\n )\n .argument(\"<message...>\", \"Message text\")\n .action(async (target: string, messageParts: string[]) => {\n await withClient((c) =>\n printToolResult(c, \"send_message\", {\n ...(looksLikeThreadSlug(target) ? { threadSlug: target } : { recipient: target }),\n message: messageParts.join(\" \"),\n }),\n );\n });\n\nconst contactsCommand = program\n .command(\"contacts\")\n .description(\"Search and inspect macOS contacts (read-only)\");\n\ncontactsCommand\n .command(\"list\")\n .description(\"List contacts, sorted by name\")\n .argument(\"[limit]\", \"Number of contacts\", \"20\")\n .argument(\"[offset]\", \"Skip this many (pagination)\", \"0\")\n .action(async (limit: string, offset: string) => {\n await withClient((c) =>\n printToolResult(c, \"list_contacts\", { limit: Number(limit), offset: Number(offset) }),\n );\n });\n\ncontactsCommand\n .command(\"search\")\n .description(\"Search contacts by name, phone, or email\")\n .argument(\"<query>\", \"Substring to match\")\n .argument(\"[limit]\", \"Number of results\", \"20\")\n .action(async (query: string, limit: string) => {\n await withClient((c) => printToolResult(c, \"search_contacts\", { query, limit: Number(limit) }));\n });\n\ncontactsCommand\n .command(\"resolve\")\n .description(\"Resolve a phone number or email to its contact name\")\n .argument(\"<handle>\", \"Phone number or email\")\n .action(async (handle: string) => {\n await withClient((c) => printToolResult(c, \"resolve_handle\", { handle }));\n });\n\ncontactsCommand\n .command(\"show\")\n .description(\"Show a contact's handles and the thread slug for each\")\n .argument(\"<handleOrId>\", \"Phone, email, or numeric contact id\")\n .action(async (handleOrId: string) => {\n const args = /^\\d+$/.test(handleOrId) ? { id: Number(handleOrId) } : { handle: handleOrId };\n await withClient((c) => printToolResult(c, \"get_contact\", args));\n });\n\nconst humansCommand = program\n .command(\"humans\")\n .description(\"Scaffold humans/v1 relationship files (~/.agents/humans) — see the humans skill\");\n\nhumansCommand\n .command(\"init\")\n .description(\n \"Scaffold a relationship file for a contact/slug, or --top N for your top relationships\",\n )\n .argument(\"[contact]\", \"Contact name, phone, email, or thread slug\")\n .option(\"--top <n>\", \"Scaffold the top N relationships (by the relationship leaderboard)\")\n .action(async (contact: string | undefined, opts: { top?: string }) => {\n if (!contact && !opts.top) {\n console.error(\"Provide a contact/slug or --top N.\");\n process.exitCode = 1;\n return;\n }\n const args = opts.top\n ? { top: Number(opts.top) }\n : contact?.includes(\"~\")\n ? { threadSlug: contact }\n : { contact };\n await withClient((c) => printToolResult(c, \"init_human\", args));\n });\n\nhumansCommand\n .command(\"top\")\n .description(\"Show the relationship leaderboard (volume × reciprocity × recency, last 5 years)\")\n .argument(\"[windowDays]\", \"Days of history to rank\", \"1825\")\n .option(\"--json\", \"Output structured JSON\")\n .option(\"--yaml\", \"Output structured YAML\")\n .action(async (windowDays: string, opts: { json?: boolean; yaml?: boolean }) => {\n await withClient((c) =>\n printToolResult(\n c,\n \"chat_analytics\",\n { type: \"relationship_leaderboard\", windowDays: parseWindowDays(windowDays, 1825) },\n undefined,\n pickFormat(opts),\n ),\n );\n });\n\n// `imsg analytics <type> [windowDays] [--json|--yaml]` — every implemented\n// analytic, not just the leaderboard. Each type gets its own subcommand so\n// `--help` and shell completion enumerate them.\nconst analyticsCommand = program\n .command(\"analytics\")\n .alias(\"stats\")\n .description(\"Run chat analytics (streaks, response times, heatmap, tapbacks, wrapped, …)\");\n\nfor (const type of IMPLEMENTED_TYPES) {\n const info = ANALYTIC_INFO[type];\n analyticsCommand\n .command(type)\n .description(info.description)\n .argument(\"[windowDays]\", \"Days of history to analyze\", String(info.defaultWindowDays))\n .option(\"--json\", \"Output structured JSON\")\n .option(\"--yaml\", \"Output structured YAML\")\n .action(async (windowDays: string, opts: { json?: boolean; yaml?: boolean }) => {\n await withClient((c) =>\n printToolResult(\n c,\n \"chat_analytics\",\n { type, windowDays: parseWindowDays(windowDays, info.defaultWindowDays) },\n undefined,\n pickFormat(opts),\n ),\n );\n });\n}\n\nprogram\n .command(\"logs\")\n .description(\"Show server debug logs\")\n .argument(\"[tail]\", \"Show only last N lines\")\n .action(async (tail: string | undefined) => {\n await withClient((c) => printToolResult(c, \"get_logs\", tail ? { tail: Number(tail) } : {}));\n });\n\nprogram\n .command(\"last-error\")\n .description(\"Show last send_message failure details\")\n .action(async () => {\n await withClient((c) => printToolResult(c, \"get_last_send_error\", {}));\n });\n\nprogram\n .command(\"tools\")\n .description(\"List available MCP tools\")\n .action(async () => {\n await withClient(async (c) => {\n for (const tool of await c.listTools()) {\n console.log(`${tool.name}${tool.description ? ` - ${tool.description}` : \"\"}`);\n }\n });\n });\n\nprogram\n .command(\"raw\")\n .description(\"Send raw JSON-RPC params to tools/call\")\n .argument(\"<json>\", 'JSON like {\"name\":\"tool_name\",\"arguments\":{...}}')\n .action(async (json: string) => {\n const parsed = JSON.parse(json) as { name?: string; arguments?: object };\n if (!parsed.name) throw new Error('Expected JSON like {\"name\":\"tool_name\",\"arguments\":{...}}.');\n await withClient((c) => printToolResult(c, parsed.name!, parsed.arguments ?? {}));\n });\n\nprogram\n .command(\"tui\")\n .description(\"Launch the read-only terminal UI\")\n .option(\"--theme <theme>\", 'TUI theme: \"safe\" or \"powerline\"')\n .option(\"--accent <hex>\", \"TUI accent color as #RRGGBB\")\n .action(async () => {\n const { runTui } = await import(\"./tui/index.js\");\n await runTui();\n });\n\n// ── Export ───────────────────────────────────────────────────────────────\n\nprogram\n .command(\"export <target>\")\n .description(\"Export a conversation to a file (md/csv/json/ndjson)\")\n .option(\"-f, --format <fmt>\", \"Output format: md (default), csv, json, ndjson\", \"md\")\n .option(\"--since <date>\", \"Earliest date (ISO or relative, e.g. '3 months ago')\")\n .option(\"--until <date>\", \"Latest date (ISO or relative)\")\n .option(\"-o, --output <path>\", \"Output path (default: ~/imsg-export-<target>-<YYYY-MM-DD>.<ext>)\")\n .option(\"--include-attachments\", \"Copy attachments next to the export\")\n .option(\"--attachments-dir <path>\", \"Where to copy attachments (default: <output>.attachments/)\")\n .option(\"--page-size <n>\", \"Messages per DB page (100-5000)\", \"1000\")\n .action(runExportCommand);\n\n// ── Setup ────────────────────────────────────────────────────────────────\n\nprogram\n .command(\"setup\")\n .description(\"Autodetect DB paths and emit an MCP host config snippet\")\n .option(\"-w, --write <host>\", 'Write into a host config: \"claude\" or \"cursor\"')\n .option(\"-r, --runtime <runtime>\", 'Runtime command: \"npx\" (default), \"bunx\", or \"global\"')\n .option(\"--print-only\", \"Just print the snippet (default behaviour)\")\n .action(async (opts: { write?: string; runtime?: string; printOnly?: boolean }) => {\n const { probeMachine, buildMcpSnippet, writeHostConfig } = await import(\"./setup.js\");\n const report = probeMachine();\n\n if (!report.imsgDb.readable) {\n log(`✗ Messages DB is not readable: ${report.imsgDb.path}`, \"err\");\n log(` ${report.imsgDb.error ?? \"\"}`, \"err\");\n log(\n \" Grant Full Disk Access to the running app: System Settings → Privacy & Security → Full Disk Access\",\n \"warn\",\n );\n process.exitCode = 1;\n return;\n }\n\n log(`✓ Messages DB readable: ${report.imsgDb.path}`, \"ok\");\n log(\n `✓ Address Book: ${report.contactsDbs.length} source(s), ${report.contactsDbs.filter((p) => p.readable).length} readable`,\n \"ok\",\n );\n log(\n ` slugs.db: ${report.slugsDb.path} ${report.slugsDb.exists ? \"(exists)\" : \"(will be created on first run)\"}`,\n );\n\n const runtime = opts.runtime === \"bunx\" || opts.runtime === \"global\" ? opts.runtime : \"npx\";\n const snippet = buildMcpSnippet(report, { runtime });\n\n if (opts.write) {\n if (opts.write !== \"claude\" && opts.write !== \"cursor\") {\n log(`✗ unknown host: ${opts.write} (expected \"claude\" or \"cursor\")`, \"err\");\n process.exitCode = 1;\n return;\n }\n const result = writeHostConfig(opts.write, report, { runtime });\n log(\n `✓ wrote ${opts.write} config to ${result.path}${result.replaced ? \" (replaced existing imessage entry)\" : \"\"}`,\n \"ok\",\n );\n log(` backup of any prior file at ${result.path}.bak`);\n return;\n }\n\n log(\"--- snippet ---\", \"dim\");\n process.stdout.write(snippet);\n });\n\n// ── Config ───────────────────────────────────────────────────────────────\n\nconst configCmd = program\n .command(\"config\")\n .description(\"Manage TUI settings (theme, accent color)\");\n\nconfigCmd\n .command(\"show\")\n .description(\"Print resolved TUI settings and where each value came from\")\n .action(async () => {\n const { resolveTuiConfig, defaultTuiConfigPath } = await import(\"./tui-config.js\");\n const cfg = resolveTuiConfig();\n log(\n `config file : ${cfg.configPath ?? `(none — defaults; would write to ${defaultTuiConfigPath()})`}`,\n );\n log(`theme : ${cfg.theme} (from ${cfg.origin.theme})`);\n log(`accentColor : ${cfg.accentColor} (from ${cfg.origin.accentColor})`);\n if (cfg.theme === \"powerline\") {\n log(\" — powerline theme requires a Nerd Font (https://www.nerdfonts.com)\", \"warn\");\n }\n for (const w of cfg.warnings) log(w, \"warn\");\n });\n\nconfigCmd\n .command(\"edit\")\n .description(\"Open the TUI config file in $EDITOR (creates it if missing)\")\n .action(async () => {\n const { defaultTuiConfigPath, findTuiConfigPath, writeTuiConfig, DEFAULT_TUI_CONFIG } =\n await import(\"./tui-config.js\");\n const path = findTuiConfigPath() ?? defaultTuiConfigPath();\n const { existsSync } = await import(\"node:fs\");\n if (!existsSync(path)) {\n writeTuiConfig(DEFAULT_TUI_CONFIG, path);\n log(`created ${path}`, \"ok\");\n }\n const editor = process.env.EDITOR ?? \"vi\";\n const { spawn } = await import(\"node:child_process\");\n const child = spawn(editor, [path], { stdio: \"inherit\" });\n await new Promise<void>((resolve, reject) => {\n child.on(\"exit\", (code) =>\n code === 0 ? resolve() : reject(new Error(`editor exited ${code}`)),\n );\n child.on(\"error\", reject);\n });\n });\n\nprogram.action(() => {\n program.outputHelp();\n});\n\n// Only auto-parse when invoked as a script (not when imported from tests).\nconst invokedAsScript = (() => {\n try {\n const entry = process.argv[1];\n if (!entry) return false;\n return import.meta.url === pathToFileURL(realpathSync(entry)).href;\n } catch {\n return false;\n }\n})();\n\nif (invokedAsScript) {\n program.parseAsync(process.argv).catch((error) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n });\n}\n"],"names":["existsSync","dirname","join","spawn"],"mappings":"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"}