@agentcomms/whatsapp 0.12.1 → 0.12.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.
package/dist/cli.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { $ as renderPrune, A as CommsError, B as colorEnabled, C as checkStorePath, F as approvalsOf, G as installExitStatus, H as escapeForDisplay, I as approveChangeAtTerminal, J as nameAvailable, K as isCommsError, L as canPrompt, M as absoluteSearchPath, N as agentMarker, O as CHANNELS, P as approvalKind, Q as renderInstall, R as channelManifest, S as storeIdentity, T as expandSource, U as exemptFromUpdateGate, V as commandPathOf, W as gatedChangeAtTerminal, X as openCore, Y as nameShapeProblem, Z as paint, _ as chatRefOf, a as listChats, at as updateGateAtTerminal, b as requireAccount, c as Presenter, ct as withFileLock, d as draftMessage, et as runCommand, f as Visibility, g as requireSupportedNode, h as WhatsAppIndex, i as CHAT_KINDS, it as truncateDisplay, j as EXIT_CODES, k as CHANNEL_SERVERS, l as innerText, lt as writeResult, m as WhatsAppContext, n as whatsappStatus, nt as serverPruneChange, o as readChat, p as listKey, q as lookupName, r as probeStore, s as searchMessages, st as windowsSystemProgram, t as syncAccount, tt as serverInstallChange, ut as VERSION, v as PLATFORM, w as defaultStorePath, x as requireNamedConfig, y as newWhatsAppAccount, z as childEnvironment } from "./sync-BiO86eEl.mjs";
2
+ import { $ as paint, A as CommsError, B as colorEnabled, C as checkStorePath, F as approvalsOf, G as gatedChangeAtTerminal, H as commandText, I as approveChangeAtTerminal, J as isCommsError, K as inlineCommand, L as canPrompt, M as absoluteSearchPath, N as agentMarker, O as CHANNELS, P as approvalKind, Q as openCore, R as channelManifest, S as storeIdentity, T as expandSource, U as escapeForDisplay, V as commandPathOf, W as exemptFromUpdateGate, X as nameAvailable, Y as lookupName, Z as nameShapeProblem, _ as chatRefOf, a as listChats, at as shellCommand, b as requireAccount, c as Presenter, ct as updateGateAtTerminal, d as draftMessage, dt as withFileLock, et as renderInstall, f as Visibility, ft as writeResult, g as requireSupportedNode, h as WhatsAppIndex, i as CHAT_KINDS, it as serverPruneChange, j as EXIT_CODES, k as CHANNEL_SERVERS, l as innerText, m as WhatsAppContext, n as whatsappStatus, nt as runCommand, o as readChat, p as listKey, pt as VERSION, q as installExitStatus, r as probeStore, rt as serverInstallChange, s as searchMessages, st as truncateDisplay, t as syncAccount, tt as renderPrune, ut as windowsSystemProgram, v as PLATFORM, w as defaultStorePath, x as requireNamedConfig, y as newWhatsAppAccount, z as childEnvironment } from "./sync-DJlsr6xq.mjs";
3
3
  import { rm } from "node:fs/promises";
4
4
  import path, { delimiter, join } from "node:path";
5
+ import { stripVTControlCharacters } from "node:util";
5
6
  import fs, { accessSync, constants as constants$1 } from "node:fs";
6
7
  import childProcess, { spawn } from "node:child_process";
7
- import { stripVTControlCharacters } from "node:util";
8
8
  import process$1 from "node:process";
9
9
  import { EventEmitter } from "node:events";
10
10
  //#region ../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
