@agentcomms/resend 0.13.1 → 0.14.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/README.md +6 -4
- package/dist/cli.mjs +29 -8
- package/dist/index.d.mts +749 -95
- package/dist/index.mjs +2 -2
- package/dist/{send-DtBNDnE4.mjs → send-D0xGQynj.mjs} +7730 -4528
- package/dist/{server-B5FPOBcz.mjs → server-BfPGbXQD.mjs} +29 -5
- package/dist/{stdio-entry-CUFTANFM.mjs → stdio-entry-CtSxbgFr.mjs} +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -19,10 +19,11 @@ says this on every run.
|
|
|
19
19
|
|
|
20
20
|
**Nothing is sent without a person.** A send is prepared, previewed — every recipient, BCC included, the reach (unique
|
|
21
21
|
recipients), the From domain and whether it is verified — and approved: a yes in the conversation under the account's
|
|
22
|
-
`chat` policy, or the approve command the result gives and a typed code under `confirm
|
|
23
|
-
an address that arrived in mail read here, a person at a terminal
|
|
24
|
-
the request's `Idempotency-Key` and an `agentcomms_approval` tag; a
|
|
25
|
-
only checked
|
|
22
|
+
`chat` policy, or the approve command the result gives and a typed code under `confirm` — which the agent learns of
|
|
23
|
+
with `resend_send_wait`. Above ten recipients, or to an address that arrived in mail read here, a person at a terminal
|
|
24
|
+
approves, whatever the policy. The approval id is the request's `Idempotency-Key` and an `agentcomms_approval` tag; a
|
|
25
|
+
send whose outcome is unknown (`SEND_OUTCOME_UNKNOWN`) is never repeated, only checked, and a scheduled one is
|
|
26
|
+
"accepted", never "sent", until Resend's own last event for it says so.
|
|
26
27
|
|
|
27
28
|
**The key is typed by a person, at a terminal.** `agent-resend account add` reads it from a hidden prompt, or from
|
|
28
29
|
`RESEND_API_KEY` in that terminal, and stores it in the system keychain. No MCP tool accepts a key: a key typed into
|
|
@@ -96,6 +97,7 @@ terminal), `approve` (under `confirm`, a person at a terminal) and `mcp` (it sta
|
|
|
96
97
|
| `agent-resend send prepare` | `resend_send_prepare` |
|
|
97
98
|
| `agent-resend send execute <approvalId>` | `resend_send_execute` |
|
|
98
99
|
| `agent-resend send status <approvalId>` | `resend_send_status` |
|
|
100
|
+
| `agent-resend send wait <approvalId>` | `resend_send_wait` |
|
|
99
101
|
| `agent-resend scheduled list` | `resend_scheduled_list` |
|
|
100
102
|
| `agent-resend scheduled cancel <id>` | `resend_scheduled_cancel` |
|
|
101
103
|
| `agent-resend approve <approvalId>` | — a person at a terminal, with the command the result gives |
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { B as UPDATE_CHECK_CHILD_COMMAND, C as policyChange, D as sendPolicyOf,
|
|
2
|
+
import { $ as exemptFromUpdateGate, B as UPDATE_CHECK_CHILD_COMMAND, C as policyChange, D as sendPolicyOf, E as removeAccountChange, Et as writeResult, F as CHANNEL_SERVERS, G as canPrompt, H as approvalsOf, I as CommsError, J as cliHandoffs, L as EXIT_CODES, N as checkNewName, Nt as VERSION, O as showAccount, Ot as RESEND_CALLER, Q as escapeForDisplay, R as PATH_OPTIONS, S as policyApprovalRefusal, T as policyWanted, Tt as wholeNumber, U as approveChangeAtTerminal, V as agentMarker, W as approveRefusedHint, X as commandPathOf, Y as colorEnabled, Z as describeFenceReport, _ as runDoctor, _t as serverPruneChange, a as revokeSendApproval, at as kindOf, b as listAccounts, bt as truncateDisplay, c as downloadReceived, ct as pathOverridesFromCliOptions, d as listReceived, dt as renderInstall, f as listScheduled, ft as renderPrune, g as showSentEmail, gt as serverInstallChange, h as showReceived, ht as runUpdateCheckChild, i as prepareSend, it as installExitStatus, k as ResendContext, l as getMetrics, lt as refuseUnclaimedApproval, m as listSuppressions, mt as runCommand, n as executeSend, nt as handoffSentence, o as sendStatus, ot as openCore, p as listSentEmails, pt as resolvePaths, r as finishSendApproval, rt as handoffSentenceToFill, s as cancelScheduledChange, st as paint, t as beginSendApproval, tt as gatedChangeAtTerminal, u as listDomains, ut as renderApprovalWait, v as addAccountChange, vt as terminalUpdateHooks, w as policyReport, wt as waitForApproval, x as modeOf, xt as updateGateAtTerminal, y as inspectKey, z as SEND_LOOKUP } from "./send-D0xGQynj.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
5
5
|
import { stripVTControlCharacters } from "node:util";
|
|
@@ -3089,7 +3089,8 @@ function renderPolicy(report) {
|
|
|
3089
3089
|
return [
|
|
3090
3090
|
`${report.name}: ${report.mode} mode, send policy ${report.sendPolicy}${report.sendPolicyFrom === "default" ? " (the machine default)" : ""}`,
|
|
3091
3091
|
`Changes to it are approved under the machine's change policy: ${report.changePolicy}.`,
|
|
3092
|
-
`A send to more than ${report.confirmAboveRecipients} people needs a person at a terminal, whatever the policy
|
|
3092
|
+
`A send to more than ${report.confirmAboveRecipients} people needs a person at a terminal, whatever the policy.`,
|
|
3093
|
+
...report.fenced === void 0 ? [] : describeFenceReport(report.fenced)
|
|
3093
3094
|
].join("\n");
|
|
3094
3095
|
}
|
|
3095
3096
|
function renderDoctor(result, color) {
|
|
@@ -3115,15 +3116,22 @@ function renderRead(result, color) {
|
|
|
3115
3116
|
function renderPrepared(result) {
|
|
3116
3117
|
return `${result.preview}\n\nNext: ${escapeForDisplay(result.nextStep)}`;
|
|
3117
3118
|
}
|
|
3119
|
+
/**
|
|
3120
|
+
* What Resend's acceptance means (`said`), with its id when it gave one: a scheduled send is accepted for its time and
|
|
3121
|
+
* never called sent; one with no id says so, and names none.
|
|
3122
|
+
*/
|
|
3118
3123
|
function renderSent(result) {
|
|
3119
|
-
const
|
|
3124
|
+
const to = truncateDisplay(result.to.join(", "), 200);
|
|
3125
|
+
const said = `${result.said.charAt(0).toUpperCase()}${result.said.slice(1)}`;
|
|
3126
|
+
const sent = result.resendId === void 0 ? result.state === "scheduled" ? `${said} — scheduled for ${result.scheduledAt ?? "?"}, to ${to}.` : `${said} — to ${to}.` : result.state === "scheduled" ? `${said}, as ${result.resendId}, to ${to}.` : `Sent as ${result.resendId}, to ${to}.`;
|
|
3120
3127
|
return result.note ? `${sent}\nNote: ${escapeForDisplay(result.note)}.` : sent;
|
|
3121
3128
|
}
|
|
3122
3129
|
function renderStatus(result) {
|
|
3123
3130
|
return `${result.approvalId}: ${escapeForDisplay(result.verdict)}`;
|
|
3124
3131
|
}
|
|
3125
3132
|
function renderCancelled(result) {
|
|
3126
|
-
|
|
3133
|
+
const cancelled = `Cancelled ${result.id} (${result.recipients} recipient(s)). It cannot be rescheduled.`;
|
|
3134
|
+
return result.hint ? `${cancelled}\nNote: ${escapeForDisplay(result.hint)}` : cancelled;
|
|
3127
3135
|
}
|
|
3128
3136
|
//#endregion
|
|
3129
3137
|
//#region src/cli/program.ts
|
|
@@ -3234,8 +3242,9 @@ is out: update first, or put it off (the stop names both commands) · 64 usage
|
|
|
3234
3242
|
noInput: false,
|
|
3235
3243
|
streams,
|
|
3236
3244
|
approvals: approvalsOf(command),
|
|
3237
|
-
approvalClaim: path.join(" ") === "send status" ? SEND_LOOKUP : void 0,
|
|
3245
|
+
approvalClaim: path.join(" ") === "send status" ? SEND_LOOKUP : path.join(" ") === "send wait" ? { lookup: true } : void 0,
|
|
3238
3246
|
...terminalUpdateHooks(core, env, {
|
|
3247
|
+
channel: "resend",
|
|
3239
3248
|
output: output(),
|
|
3240
3249
|
streams
|
|
3241
3250
|
})
|
|
@@ -3266,6 +3275,7 @@ is out: update first, or put it off (the stop names both commands) · 64 usage
|
|
|
3266
3275
|
* after the program, which core locates as Resend's own and runs again with `--approval <id>`.
|
|
3267
3276
|
*/
|
|
3268
3277
|
const changeAt = (context, change, flags, rerun) => gatedChangeAtTerminal(context.core, change, {
|
|
3278
|
+
channel: "resend",
|
|
3269
3279
|
approvalId: flags.approval === void 0 ? void 0 : String(flags.approval),
|
|
3270
3280
|
env,
|
|
3271
3281
|
output: output(),
|
|
@@ -3430,6 +3440,17 @@ is out: update first, or put it off (the stop names both commands) · 64 usage
|
|
|
3430
3440
|
const status = await sendStatus(context, String(flags.account), approvalId);
|
|
3431
3441
|
writeResult(status, output(), renderStatus, streams);
|
|
3432
3442
|
}));
|
|
3443
|
+
send.command("wait <approvalId>").description("wait for an approval to be usable or finished, and say where it stands — it only looks, and never sends").option("--wait-seconds <n>", `how long to wait: 30 when left out, 300 at most, 0 for the status now`).action(act(async (context, _options, approvalId, flags) => {
|
|
3444
|
+
const result = await waitForApproval(context.core, approvalId, {
|
|
3445
|
+
waitSeconds: wholeNumber(flags.waitSeconds, {
|
|
3446
|
+
name: "--wait-seconds",
|
|
3447
|
+
min: 0,
|
|
3448
|
+
max: 300
|
|
3449
|
+
}),
|
|
3450
|
+
channel: "resend"
|
|
3451
|
+
});
|
|
3452
|
+
writeResult(result, output(), renderApprovalWait, streams);
|
|
3453
|
+
}));
|
|
3433
3454
|
const scheduled = program.command("scheduled").description("emails waiting to be sent at a later time");
|
|
3434
3455
|
accountOption(scheduled.command("list")).description("scheduled emails among the most recent 300 sent").action(act(async (context, options, flags) => {
|
|
3435
3456
|
const result = await listScheduled(context, String(flags.account));
|
|
@@ -3449,12 +3470,12 @@ is out: update first, or put it off (the stop names both commands) · 64 usage
|
|
|
3449
3470
|
const marker = agentMarker(env);
|
|
3450
3471
|
const approve = context.handoffs.own(["approve", approvalId]);
|
|
3451
3472
|
if (marker) throw new CommsError("APPROVAL_REQUIRED", "only a person can approve a send or a change, not an agent", {
|
|
3452
|
-
hint:
|
|
3473
|
+
hint: approveRefusedHint(context.handoffs, approvalId),
|
|
3453
3474
|
details: { marker }
|
|
3454
3475
|
});
|
|
3455
3476
|
if (!canPrompt(env, streams, { json: options.json })) throw new CommsError("APPROVAL_REQUIRED", "approving needs an interactive terminal", { hint: handoffSentence(approve, (command) => `Run ${command} directly in a terminal.`) });
|
|
3456
3477
|
const pending = await context.core.approvals.get(approvalId);
|
|
3457
|
-
if (
|
|
3478
|
+
if (kindOf(pending) === "change") {
|
|
3458
3479
|
const outcome = await approveChangeAtTerminal(context.core, approvalId, env, {
|
|
3459
3480
|
json: options.json,
|
|
3460
3481
|
color: options.color,
|
|
@@ -3476,7 +3497,7 @@ is out: update first, or put it off (the stop names both commands) · 64 usage
|
|
|
3476
3497
|
}));
|
|
3477
3498
|
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) => {
|
|
3478
3499
|
ran = true;
|
|
3479
|
-
const startResendStdioServer = deps.startMcp ?? (await import("./stdio-entry-
|
|
3500
|
+
const startResendStdioServer = deps.startMcp ?? (await import("./stdio-entry-CtSxbgFr.mjs")).startResendStdioServer;
|
|
3480
3501
|
const core = coreForInvocation();
|
|
3481
3502
|
await startResendStdioServer({
|
|
3482
3503
|
...deps,
|