@agentcomms/resend 0.12.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { $ as installExitStatus, B as agentMarker, C as policyChange, D as sendPolicyOf, E as removeAccountChange, F as CHANNEL_SERVERS, H as approvalsOf, I as CommsError, J as commandPathOf, L as EXIT_CODES, N as checkNewName, O as showAccount, Q as gatedChangeAtTerminal, R as SEND_LOOKUP, S as policyApprovalRefusal, T as policyWanted, U as approveChangeAtTerminal, V as approvalKind, W as canPrompt, X as exemptFromUpdateGate, Y as escapeForDisplay, _ as runDoctor, a as revokeSendApproval, at as runCommand, b as listAccounts, c as downloadReceived, ct as serverPruneChange, d as listReceived, dt as truncateDisplay, et as openCore, f as listScheduled, ft as updateGateAtTerminal, g as showSentEmail, h as showReceived, i as prepareSend, it as renderPrune, k as ResendContext, l as getMetrics, lt as terminalUpdateHooks, m as listSuppressions, mt as writeResult, n as executeSend, nt as refuseUnclaimedApproval, o as sendStatus, ot as runUpdateCheckChild, p as listSentEmails, q as colorEnabled, r as finishSendApproval, rt as renderInstall, s as cancelScheduledChange, st as serverInstallChange, t as beginSendApproval, tt as paint, u as listDomains, v as addAccountChange, w as policyReport, x as modeOf, y as inspectKey, yt as VERSION, z as UPDATE_CHECK_CHILD_COMMAND } from "./send-BlDpMIlS.mjs";
2
+ import { $ as inlineCommand, B as agentMarker, C as policyChange, D as sendPolicyOf, E as removeAccountChange, F as CHANNEL_SERVERS, H as approvalsOf, I as CommsError, J as commandPathOf, L as EXIT_CODES, N as checkNewName, O as showAccount, Q as gatedChangeAtTerminal, R as SEND_LOOKUP, S as policyApprovalRefusal, T as policyWanted, U as approveChangeAtTerminal, V as approvalKind, W as canPrompt, X as exemptFromUpdateGate, Y as escapeForDisplay, _ as runDoctor, a as revokeSendApproval, at as renderPrune, b as listAccounts, c as downloadReceived, ct as serverInstallChange, d as listReceived, dt as terminalUpdateHooks, et as installExitStatus, f as listScheduled, g as showSentEmail, gt as writeResult, h as showReceived, i as prepareSend, it as renderInstall, k as ResendContext, l as getMetrics, lt as serverPruneChange, m as listSuppressions, mt as updateGateAtTerminal, n as executeSend, nt as paint, o as sendStatus, ot as runCommand, p as listSentEmails, pt as truncateDisplay, q as colorEnabled, r as finishSendApproval, rt as refuseUnclaimedApproval, s as cancelScheduledChange, st as runUpdateCheckChild, t as beginSendApproval, tt as openCore, u as listDomains, ut as shellCommand, v as addAccountChange, w as policyReport, x as modeOf, xt as VERSION, y as inspectKey, z as UPDATE_CHECK_CHILD_COMMAND } from "./send-D2ZOWO_6.mjs";
3
3
  import path from "node:path";
4
- import fs from "node:fs";
5
4
  import { createInterface } from "node:readline/promises";
6
5
  import { stripVTControlCharacters } from "node:util";
6
+ import fs from "node:fs";
7
7
  import childProcess from "node:child_process";
8
8
  import process$1 from "node:process";
9
9
  import { EventEmitter } from "node:events";
