@agentcomms/resend 0.12.2 → 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,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-BedjeO_M.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-QIUMjquj.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) => {
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-BcrEyoig.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
@@ -11997,6 +11997,8 @@ interface LiveDraft {
11997
11997
  }
11998
11998
  /** What the product making a claim tells the store about itself. */
11999
11999
  interface ClaimOptions {
12000
+ /** The shell syntax used by any approval command this refusal prints. */
12001
+ platform?: NodeJS.Platform | undefined;
12000
12002
  /**
12001
12003
  * What the caller is told when the send is waiting for a person: which command approves it, and what to run after.
12002
12004
  *
@@ -12029,7 +12031,7 @@ declare class ApprovalStore {
12029
12031
  create(input: CreateApprovalInput): Promise<ApprovalRecord>;
12030
12032
  get(approvalId: string): Promise<ApprovalRecord | null>;
12031
12033
  /** Issues a new challenge to show a human; only its hash is kept. */
12032
- issueChallenge(approvalId: string, kind?: ApprovalKind): Promise<string>;
12034
+ issueChallenge(approvalId: string, kind?: ApprovalKind, platform?: NodeJS.Platform): Promise<string>;
12033
12035
  /**
12034
12036
  * A human approved through a confirm channel by typing the issued challenge. The draft must still be exactly what the
12035
12037
  * record was prepared for; otherwise the record is voided, because the human would be approving content the record
@@ -12038,7 +12040,7 @@ declare class ApprovalStore {
12038
12040
  * A change is approved the same way, with `kind: 'change'` and its digest standing in for the draft (see
12039
12041
  * `createChange`), so a person's typed code means one thing whichever kind of approval it is typed for.
12040
12042
  */
12041
- approve(approvalId: string, via: ApprovalChannel, live: LiveDraft, answer: string, kind?: ApprovalKind): Promise<ApprovalRecord>;
12043
+ approve(approvalId: string, via: ApprovalChannel, live: LiveDraft, answer: string, kind?: ApprovalKind, platform?: NodeJS.Platform): Promise<ApprovalRecord>;
12042
12044
  /**
12043
12045
  * Claims the record for sending, once. Non-consuming refusals (not yet approved) leave the record untouched so the
12044
12046
  * human can still approve it; integrity failures (other inbox or account, edited or changed draft, different
@@ -12092,7 +12094,7 @@ declare class ApprovalStore {
12092
12094
  *
12093
12095
  * Only a pending question can be answered, and only once: a second answer is refused, not taken over the first.
12094
12096
  */
12095
- answerDownload(approvalId: string, via: ApprovalChannel, answer: RecordedSaveAnswer): Promise<ApprovalRecord & {
12097
+ answerDownload(approvalId: string, via: ApprovalChannel, answer: RecordedSaveAnswer, platform?: NodeJS.Platform): Promise<ApprovalRecord & {
12096
12098
  download: DownloadBinding;
12097
12099
  }>;
12098
12100
  /**
@@ -12118,6 +12120,7 @@ declare class ApprovalStore {
12118
12120
  policy?: ChangePolicy | undefined;
12119
12121
  pendingHint?: string | undefined;
12120
12122
  signal?: AbortSignal | undefined;
12123
+ platform?: NodeJS.Platform | undefined;
12121
12124
  }): Promise<ApprovalRecord & {
12122
12125
  download: DownloadBinding;
12123
12126
  }>;
@@ -12429,6 +12432,8 @@ interface ResendContextOptions {
12429
12432
  core?: Core | undefined;
12430
12433
  env?: NodeJS.ProcessEnv | undefined;
12431
12434
  now?: (() => Date) | undefined;
12435
+ /** The shell syntax used for commands an operation returns or prints. */
12436
+ platform?: NodeJS.Platform | undefined;
12432
12437
  surface?: "cli" | "mcp" | undefined;
12433
12438
  /** The inner fetch every request goes through, always inside the guard. Injected so a test never reaches Resend. */
12434
12439
  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-BedjeO_M.mjs";
2
+ import { t as createResendMcpServer } from "./server-Bq2OYONI.mjs";
3
3
  //#region src/index.ts
4
4
  /**
5
5
  * The library entry of `@agentcomms/resend`.