@@ -2994,12 +2994,17 @@ const WHATSAPP_MCP = {
2994
2994
  function refuseAnAgent(context, command, what) {
2995
2995
  const marker = agentMarker(context.env);
2996
2996
  if (marker !== null || context.surface !== "cli") throw new CommsError("LOOSENING_REFUSED", `only a person ${what}`, {
2997
- hint: `Ask the person to run \`agent-whatsapp ${command}\` in their own terminal.`,
2997
+ hint: `Ask the person to run ${inlineCommand(command)} in their own terminal.`,
2998
2998
  ...marker === null ? {} : { details: { marker } }
2999
2999
  });
3000
3000
  }
3001
3001
  async function addAccount(context, request) {
3002
- refuseAnAgent(context, `add ${request.name}`, "chooses which WhatsApp store an agent may read");
3002
+ refuseAnAgent(context, shellCommand([
3003
+ "agent-whatsapp",
3004
+ "add",
3005
+ request.name,
3006
+ ...request.source === void 0 ? [] : ["--source", request.source]
3007
+ ], context.platform), "chooses which WhatsApp store an agent may read");
3003
3008
  const problem = nameShapeProblem(request.name, PLATFORM);
3004
3009
  if (problem) throw new CommsError("USAGE", problem);
3005
3010
  const isDefault = request.source === void 0;
@@ -3013,7 +3018,11 @@ async function addAccount(context, request) {
3013
3018
  const refuseTaken = (config) => {
3014
3019
  requireNamedConfig(config);
3015
3020
  const free = nameAvailable(config, "account", request.name, PLATFORM);
3016
- if (!free.ok) throw lookupName(config, "account", request.name)?.platform === "whatsapp" ? new CommsError("USAGE", `"${request.name}" is already added`, { hint: `Remove it first with \`agent-whatsapp remove ${request.name}\` to point it at another store.` }) : free.error;
3021
+ if (!free.ok) throw lookupName(config, "account", request.name)?.platform === "whatsapp" ? new CommsError("USAGE", `"${request.name}" is already added`, { hint: `Remove it first with ${inlineCommand(shellCommand([
3022
+ "agent-whatsapp",
3023
+ "remove",
3024
+ request.name
3025
+ ], context.platform))} to point it at another store.` }) : free.error;
3017
3026
  for (const [name, other] of Object.entries(config.accounts)) {
3018
3027
  if (other.platform !== "whatsapp") continue;
3019
3028
  if (context.storeOf(other).path === path || other.workspace === identity.workspace) throw new CommsError("USAGE", `that store is already added, as "${name}"`, { hint: "One name per message store." });
@@ -3043,7 +3052,12 @@ async function addAccount(context, request) {
3043
3052
  default: isDefault,
3044
3053
  id: account.workspace
3045
3054
  },
3046
- next: `agent-whatsapp sync --account ${request.name}`
3055
+ next: commandText(shellCommand([
3056
+ "agent-whatsapp",
3057
+ "sync",
3058
+ "--account",
3059
+ request.name
3060
+ ], context.platform))
3047
3061
  };
3048
3062
  }
3049
3063
  /**
@@ -3052,8 +3066,12 @@ async function addAccount(context, request) {
3052
3066
  */
3053
3067
  const REMOVE_WAIT_MS = 6e4;
3054
3068
  async function removeAccount(context, request) {
3055
- refuseAnAgent(context, `remove ${request.name}`, "removes a WhatsApp account");
3056
- const { account } = requireAccount(await context.config(), request.name);
3069
+ refuseAnAgent(context, shellCommand([
3070
+ "agent-whatsapp",
3071
+ "remove",
3072
+ request.name
3073
+ ], context.platform), "removes a WhatsApp account");
3074
+ const { account } = requireAccount(await context.config(), request.name, context.platform);
3057
3075
  await withFileLock(context.syncLock(account), async () => {
3058
3076
  await context.core.config.update((config) => {
3059
3077
  if (lookupName(config, "account", request.name)?.id !== account.id) throw new CommsError("TRANSIENT", `"${request.name}" changed while it was being removed`, { hint: "Nothing was removed. Run it again." });
@@ -3097,7 +3115,7 @@ function effectOf(lists) {
3097
3115
  async function named(context, name, account, chatId) {
3098
3116
  let index;
3099
3117
  try {
3100
- index = await WhatsAppIndex.open(context.accountDir(account), name, new Visibility(void 0));
3118
+ index = await WhatsAppIndex.open(context.accountDir(account), name, new Visibility(void 0), context.platform);
3101
3119
  } catch (error) {
3102
3120
  if (!isCommsError(error) || error.details?.reason !== "NOT_SYNCED") throw error;
3103
3121
  return {
@@ -3118,7 +3136,12 @@ async function named(context, name, account, chatId) {
3118
3136
  }
3119
3137
  /** The one path every list change takes: the person check first, before any input is read. */
3120
3138
  async function change(context, command, request, next) {
3121
- refuseAnAgent(context, command, "changes which chats an agent may see");
3139
+ refuseAnAgent(context, shellCommand([
3140
+ "agent-whatsapp",
3141
+ command,
3142
+ ...request.chat === void 0 ? [] : [request.chat],
3143
+ ...request.account === void 0 ? [] : ["--account", request.account]
3144
+ ], context.platform), "changes which chats an agent may see");
3122
3145
  const chatId = request.chat === void 0 ? void 0 : chatRefOf(request.chat, { international: true }).id;
3123
3146
  const { name, account } = await context.account(request.account);
3124
3147
  const { before, after } = await context.lists.update(account.id, (lists) => next(lists, chatId));
@@ -3128,7 +3151,12 @@ async function change(context, command, request, next) {
3128
3151
  deny: [...after.deny],
3129
3152
  changed: JSON.stringify(before) !== JSON.stringify(after),
3130
3153
  effect: effectOf(after),
3131
- next: `agent-whatsapp sync --account ${name}`,
3154
+ next: commandText(shellCommand([
3155
+ "agent-whatsapp",
3156
+ "sync",
3157
+ "--account",
3158
+ name
3159
+ ], context.platform)),
3132
3160
  ...chatId === void 0 ? {} : await named(context, name, account, chatId)
3133
3161
  };
3134
3162
  }
@@ -3215,7 +3243,7 @@ function renderAdded(result, color) {
3215
3243
  function renderRemoved(result, color) {
3216
3244
  return `${paint(color, "green", "Removed")} ${result.account}, and its local index. WhatsApp's own store was not touched.`;
3217
3245
  }
3218
- function renderStatus(result, color) {
3246
+ function renderStatus(result, color, platform = process.platform) {
3219
3247
  const lines = [];
3220
3248
  if (result.accounts.length === 0) lines.push(`No WhatsApp account yet. ${result.setup ?? ""}`);
3221
3249
  for (const account of result.accounts) {
@@ -3229,7 +3257,12 @@ function renderStatus(result, color) {
3229
3257
  lines.push(` index ${account.index.chats} chats, ${account.index.messages} messages, ${account.index.media} with media, ${account.index.statusChats} status-update chat(s) · synced ${account.index.indexedAt}`);
3230
3258
  if (account.index.unattributedStatus > 0) lines.push(` ${unattributed(account.index.unattributedStatus)}`);
3231
3259
  for (const entry of account.index.degraded) lines.push(paint(color, "dim", ` without ${entry.part}: ${entry.costs}`));
3232
- } else lines.push(` index not synced yet — agent-whatsapp sync --account ${account.account}`);
3260
+ } else lines.push(` index not synced yet — ${commandText(shellCommand([
3261
+ "agent-whatsapp",
3262
+ "sync",
3263
+ "--account",
3264
+ account.account
3265
+ ], platform))}`);
3233
3266
  }
3234
3267
  lines.push("", paint(color, "dim", `Reads: ${result.reads}.`), paint(color, "dim", `Sends: ${result.sends}.`));
3235
3268
  return lines.join("\n");
@@ -3338,6 +3371,7 @@ async function run(argv, deps = {}) {
3338
3371
  stdin: process.stdin
3339
3372
  };
3340
3373
  const env = deps.env ?? process.env;
3374
+ const platform = deps.platform ?? process.platform;
3341
3375
  const open = deps.open ?? openLink;
3342
3376
  const program = new Command();
3343
3377
  let exitCode = 0;
@@ -3365,7 +3399,8 @@ a macOS dialog may be waiting) · 77 permission needed (macOS privacy) · 78 con
3365
3399
  const options = program.opts();
3366
3400
  return {
3367
3401
  json: Boolean(options.json),
3368
- color: colorEnabled(env, streams.stdout, options.color)
3402
+ color: colorEnabled(env, streams.stdout, options.color),
3403
+ platform
3369
3404
  };
3370
3405
  };
3371
3406
  /**
@@ -3451,7 +3486,7 @@ a macOS dialog may be waiting) · 77 permission needed (macOS privacy) · 78 con
3451
3486
  account: flags.account === void 0 ? void 0 : String(flags.account),
3452
3487
  check: flags.check !== false
3453
3488
  });
3454
- writeResult(result, options, () => renderStatus(result, options.color), streams);
3489
+ writeResult(result, options, () => renderStatus(result, options.color, context.platform), streams);
3455
3490
  }));
3456
3491
  accountOption(program.command("sync")).description("copy WhatsApp's store privately, check it, and rebuild the local index from the copy").action(act(async (context, options, flags) => {
3457
3492
  const result = await syncAccount(context, { account: String(flags.account) });
@@ -3509,16 +3544,25 @@ a macOS dialog may be waiting) · 77 permission needed (macOS privacy) · 78 con
3509
3544
  program.command("approve <approvalId>").description("approve a change at this terminal — registering or pruning this server — by reading it and typing the code back; WhatsApp never sends, so there is no message to approve").action(act(async (context, options, approvalId) => {
3510
3545
  const marker = agentMarker(env);
3511
3546
  if (marker) throw new CommsError("APPROVAL_REQUIRED", "only a person can approve a change, not an agent", {
3512
- hint: `Ask the person to run \`agent-whatsapp approve ${approvalId}\` in their own terminal.`,
3547
+ hint: `Ask the person to run ${inlineCommand(shellCommand([
3548
+ "agent-whatsapp",
3549
+ "approve",
3550
+ approvalId
3551
+ ], context.platform))} in their own terminal.`,
3513
3552
  details: { marker }
3514
3553
  });
3515
- if (!canPrompt(env, streams, { json: options.json })) throw new CommsError("APPROVAL_REQUIRED", "approving a change needs an interactive terminal", { hint: `Run \`agent-whatsapp approve ${approvalId}\` directly in a terminal.` });
3554
+ if (!canPrompt(env, streams, { json: options.json })) throw new CommsError("APPROVAL_REQUIRED", "approving a change needs an interactive terminal", { hint: `Run ${inlineCommand(shellCommand([
3555
+ "agent-whatsapp",
3556
+ "approve",
3557
+ approvalId
3558
+ ], context.platform))} directly in a terminal.` });
3516
3559
  const pending = await context.core.approvals.get(approvalId);
3517
3560
  if (!pending) throw new CommsError("NOT_FOUND", `no approval ${approvalId}`, { hint: "It may have expired, been used, or been cancelled. Prepare the change again." });
3518
3561
  if (approvalKind(pending) !== "change") throw new CommsError("USAGE", `approval ${approvalId} is for a send, and WhatsApp never sends`, { hint: `Approve it with the command that prepared it — ${sendApproveCommands()} — not this one.` });
3519
3562
  const outcome = await approveChangeAtTerminal(context.core, approvalId, env, {
3520
3563
  json: options.json,
3521
- color: options.color
3564
+ color: options.color,
3565
+ platform: context.platform
3522
3566
  }, streams);
3523
3567
  streams.stdout.write(outcome.state === "approved" ? "Approved. This command approves; the change is applied by the command that prepared it.\n" : "Cancelled. Nothing was changed.\n");
3524
3568
  }));
@@ -3534,9 +3578,9 @@ a macOS dialog may be waiting) · 77 permission needed (macOS privacy) · 78 con
3534
3578
  ran = true;
3535
3579
  exitCode = await runCommand(output(), async () => {
3536
3580
  requireSupportedNode();
3537
- const { startWhatsAppStdioServer } = await import("./stdio-entry-BznXKJaK.mjs");
3538
- await startWhatsAppStdioServer({
3581
+ await (deps.startMcp ?? (await import("./stdio-entry-CAM7LpPv.mjs")).startWhatsAppStdioServer)({
3539
3582
  env,
3583
+ platform,
3540
3584
  ...flags.account ? { account: String(flags.account) } : {}
3541
3585
  });
3542
3586
  }, streams);
@@ -3559,7 +3603,7 @@ a macOS dialog may be waiting) · 77 permission needed (macOS privacy) · 78 con
3559
3603
  const launcher = flags.launcher;
3560
3604
  const name = flags.name;
3561
3605
  await context.migration();
3562
- const again = [
3606
+ const again = shellCommand([
3563
3607
  "agent-whatsapp",
3564
3608
  "mcp",
3565
3609
  "install",
@@ -3570,7 +3614,7 @@ a macOS dialog may be waiting) · 77 permission needed (macOS privacy) · 78 con
3570
3614
  ...launcher !== void 0 ? ["--launcher", launcher] : [],
3571
3615
  ...flags.verify === false ? ["--no-verify"] : [],
3572
3616
  ...flags.force === true ? ["--force"] : []
3573
- ].join(" ");
3617
+ ], context.platform);
3574
3618
  const result = await changeAt(context, serverInstallChange(context.core, env, {
3575
3619
  channel: "whatsapp",
3576
3620
  client: flags.client,
@@ -3590,7 +3634,12 @@ a macOS dialog may be waiting) · 77 permission needed (macOS privacy) · 78 con
3590
3634
  channel: "whatsapp",
3591
3635
  dryRun: flags.dryRun === true,
3592
3636
  includePrinted: flags.includePrinted === true
3593
- }, WHATSAPP_MCP), flags, `agent-whatsapp mcp prune${flags.includePrinted === true ? " --include-printed" : ""}`);
3637
+ }, WHATSAPP_MCP), flags, shellCommand([
3638
+ "agent-whatsapp",
3639
+ "mcp",
3640
+ "prune",
3641
+ ...flags.includePrinted === true ? ["--include-printed"] : []
3642
+ ], context.platform));
3594
3643
  writeResult(result, output(), () => renderPrune(result, options.color), streams);
3595
3644
  }));
3596
3645
  try {
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { u as composeDraft, ut as VERSION } from "./sync-BiO86eEl.mjs";
2
- import { t as createWhatsAppMcpServer } from "./server-BHwKQeXq.mjs";
1
+ import { pt as VERSION, u as composeDraft } from "./sync-DJlsr6xq.mjs";
2
+ import { t as createWhatsAppMcpServer } from "./server-B1EmZ6FZ.mjs";
3
3
  //#region src/index.ts
4
4
  /**
5
5
  * The library entry of `@agentcomms/whatsapp`.
@@ -1,4 +1,4 @@
1
- import { D as strictToolArguments, E as UNTRUSTED_NOTICE, a as listChats, d as draftMessage, i as CHAT_KINDS, m as WhatsAppContext, n as whatsappStatus, o as readChat, ot as updateToolGate, rt as toCommsError, s as searchMessages, t as syncAccount, ut as VERSION } from "./sync-BiO86eEl.mjs";
1
+ import { D as strictToolArguments, E as UNTRUSTED_NOTICE, a as listChats, d as draftMessage, i as CHAT_KINDS, lt as updateToolGate, m as WhatsAppContext, n as whatsappStatus, o as readChat, ot as toCommsError, pt as VERSION, s as searchMessages, t as syncAccount } from "./sync-DJlsr6xq.mjs";
2
2
  import { c as boolean, h as number, x as string } from "./schemas-DiGKNDNq.mjs";
3
3
  import { t as McpServer } from "./mcp-DXXb3Vv3-Co5BzjYe.mjs";
4
4
  //#region src/mcp/server.ts
@@ -1,4 +1,4 @@
1
- import { t as createWhatsAppMcpServer } from "./server-BHwKQeXq.mjs";
1
+ import { t as createWhatsAppMcpServer } from "./server-B1EmZ6FZ.mjs";
2
2
  //#region src/mcp/stdio-entry.ts
3
3
  /**
4
4
  * Starting the stdio server. On stdio, stdout is the protocol, so the console is redirected to stderr first — the