@@ -3040,12 +3040,12 @@ const KEY_SHAPE = /^re_[A-Za-z0-9_]{8,200}$/;
3040
3040
  async function readApiKey(env, streams, options) {
3041
3041
  const marker = agentMarker(env);
3042
3042
  if (marker) throw new CommsError("AUTH_REQUIRED", "a Resend API key is added by a person at their own terminal, not by an agent", {
3043
- hint: `Ask the user to run \`${options.command}\` in their own terminal. Never paste a key into a chat: the transcript keeps it.`,
3043
+ hint: `Ask the user to run ${inlineCommand(options.command)} in their own terminal. Never paste a key into a chat: the transcript keeps it.`,
3044
3044
  details: { marker }
3045
3045
  });
3046
3046
  let key = env["RESEND_API_KEY"]?.trim() ?? "";
3047
3047
  if (key === "") {
3048
- if (!canPrompt(env, streams, { json: options.json })) throw new CommsError("AUTH_REQUIRED", "a Resend API key is needed, and there is no terminal to ask for it", { hint: `A person runs \`${options.command}\` in a terminal, which asks for the key without showing it, or sets ${KEY_ENV} for that one command.` });
3048
+ if (!canPrompt(env, streams, { json: options.json })) throw new CommsError("AUTH_REQUIRED", "a Resend API key is needed, and there is no terminal to ask for it", { hint: `A person runs ${inlineCommand(options.command)} in a terminal, which asks for the key without showing it, or sets ${KEY_ENV} for that one command.` });
3049
3049
  key = (await askHidden(streams, "Resend API key (https://resend.com/api-keys; it is not shown as you type): ")).trim();
3050
3050
  }
3051
3051
  if (!KEY_SHAPE.test(key)) throw new CommsError("BAD_DATA", "that does not look like a Resend API key (they start with re_)", { hint: "Nothing was stored. Copy the key again from the Resend dashboard." });
@@ -3115,7 +3115,8 @@ function renderPrepared(result) {
3115
3115
  return `${result.preview}\n\nNext: ${escapeForDisplay(result.nextStep)}`;
3116
3116
  }
3117
3117
  function renderSent(result) {
3118
- return result.state === "scheduled" ? `Scheduled for ${result.scheduledAt ?? "?"} as ${result.resendId}, to ${truncateDisplay(result.to.join(", "), 200)}.` : `Sent as ${result.resendId}, to ${truncateDisplay(result.to.join(", "), 200)}.`;
3118
+ const sent = result.state === "scheduled" ? `Scheduled for ${result.scheduledAt ?? "?"} as ${result.resendId}, to ${truncateDisplay(result.to.join(", "), 200)}.` : `Sent as ${result.resendId}, to ${truncateDisplay(result.to.join(", "), 200)}.`;
3119
+ return result.note ? `${sent}\nNote: ${escapeForDisplay(result.note)}.` : sent;
3119
3120
  }
3120
3121
  function renderStatus(result) {
3121
3122
  return `${result.approvalId}: ${escapeForDisplay(result.verdict)}`;
@@ -3144,6 +3145,7 @@ async function run(argv, deps = {}) {
3144
3145
  stdin: process.stdin
3145
3146
  };
3146
3147
  const env = deps.env ?? process.env;
3148
+ const platform = deps.platform ?? process.platform;
3147
3149
  const program = new Command();
3148
3150
  let exitCode = 0;
3149
3151
  let ran = false;
@@ -3173,7 +3175,8 @@ is out: update first, or put it off (agentcomms update, agentcomms update --late
3173
3175
  };
3174
3176
  const output = () => ({
3175
3177
  json: globals().json,
3176
- color: globals().color
3178
+ color: globals().color,
3179
+ platform
3177
3180
  });
3178
3181
  let gated = null;
3179
3182
  program.hook("preAction", async (_program, command) => {
@@ -3236,8 +3239,16 @@ is out: update first, or put it off (agentcomms update, agentcomms update --late
3236
3239
  "never"
3237
3240
  ])).option("--domain <domain>", "for a sending-only key restricted to one domain: that domain")).action(act(async (context, options, name, flags) => {
3238
3241
  const mode = modeOf(flags.mode);
3239
- const command = `agent-resend account add ${name}${mode ? ` --mode ${mode}` : ""}${flags.send ? ` --send ${String(flags.send)}` : ""}${flags.domain ? ` --domain ${String(flags.domain)}` : ""}`;
3240
- checkNewName(await context.config(), name);
3242
+ const command = shellCommand([
3243
+ "agent-resend",
3244
+ "account",
3245
+ "add",
3246
+ name,
3247
+ ...mode ? ["--mode", mode] : [],
3248
+ ...flags.send ? ["--send", String(flags.send)] : [],
3249
+ ...flags.domain ? ["--domain", String(flags.domain)] : []
3250
+ ], platform);
3251
+ checkNewName(await context.config(), name, context.platform);
3241
3252
  const key = await readApiKey(env, streams, {
3242
3253
  json: options.json,
3243
3254
  command
@@ -3261,7 +3272,12 @@ is out: update first, or put it off (agentcomms update, agentcomms update --late
3261
3272
  writeResult(result, output(), (data) => renderAccount(data, options.color), streams);
3262
3273
  }));
3263
3274
  approvalOption(account.command("remove <name>").description("forget an account and delete its key, once a person approves it")).action(act(async (context, _options, name, flags) => {
3264
- const removed = await changeAt(context, removeAccountChange(context, name), flags, `agent-resend account remove ${name}`);
3275
+ const removed = await changeAt(context, removeAccountChange(context, name), flags, shellCommand([
3276
+ "agent-resend",
3277
+ "account",
3278
+ "remove",
3279
+ name
3280
+ ], platform));
3265
3281
  writeResult(removed, output(), renderRemoved, streams);
3266
3282
  }));
3267
3283
  approvalOption(account.command("policy <name>").description("report how its sends and changes are approved, or set --send, --mode and --change; loosening is approved by a person").option("--send <policy>", "chat, confirm or never").option("--mode <mode>", "read or send").option("--change <policy>", "how a loosening of this account is approved: chat or confirm")).action(act(async (context, _options, name, flags) => {
@@ -3272,7 +3288,15 @@ is out: update first, or put it off (agentcomms update, agentcomms update --late
3272
3288
  });
3273
3289
  const reporting = wanted.send === void 0 && wanted.mode === void 0 && wanted.change === void 0;
3274
3290
  if (reporting) refuseUnclaimedApproval(flags.approval, policyApprovalRefusal("cli"));
3275
- const result = reporting ? await policyReport(context, name) : await changeAt(context, policyChange(context, name, wanted), flags, `agent-resend account policy ${name}${wanted.send ? ` --send ${wanted.send}` : ""}${wanted.mode ? ` --mode ${wanted.mode}` : ""}${wanted.change ? ` --change ${wanted.change}` : ""}`);
3291
+ const result = reporting ? await policyReport(context, name) : await changeAt(context, policyChange(context, name, wanted), flags, shellCommand([
3292
+ "agent-resend",
3293
+ "account",
3294
+ "policy",
3295
+ name,
3296
+ ...wanted.send ? ["--send", wanted.send] : [],
3297
+ ...wanted.mode ? ["--mode", wanted.mode] : [],
3298
+ ...wanted.change ? ["--change", wanted.change] : []
3299
+ ], platform));
3276
3300
  writeResult(result, output(), renderPolicy, streams);
3277
3301
  }));
3278
3302
  program.command("doctor").description("check what has to work, and say who enforces what — read-only is this package’s promise, not the key’s").option("--account <name>", "check only this account").option("--offline", "do not ask Resend anything", false).action(act(async (context, options, flags) => {
@@ -3373,21 +3397,37 @@ is out: update first, or put it off (agentcomms update, agentcomms update --late
3373
3397
  writeResult(result, output(), (data) => renderRead(data, options.color), streams);
3374
3398
  }));
3375
3399
  approvalOption(accountOption(scheduled.command("cancel <id>")).description("cancel a scheduled email; one this machine did not schedule is approved by a person first")).action(act(async (context, _options, id, flags) => {
3376
- const cancelled = await changeAt(context, cancelScheduledChange(context, String(flags.account), id), flags, `agent-resend scheduled cancel ${id} --account ${String(flags.account)}`);
3400
+ const cancelled = await changeAt(context, cancelScheduledChange(context, String(flags.account), id), flags, shellCommand([
3401
+ "agent-resend",
3402
+ "scheduled",
3403
+ "cancel",
3404
+ id,
3405
+ "--account",
3406
+ String(flags.account)
3407
+ ], platform));
3377
3408
  writeResult(cancelled, output(), renderCancelled, streams);
3378
3409
  }));
3379
3410
  program.command("approve <approvalId>").description("approve a send or a change at this terminal: read it, then type the code back").action(act(async (context, options, approvalId) => {
3380
3411
  const marker = agentMarker(env);
3381
3412
  if (marker) throw new CommsError("APPROVAL_REQUIRED", "only a person can approve a send or a change, not an agent", {
3382
- hint: `Ask the user to run \`agent-resend approve ${approvalId}\` in their own terminal.`,
3413
+ hint: `Ask the user to run ${inlineCommand(shellCommand([
3414
+ "agent-resend",
3415
+ "approve",
3416
+ approvalId
3417
+ ], context.platform))} in their own terminal.`,
3383
3418
  details: { marker }
3384
3419
  });
3385
- if (!canPrompt(env, streams, { json: options.json })) throw new CommsError("APPROVAL_REQUIRED", "approving needs an interactive terminal", { hint: `Run \`agent-resend approve ${approvalId}\` directly in a terminal.` });
3420
+ if (!canPrompt(env, streams, { json: options.json })) throw new CommsError("APPROVAL_REQUIRED", "approving needs an interactive terminal", { hint: `Run ${inlineCommand(shellCommand([
3421
+ "agent-resend",
3422
+ "approve",
3423
+ approvalId
3424
+ ], context.platform))} directly in a terminal.` });
3386
3425
  const pending = await context.core.approvals.get(approvalId);
3387
3426
  if (pending && approvalKind(pending) === "change") {
3388
3427
  const outcome = await approveChangeAtTerminal(context.core, approvalId, env, {
3389
3428
  json: options.json,
3390
- color: options.color
3429
+ color: options.color,
3430
+ platform: context.platform
3391
3431
  }, streams);
3392
3432
  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");
3393
3433
  return;
@@ -3405,7 +3445,7 @@ is out: update first, or put it off (agentcomms update, agentcomms update --late
3405
3445
  }));
3406
3446
  const mcp = program.command("mcp").description("run the MCP server on stdio, for a coding agent to connect to").option("--account <name>", "pin the server to one account; every tool then acts on it and no other").action(async (flags) => {
3407
3447
  ran = true;
3408
- const { startResendStdioServer } = await import("./stdio-entry-Cibag7m5.mjs");
3448
+ const { startResendStdioServer } = await import("./stdio-entry-BCnq_EyF.mjs");
3409
3449
  await startResendStdioServer({
3410
3450
  ...deps,
3411
3451
  env,
@@ -3429,7 +3469,7 @@ is out: update first, or put it off (agentcomms update, agentcomms update --late
3429
3469
  const pinned = flags.account ?? mcp.opts().account;
3430
3470
  const launcher = flags.launcher;
3431
3471
  const name = flags.name;
3432
- const again = [
3472
+ const again = shellCommand([
3433
3473
  "agent-resend",
3434
3474
  "mcp",
3435
3475
  "install",
@@ -3440,7 +3480,7 @@ is out: update first, or put it off (agentcomms update, agentcomms update --late
3440
3480
  ...launcher !== void 0 ? ["--launcher", launcher] : [],
3441
3481
  ...flags.verify === false ? ["--no-verify"] : [],
3442
3482
  ...flags.force === true ? ["--force"] : []
3443
- ].join(" ");
3483
+ ], platform);
3444
3484
  const result = await changeAt(context, serverInstallChange(context.core, env, {
3445
3485
  channel: "resend",
3446
3486
  client: flags.client,
@@ -3460,7 +3500,12 @@ is out: update first, or put it off (agentcomms update, agentcomms update --late
3460
3500
  channel: "resend",
3461
3501
  dryRun: flags.dryRun === true,
3462
3502
  includePrinted: flags.includePrinted === true
3463
- }, RESEND_MCP), flags, `agent-resend mcp prune${flags.includePrinted === true ? " --include-printed" : ""}`);
3503
+ }, RESEND_MCP), flags, shellCommand([
3504
+ "agent-resend",
3505
+ "mcp",
3506
+ "prune",
3507
+ ...flags.includePrinted === true ? ["--include-printed"] : []
3508
+ ], platform));
3464
3509
  writeResult(result, output(), () => renderPrune(result, options.color), streams);
3465
3510
  }));
3466
3511
  program.command(`${UPDATE_CHECK_CHILD_COMMAND} <claimedAt>`, { hidden: true }).description("internal: finish the day's update check a command handed on").action(act(async (context, _options, claimedAt) => {
@@ -1,4 +1,4 @@
1
- import { D as _coercedNumber, O as _isoDate, k as _isoDateTime, n as ZodISODateTime, r as ZodNumber, t as ZodISODate } from "./schemas-DiGKNDNq.mjs";
1
+ import { D as _coercedNumber, r as ZodNumber } from "./iso-USuVU_sk.mjs";
2
2
  //#region ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/compat.js
3
3
  /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
4
4
  const ZodIssueCode = {
@@ -18,17 +18,9 @@ const ZodIssueCode = {
18
18
  var ZodFirstPartyTypeKind;
19
19
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
20
20
  //#endregion
21
- //#region ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/iso.js
22
- function datetime(params) {
23
- return _isoDateTime(ZodISODateTime, params);
24
- }
25
- function date(params) {
26
- return _isoDate(ZodISODate, params);
27
- }
28
- //#endregion
29
21
  //#region ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/coerce.js
30
22
  function number(params) {
31
23
  return _coercedNumber(ZodNumber, params);
32
24
  }
33
25
  //#endregion
34
- export { ZodIssueCode as i, date as n, datetime as r, number as t };
26
+ export { ZodIssueCode as n, number as t };
@@ -1,4 +1,4 @@
1
- import { A as stampErrorBrands, C as mergeCapabilities, D as runInputRequiredFlow, E as resolveInputRequiredDriverConfig, M as ListChangedOptionsBaseSchema, N as SERVER_INFO_META_KEY, O as scanXMcpHeaderDeclarations, P as SUBSCRIPTION_ID_META_KEY, S as legacyProtocolVersions, T as parseSchema, _ as isJSONRPCErrorResponse, b as isModernProtocolVersion, c as SdkErrorCode, d as __commonJSMin, f as __toESM, g as declaredDialect, h as codecForVersion, i as ProtocolErrorCode, j as DiscoverResultSchema, l as SdkHttpError, m as buildMcpParamHeaders, n as Protocol, o as SUPPORTED_MODERN_PROTOCOL_VERSIONS, p as brandedHasInstance, r as ProtocolError, s as SdkError, t as MODERN_WIRE_REVISION, u as UnsupportedProtocolVersionError, v as isJSONRPCRequest, w as modernProtocolVersions, x as isSpecType, y as isJSONRPCResultResponse } from "./src-D_zzAWoS-BhK0GFdq-XAvBzdGB.mjs";
1
+ import { A as stampErrorBrands, C as mergeCapabilities, D as runInputRequiredFlow, E as resolveInputRequiredDriverConfig, M as ListChangedOptionsBaseSchema, N as SERVER_INFO_META_KEY, O as scanXMcpHeaderDeclarations, P as SUBSCRIPTION_ID_META_KEY, S as legacyProtocolVersions, T as parseSchema, _ as isJSONRPCErrorResponse, b as isModernProtocolVersion, c as SdkErrorCode, d as __commonJSMin, f as __toESM, g as declaredDialect, h as codecForVersion, i as ProtocolErrorCode, j as DiscoverResultSchema, l as SdkHttpError, m as buildMcpParamHeaders, n as Protocol, o as SUPPORTED_MODERN_PROTOCOL_VERSIONS, p as brandedHasInstance, r as ProtocolError, s as SdkError, t as MODERN_WIRE_REVISION, u as UnsupportedProtocolVersionError, v as isJSONRPCRequest, w as modernProtocolVersions, x as isSpecType, y as isJSONRPCResultResponse } from "./src-D_zzAWoS-BhK0GFdq-oo-8IJem.mjs";
2
2
  //#region ../core/dist/dist-COPefvtq.mjs
3
3
  var require_code$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
package/dist/index.d.mts CHANGED
@@ -11509,7 +11509,7 @@ type RegisteredPrompt = {
11509
11509
  remove(): void;
11510
11510
  };
11511
11511
  //#endregion
11512
- //#region ../core/dist/change-flow-C4tw0Usg.d.mts
11512
+ //#region ../core/dist/change-flow-DxZfblwU.d.mts
11513
11513
  type SendPolicy = "chat" | "confirm" | "never";
11514
11514
  /**
11515
11515
  * How a loosening of the configuration is approved: `chat` — the person says yes in the conversation and the agent
@@ -11528,6 +11528,14 @@ interface ClientConfig {
11528
11528
  projectId?: string | undefined;
11529
11529
  secretRef: string;
11530
11530
  addedAt: string;
11531
+ /**
11532
+ * The organisation profile that made this row and owns it (design 2026-10-02 §D4) — absent on a row a person
11533
+ * registered, or one a profile adopted. A row carrying it is the profile's to change: `org update` and `org remove`
11534
+ * change it, and `client add --replace` and `client remove` refuse it while its organisation has a record.
11535
+ *
11536
+ * Additive: client rows are loose, so a release that does not know the key keeps it through its writes.
11537
+ */
11538
+ organisation?: string | undefined;
11531
11539
  }
11532
11540
  interface InboxConfig {
11533
11541
  /** Immutable id (`ibx_` + 16 base32 characters). Secrets and all state are keyed by it; the alias is a label. */
@@ -11653,6 +11661,34 @@ interface AccountConfig {
11653
11661
  * had chosen another port followed them to a sign-in that failed on the way back.
11654
11662
  */
11655
11663
  redirectPort?: number | undefined;
11664
+ /** The organisation profile whose Slack app created this account. Absent for a person's own app. */
11665
+ organisation?: string | undefined;
11666
+ /** Which app in that profile issued the account's current credential. */
11667
+ profileApp?: "read" | "send" | undefined;
11668
+ }
11669
+ type PendingRevocationStatus = "pending" | "revoked" | "expired";
11670
+ /** One bearer token in a superseded rotating bundle, tracked independently from its pair. */
11671
+ interface PendingRevocationTokenState {
11672
+ status: PendingRevocationStatus;
11673
+ /** The fixed absolute time after which the old token is known to be unusable. */
11674
+ deadline: string;
11675
+ }
11676
+ /**
11677
+ * A superseded credential kept until each token in it is conclusively revoked or expired.
11678
+ *
11679
+ * `store` belongs to the entry rather than being inferred from `secrets.store`: an older release can move the root
11680
+ * store without knowing to move this bundle, and cleanup must still find the only copy that exists.
11681
+ */
11682
+ interface PendingRevocation {
11683
+ ref: string;
11684
+ store: StoreKind;
11685
+ platform: string;
11686
+ workspace: string;
11687
+ createdAt: string;
11688
+ tokens: {
11689
+ access: PendingRevocationTokenState;
11690
+ refresh?: PendingRevocationTokenState | undefined;
11691
+ };
11656
11692
  }
11657
11693
  interface ConfigBody {
11658
11694
  /**
@@ -11666,6 +11702,8 @@ interface ConfigBody {
11666
11702
  inboxes: Record<string, InboxConfig>;
11667
11703
  /** Non-mail accounts. Absent in every config written before this key existed, hence the default. */
11668
11704
  accounts: Record<string, AccountConfig>;
11705
+ /** Superseded rotating credentials which still need conclusive per-token cleanup. */
11706
+ pendingRevocations?: PendingRevocation[] | undefined;
11669
11707
  defaults: Defaults;
11670
11708
  }
11671
11709
  interface ConfigV1 extends ConfigBody {
@@ -11687,11 +11725,74 @@ interface FormerNames {
11687
11725
  inboxes: Record<string, FormerName>;
11688
11726
  accounts: Record<string, FormerName>;
11689
11727
  }
11728
+ /** Who an organisation's Google client is for, as its administrator states it (design 2026-10-02 §D2). */
11729
+ type OrganisationServes = "any" | {
11730
+ domains: string[];
11731
+ };
11732
+ /**
11733
+ * One Google client an organisation profile brought here: a *generation* (design 2026-10-02 §D4).
11734
+ *
11735
+ * `owned` — the profile made the client row `name` (`rgc-1`), which carries `organisation`, and its secret is the
11736
+ * profile's to rewrite. `adopted` — the row was already here under a name a person chose (they ran `client add` with
11737
+ * the organisation's file), and stays theirs: no `org` command changes or removes it. `serves` is per generation,
11738
+ * because it is a fact about one client, not about the organisation.
11739
+ */
11740
+ interface OrganisationGeneration {
11741
+ name: string;
11742
+ clientId: string;
11743
+ projectId?: string | undefined;
11744
+ ownership: "owned" | "adopted";
11745
+ serves: OrganisationServes;
11746
+ addedAt: string;
11747
+ }
11748
+ interface OrganisationSlackApp {
11749
+ clientId: string;
11750
+ appId?: string | undefined;
11751
+ }
11752
+ /**
11753
+ * What this machine records of one organisation profile: never its bytes and never its secret — where it was read
11754
+ * from, the SHA-256 of what was read and when, the generations of its Google client, and its Slack apps.
11755
+ */
11756
+ interface OrganisationRecord {
11757
+ label: string;
11758
+ /** Read again, from this absolute path, by every `org update`. `file` is the one kind version 1 knows (§D3). */
11759
+ source: {
11760
+ kind: string;
11761
+ path: string;
11762
+ };
11763
+ sha256: string;
11764
+ readAt: string;
11765
+ addedAt: string;
11766
+ /** Whether the member asked for this organisation's client to serve addresses outside it too (§D6). */
11767
+ forOtherAddresses: boolean;
11768
+ /** `active` names the generation new mailboxes get — none once a profile stops naming a Google client. */
11769
+ gmail?: {
11770
+ active: string | null;
11771
+ generations: OrganisationGeneration[];
11772
+ } | undefined;
11773
+ slack?: {
11774
+ workspace: string;
11775
+ workspaceName: string;
11776
+ redirectPort: number;
11777
+ apps: {
11778
+ read?: OrganisationSlackApp | undefined;
11779
+ send?: OrganisationSlackApp | undefined;
11780
+ };
11781
+ } | undefined;
11782
+ }
11690
11783
  interface ConfigV2 extends ConfigBody {
11691
11784
  version: 2;
11692
11785
  formerNames: FormerNames;
11786
+ /**
11787
+ * The organisation profiles added here, by organisation word (design 2026-10-02 §D4). Absent reads as none, and
11788
+ * stays absent until the first `org add`: a key the schema filled in would be written into every file by the next
11789
+ * unrelated change.
11790
+ */
11791
+ organisations?: Record<string, OrganisationRecord> | undefined;
11693
11792
  }
11694
11793
  type Config$1 = ConfigV1 | ConfigV2;
11794
+ /** The committed config returned by an update; process-only commit metadata is deliberately stored out of band. */
11795
+ type ConfigUpdateResult = Config$1;
11695
11796
  declare class ConfigStore {
11696
11797
  #private;
11697
11798
  readonly path: string;
@@ -11704,7 +11805,8 @@ declare class ConfigStore {
11704
11805
  */
11705
11806
  update(mutator: (config: Config$1) => Config$1 | Promise<Config$1>, options?: {
11706
11807
  consent?: LooseningConsent;
11707
- }): Promise<Config$1>;
11808
+ signal?: AbortSignal | undefined;
11809
+ }): Promise<ConfigUpdateResult>;
11708
11810
  /**
11709
11811
  * The one way a version-1 config becomes version 2.
11710
11812
  *
@@ -11863,6 +11965,16 @@ interface ChangeBinding {
11863
11965
  settings?: SettingChange[] | undefined;
11864
11966
  /** What it does outside the configuration, in words: a sign-in, a registration, files removed. */
11865
11967
  effects: string[];
11968
+ /**
11969
+ * What the call that prepared it already did at once, because it never waits for an approval — a narrowing beside
11970
+ * the change (design 2026-10-02 §D8). Not what approving does: the preview lists these apart, and its header says
11971
+ * the rest is what waits. A field of its own rather than words in `effects`, so no text a change carries — a label
11972
+ * a profile chose, say — can make a preview claim something was done.
11973
+ *
11974
+ * Bound when present, so a record cannot gain one it was not prepared with; absent reads as none, and leaves the
11975
+ * digest of every other change exactly what it was.
11976
+ */
11977
+ doneAtOnce?: string[] | undefined;
11866
11978
  }
11867
11979
  /**
11868
11980
  * Exactly which download a question was asked for, stored on the record so the answer can be held to it.
@@ -11997,6 +12109,8 @@ interface LiveDraft {
11997
12109
  }
11998
12110
  /** What the product making a claim tells the store about itself. */
11999
12111
  interface ClaimOptions {
12112
+ /** The shell syntax used by any approval command this refusal prints. */
12113
+ platform?: NodeJS.Platform | undefined;
12000
12114
  /**
12001
12115
  * What the caller is told when the send is waiting for a person: which command approves it, and what to run after.
12002
12116
  *
@@ -12029,7 +12143,7 @@ declare class ApprovalStore {
12029
12143
  create(input: CreateApprovalInput): Promise<ApprovalRecord>;
12030
12144
  get(approvalId: string): Promise<ApprovalRecord | null>;
12031
12145
  /** Issues a new challenge to show a human; only its hash is kept. */
12032
- issueChallenge(approvalId: string, kind?: ApprovalKind): Promise<string>;
12146
+ issueChallenge(approvalId: string, kind?: ApprovalKind, platform?: NodeJS.Platform): Promise<string>;
12033
12147
  /**
12034
12148
  * A human approved through a confirm channel by typing the issued challenge. The draft must still be exactly what the
12035
12149
  * record was prepared for; otherwise the record is voided, because the human would be approving content the record
@@ -12038,7 +12152,7 @@ declare class ApprovalStore {
12038
12152
  * A change is approved the same way, with `kind: 'change'` and its digest standing in for the draft (see
12039
12153
  * `createChange`), so a person's typed code means one thing whichever kind of approval it is typed for.
12040
12154
  */
12041
- approve(approvalId: string, via: ApprovalChannel, live: LiveDraft, answer: string, kind?: ApprovalKind): Promise<ApprovalRecord>;
12155
+ approve(approvalId: string, via: ApprovalChannel, live: LiveDraft, answer: string, kind?: ApprovalKind, platform?: NodeJS.Platform): Promise<ApprovalRecord>;
12042
12156
  /**
12043
12157
  * Claims the record for sending, once. Non-consuming refusals (not yet approved) leave the record untouched so the
12044
12158
  * human can still approve it; integrity failures (other inbox or account, edited or changed draft, different
@@ -12092,7 +12206,7 @@ declare class ApprovalStore {
12092
12206
  *
12093
12207
  * Only a pending question can be answered, and only once: a second answer is refused, not taken over the first.
12094
12208
  */
12095
- answerDownload(approvalId: string, via: ApprovalChannel, answer: RecordedSaveAnswer): Promise<ApprovalRecord & {
12209
+ answerDownload(approvalId: string, via: ApprovalChannel, answer: RecordedSaveAnswer, platform?: NodeJS.Platform): Promise<ApprovalRecord & {
12096
12210
  download: DownloadBinding;
12097
12211
  }>;
12098
12212
  /**
@@ -12118,6 +12232,7 @@ declare class ApprovalStore {
12118
12232
  policy?: ChangePolicy | undefined;
12119
12233
  pendingHint?: string | undefined;
12120
12234
  signal?: AbortSignal | undefined;
12235
+ platform?: NodeJS.Platform | undefined;
12121
12236
  }): Promise<ApprovalRecord & {
12122
12237
  download: DownloadBinding;
12123
12238
  }>;
@@ -12429,6 +12544,8 @@ interface ResendContextOptions {
12429
12544
  core?: Core | undefined;
12430
12545
  env?: NodeJS.ProcessEnv | undefined;
12431
12546
  now?: (() => Date) | undefined;
12547
+ /** The shell syntax used for commands an operation returns or prints. */
12548
+ platform?: NodeJS.Platform | undefined;
12432
12549
  surface?: "cli" | "mcp" | undefined;
12433
12550
  /** The inner fetch every request goes through, always inside the guard. Injected so a test never reaches Resend. */
12434
12551
  fetch?: FetchLike | undefined;
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { _t as RESEND_DOWNLOAD_ORIGIN, gt as RESEND_API_ORIGIN, ht as REFUSED, vt as ROUTES, yt as VERSION } from "./send-BlDpMIlS.mjs";
2
- import { t as createResendMcpServer } from "./server-B-ubuD7Z.mjs";
1
+ import { _t as REFUSED, bt as ROUTES, vt as RESEND_API_ORIGIN, xt as VERSION, yt as RESEND_DOWNLOAD_ORIGIN } from "./send-D2ZOWO_6.mjs";
2
+ import { t as createResendMcpServer } from "./server-CLjdcZDg.mjs";
3
3
  //#region src/index.ts
4
4
  /**
5
5
  * The library entry of `@agentcomms/resend`.
@@ -1013,7 +1013,7 @@ const dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468
1013
1013
  function anchor(source) {
1014
1014
  return new RegExp(`^${source}$`);
1015
1015
  }
1016
- const date = /*@__PURE__*/ anchor(dateSource);
1016
+ const date$1 = /*@__PURE__*/ anchor(dateSource);
1017
1017
  function timeSource(args) {
1018
1018
  const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`;
1019
1019
  return typeof args.precision === "number" ? args.precision === -1 ? `${hhmm}` : args.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args.precision}}` : args.seconds ? `${hhmm}:[0-5]\\d(?:\\.\\d+)?` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`;
@@ -1021,7 +1021,7 @@ function timeSource(args) {
1021
1021
  function time(args) {
1022
1022
  return new RegExp(`^${timeSource(args)}$`);
1023
1023
  }
1024
- function datetime(args) {
1024
+ function datetime$1(args) {
1025
1025
  const opts = ["Z"];
1026
1026
  if (args.offset) opts.push(`([+-](?:[01]\\d|2[0-3]):[0-5]\\d)`);
1027
1027
  const qualified = `${timeSource({
@@ -1672,11 +1672,11 @@ const $ZodKSUID = /*@__PURE__*/ $constructor("$ZodKSUID", (inst, def) => {
1672
1672
  $ZodStringFormat.init(inst, def);
1673
1673
  });
1674
1674
  const $ZodISODateTime = /*@__PURE__*/ $constructor("$ZodISODateTime", (inst, def) => {
1675
- def.pattern ?? (def.pattern = datetime(def));
1675
+ def.pattern ?? (def.pattern = datetime$1(def));
1676
1676
  $ZodStringFormat.init(inst, def);
1677
1677
  });
1678
1678
  const $ZodISODate = /*@__PURE__*/ $constructor("$ZodISODate", (inst, def) => {
1679
- def.pattern ?? (def.pattern = date);
1679
+ def.pattern ?? (def.pattern = date$1);
1680
1680
  $ZodStringFormat.init(inst, def);
1681
1681
  });
1682
1682
  const $ZodISOTime = /*@__PURE__*/ $constructor("$ZodISOTime", (inst, def) => {
@@ -5882,4 +5882,12 @@ function preprocess(fn, schema) {
5882
5882
  });
5883
5883
  }
5884
5884
  //#endregion
5885
- export { NEVER as A, unknown as C, _coercedNumber as D, toJSONSchema as E, _isoDate as O, union as S, safeParse as T, optional as _, _null as a, strictObject as b, boolean as c, intersection as d, lazy as f, object as g, number as h, _enum as i, _isoDateTime as k, discriminatedUnion as l, looseObject as m, ZodISODateTime as n, any as o, literal as p, ZodNumber as r, array as s, ZodISODate as t, email as u, preprocess as v, url as w, string as x, record as y };
5885
+ //#region ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/iso.js
5886
+ function datetime(params) {
5887
+ return /* @__PURE__ */ _isoDateTime(ZodISODateTime, params);
5888
+ }
5889
+ function date(params) {
5890
+ return /* @__PURE__ */ _isoDate(ZodISODate, params);
5891
+ }
5892
+ //#endregion
5893
+ export { unknown as C, _coercedNumber as D, toJSONSchema as E, NEVER as O, union as S, safeParse as T, optional as _, _null as a, strictObject as b, boolean as c, intersection as d, lazy as f, object as g, number as h, _enum as i, discriminatedUnion as l, looseObject as m, datetime as n, any as o, literal as p, ZodNumber as r, array as s, date as t, email as u, preprocess as v, url as w, string as x, record as y };
@@ -1,5 +1,5 @@
1
- import { A as NEVER, C as unknown, E as toJSONSchema, S as union, T as safeParse, _ as optional, a as _null, c as boolean, d as intersection, f as lazy, g as object, h as number, i as _enum, l as discriminatedUnion, m as looseObject, o as any, p as literal, s as array, u as email, v as preprocess, w as url, x as string, y as record } from "./schemas-DiGKNDNq.mjs";
2
- import { i as ZodIssueCode, n as date, r as datetime, t as number$1 } from "./coerce-BscjcmYU.mjs";
1
+ import { C as unknown, E as toJSONSchema, O as NEVER, S as union, T as safeParse, _ as optional, a as _null, c as boolean, d as intersection, f as lazy, g as object, h as number, i as _enum, l as discriminatedUnion, m as looseObject, n as datetime, o as any, p as literal, s as array, t as date, u as email, v as preprocess, w as url, x as string, y as record } from "./iso-USuVU_sk.mjs";
2
+ import { n as ZodIssueCode, t as number$1 } from "./coerce-CqGigABD.mjs";
3
3
  import process$1 from "node:process";
4
4
  //#region ../../node_modules/.pnpm/@modelcontextprotocol+server@2.0.0/node_modules/@modelcontextprotocol/server/dist/chunk-Br0eD_fh.mjs
5
5
  var __create = Object.create;