agentinbox-cli 0.1.0-nightly.35 → 0.1.0-nightly.37

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.
Files changed (101) hide show
  1. package/dist/{admin-CCIR1XvZ.js → admin-B-e0fGL8.js} +21 -7
  2. package/dist/admin-B-e0fGL8.js.map +1 -0
  3. package/dist/cli.js +6 -25
  4. package/dist/cli.js.map +1 -1
  5. package/dist/{commands-BRvw2jIt.js → commands-B1JRkH7_.js} +59 -21
  6. package/dist/commands-B1JRkH7_.js.map +1 -0
  7. package/dist/{connect-DR3YrwvV.js → connect-DbfCEHOf.js} +21 -12
  8. package/dist/{connect-DR3YrwvV.js.map → connect-DbfCEHOf.js.map} +1 -1
  9. package/dist/hermes-BobpCc4t.js +940 -0
  10. package/dist/hermes-BobpCc4t.js.map +1 -0
  11. package/dist/hermes-DiW4LyFm.js +3 -0
  12. package/dist/{listen-CvRrKzBz.js → listen-CE_6o-WO.js} +195 -667
  13. package/dist/listen-CE_6o-WO.js.map +1 -0
  14. package/dist/listen-K5SDQlRA.js +2 -0
  15. package/dist/{mcpheader-Cccnqodg.js → mcpheader-8Mqlqp1h.js} +68 -5
  16. package/dist/mcpheader-8Mqlqp1h.js.map +1 -0
  17. package/dist/mcpheader-BNjmjI1b.js +2 -0
  18. package/dist/mcpsetup-RpaNjEw_.js +2 -0
  19. package/dist/{mcpsetup-CvRN7NPm.js → mcpsetup-d1PRQk9r.js} +139 -7
  20. package/dist/mcpsetup-d1PRQk9r.js.map +1 -0
  21. package/dist/node-check-D6v5n6d2.js +24 -0
  22. package/dist/node-check-D6v5n6d2.js.map +1 -0
  23. package/dist/{profile-C1u9BrI8.js → profile-BqGV-DOU.js} +7 -1
  24. package/dist/profile-BqGV-DOU.js.map +1 -0
  25. package/dist/profile-C38suDkJ.js +2 -0
  26. package/dist/recipes-Cw2ShA42.js +310 -0
  27. package/dist/recipes-Cw2ShA42.js.map +1 -0
  28. package/dist/recipes-DlhXH1O8.js +2 -0
  29. package/dist/{server-8N5imyc2.js → server-DiPOZSU8.js} +874 -32
  30. package/dist/server-DiPOZSU8.js.map +1 -0
  31. package/dist/{service-DkVpScAM.js → service-D75izPEj.js} +1 -1
  32. package/dist/{service-iiykwB5r.js → service-DHBfOtp7.js} +155 -52
  33. package/dist/service-DHBfOtp7.js.map +1 -0
  34. package/dist/{service-DdmIr4ox.js → service-VEbnQILm.js} +11 -5
  35. package/dist/service-VEbnQILm.js.map +1 -0
  36. package/dist/service-nQ2gc_4x.js +2 -0
  37. package/dist/skill/SKILL.md +35 -16
  38. package/dist/web/assets/{_agentId-BVFcaL-N.js → _agentId-S1HPvZ-A.js} +1 -1
  39. package/dist/web/assets/{_app-CQ3qgq-F.js → _app-9OiYPzoE.js} +1 -1
  40. package/dist/web/assets/{_app-CKJmVNkI.js → _app-CTqw82IX.js} +1 -1
  41. package/dist/web/assets/{_webhookId-Cerio5Vu.js → _webhookId-ZgpFgu5b.js} +1 -1
  42. package/dist/web/assets/{account-status-BjH_H-Q2.js → account-status-D30kFHUc.js} +1 -1
  43. package/dist/web/assets/{accounts-Csv2aC5y.js → accounts-CnIPa0qh.js} +1 -1
  44. package/dist/web/assets/{accounts-list-CGhwo783.js → accounts-list-BtQxpmGm.js} +1 -1
  45. package/dist/web/assets/{agent-create-form-DE8IWy9S.js → agent-create-form-DpzMNzHr.js} +1 -1
  46. package/dist/web/assets/{agents-CzNLXrHc.js → agents-BD-NIb5j.js} +1 -1
  47. package/dist/web/assets/{approvals-DFUU68fJ.js → approvals-B6wHykyi.js} +1 -1
  48. package/dist/web/assets/{attention-BhWf7Sf-.js → attention-DMA02b1f.js} +1 -1
  49. package/dist/web/assets/{audit-fezrf1T6.js → audit-BUc7vZhg.js} +1 -1
  50. package/dist/web/assets/{audit-bits-CnuntUM2.js → audit-bits-BYFcaQSf.js} +1 -1
  51. package/dist/web/assets/{chips-input-mJflzY4r.js → chips-input-DDDBXHB7.js} +1 -1
  52. package/dist/web/assets/{choice-cards-B0cy08db.js → choice-cards-nNXow1Od.js} +1 -1
  53. package/dist/web/assets/cli-d49Yn6md.js +1 -0
  54. package/dist/web/assets/{command-xvyfCxrc.js → command-DdmekLLh.js} +1 -1
  55. package/dist/web/assets/{common-CY3qLoy1.js → common-C0QNVOcQ.js} +1 -1
  56. package/dist/web/assets/{connect-agent-guide-DsbwQbYV.js → connect-agent-guide-BCKNX8yq.js} +1 -1
  57. package/dist/web/assets/{connect-host-ALXlbF75.js → connect-host-CiD91Gso.js} +1 -1
  58. package/dist/web/assets/{data-table-Dl9rCJ-v.js → data-table-B1VUusw5.js} +1 -1
  59. package/dist/web/assets/{events-RItAQZX4.js → events-DDQlbNRb.js} +1 -1
  60. package/dist/web/assets/get-started-B3_jDaTo.js +1 -0
  61. package/dist/web/assets/{index-CtDCYav3.js → index-DESr3-Rq.js} +3 -3
  62. package/dist/web/assets/{label-multi-select-nZ9oYzGS.js → label-multi-select-DYnV5CnF.js} +1 -1
  63. package/dist/web/assets/{last-call-DkjeYO8l.js → last-call-DQHmzSx9.js} +1 -1
  64. package/dist/web/assets/{login-HvIJHpVy.js → login-BAnCYytu.js} +1 -1
  65. package/dist/web/assets/{mutations-txguWSkg.js → mutations-B3jbqBsA.js} +1 -1
  66. package/dist/web/assets/{pairing-CwfQMKxC.js → pairing-C1S88iMj.js} +1 -1
  67. package/dist/web/assets/{public-url-CCaLIiMZ.js → public-url-BoSol5Rt.js} +1 -1
  68. package/dist/web/assets/{select-DsM_JHxb.js → select-CjDJAlMf.js} +1 -1
  69. package/dist/web/assets/{settings-BqnoHfr1.js → settings-DTprvEn3.js} +1 -1
  70. package/dist/web/assets/{setup-D_7uRkQJ.js → setup-DkeFAoTi.js} +1 -1
  71. package/dist/web/assets/{sheet-CM1KfYL2.js → sheet-CQ1hG6mF.js} +1 -1
  72. package/dist/web/assets/{step-url-BBaGsS0C.js → step-url-B_HuVNnd.js} +1 -1
  73. package/dist/web/assets/{test-email-button-Cr16sm7O.js → test-email-button-D3GmMouA.js} +1 -1
  74. package/dist/web/assets/{toggle-group-DAPHSER5.js → toggle-group-jgPklWgu.js} +1 -1
  75. package/dist/web/assets/{use-delivery-speed-L8Os4HxL.js → use-delivery-speed-n5-lnVz6.js} +1 -1
  76. package/dist/web/assets/{webhook-bits-7cNQgKhe.js → webhook-bits-BtV3Echq.js} +1 -1
  77. package/dist/web/assets/{webhook-sheet-cqAJmFmo.js → webhook-sheet-ByWrp_sw.js} +1 -1
  78. package/dist/web/assets/{webhooks-B6WgYLzH.js → webhooks-DmHVQ9L0.js} +1 -1
  79. package/dist/web/index.html +2 -2
  80. package/package.json +1 -1
  81. package/dist/admin-CCIR1XvZ.js.map +0 -1
  82. package/dist/commands-BRvw2jIt.js.map +0 -1
  83. package/dist/listen-Cjsv8Gwy.js +0 -2
  84. package/dist/listen-CvRrKzBz.js.map +0 -1
  85. package/dist/mcpheader-Cccnqodg.js.map +0 -1
  86. package/dist/mcpheader-H0mMJYYw.js +0 -2
  87. package/dist/mcpsetup-CPxIa7U3.js +0 -2
  88. package/dist/mcpsetup-CvRN7NPm.js.map +0 -1
  89. package/dist/profile-BL6jqiTB.js +0 -2
  90. package/dist/profile-C1u9BrI8.js.map +0 -1
  91. package/dist/recipes-Bn3ttR3i.js +0 -2
  92. package/dist/recipes-U2teSD6l.js +0 -123
  93. package/dist/recipes-U2teSD6l.js.map +0 -1
  94. package/dist/server-8N5imyc2.js.map +0 -1
  95. package/dist/service-B5T24GYF.js +0 -2
  96. package/dist/service-DdmIr4ox.js.map +0 -1
  97. package/dist/service-iiykwB5r.js.map +0 -1
  98. package/dist/ui-B8Sd4Y7Y.js +0 -81
  99. package/dist/ui-B8Sd4Y7Y.js.map +0 -1
  100. package/dist/web/assets/cli-DcQ046Hh.js +0 -1
  101. package/dist/web/assets/get-started-fdzGyOrW.js +0 -1
@@ -1,9 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { S as ApiError, a as pidAlive, b as Dispatcher, c as writeDead, d as forwardSecret, f as resolveListen, g as checkTransport, h as TransportError, l as DEFAULT_LISTEN_TYPES, m as forwardEvent, o as readDead, s as readStatus, w as getSelf, x as describeGrants, y as runCommand } from "./listen-CvRrKzBz.js";
3
- import { i as safeText, r as formatDuration } from "./ui-B8Sd4Y7Y.js";
4
- import { d as NPX, i as saveProfile, n as loadProfile, s as ensurePrivateDir } from "./profile-C1u9BrI8.js";
2
+ import { A as getSelf, _ as forwardEvent, c as DEFAULT_LISTEN_TYPES, d as describeFilter, f as forwardSecret, p as resolveListen, w as ApiError } from "./hermes-BobpCc4t.js";
3
+ import { h as safeText, m as formatDuration } from "./mcpsetup-d1PRQk9r.js";
4
+ import { d as NPX, i as saveProfile, n as loadProfile, s as ensurePrivateDir } from "./profile-BqGV-DOU.js";
5
+ import { c as readDead, d as runCommand, f as Dispatcher, i as outputLine, l as readStatus, p as describeGrants, s as pidAlive, u as writeDead } from "./listen-CE_6o-WO.js";
6
+ import { S as checkTransport, p as isHermesRoute, x as TransportError } from "./recipes-Cw2ShA42.js";
5
7
  import { c as profilePath, i as deadPath, o as logPath, p as validProfileName } from "./paths-DckASYtc.js";
6
- import { d as unitName, n as isServiceInstalled, r as launchdLabel } from "./service-iiykwB5r.js";
8
+ import { f as unitName, n as isServiceInstalled, r as launchdLabel } from "./service-DHBfOtp7.js";
7
9
  import pc from "picocolors";
8
10
  //#region server/listen/admin.ts
9
11
  const out = (s = "") => process.stdout.write(`${s}\n`);
@@ -48,6 +50,17 @@ async function printStatus(profileName) {
48
50
  const targets = [exec ? `exec ${safeText(exec, 120)}` : null, forward ? `forward ${forward}` : null].filter(Boolean);
49
51
  out(`${pc.bold("Runs")} ${targets.length ? targets.join(" · ") : pc.gray("nothing saved (pass --exec/--forward with --save)")}`);
50
52
  out(`${pc.bold("Events")} ${profile.types?.length ? profile.types.join(", ") : `${DEFAULT_LISTEN_TYPES.join(", ")} ${pc.gray("(default types; add --types all --save for every event)")}`}`);
53
+ let saved = null;
54
+ try {
55
+ saved = resolveListen(name, profile, {}).config;
56
+ } catch {}
57
+ out(`${pc.bold("Filters")} ${alive && st?.filters || (saved ? describeFilter(saved) : "?")}`);
58
+ const batchSeconds = alive && st && st.batchSeconds !== void 0 ? st.batchSeconds : saved?.batchSeconds ?? 0;
59
+ if (batchSeconds) out(`${pc.bold("Batch")} ${formatDuration(batchSeconds * 1e3)} window, up to 20 events per --exec run`);
60
+ out(`${pc.bold("Output")} ${outputLine(name, {
61
+ exec: exec ?? null,
62
+ forward: forward ? { url: forward } : null
63
+ }, logPath(name))}`);
51
64
  let svc = "not installed";
52
65
  if (process.platform === "linux" || process.platform === "darwin") {
53
66
  if (isServiceInstalled(name)) svc = `installed (${process.platform === "linux" ? unitName(name) : launchdLabel(name)}; details: ${NPX} listen service status${flagFor(name)})`;
@@ -70,7 +83,7 @@ async function printStatus(profileName) {
70
83
  else {
71
84
  const state = !alive ? pc.gray(`not running${st.stoppedAt ? ` (stopped ${ago(st.stoppedAt)}${st.exitReason ? `: ${safeText(st.exitReason, 160)}` : ""})` : " (exited unexpectedly)"}`) : st.connected ? pc.green(`running (pid ${st.pid}), connected ${ago(st.connectedSince)}`) : pc.yellow(`running (pid ${st.pid}), disconnected${st.lastDisconnect ? ` ${ago(st.lastDisconnect.at)}: ${safeText(st.lastDisconnect.reason, 160)}` : ""}`);
72
85
  out(`${pc.bold("Listener")} ${state}`);
73
- out(`${pc.bold("Cursor")} acked #${st.ackedSeq} · received #${st.receivedSeq}${alive && st.running ? ` · ${st.running} in progress` : ""} · last event ${ago(st.lastEventAt)}`);
86
+ out(`${pc.bold("Cursor")} acked #${st.ackedSeq} · received #${st.receivedSeq}${alive && st.running ? ` · ${st.running} in progress` : ""}${st.skipped ? ` · ${st.skipped} skipped by filters` : ""} · last event ${ago(st.lastEventAt)}`);
74
87
  if (st.recent.length) {
75
88
  out(pc.bold("Recent"));
76
89
  for (const r of st.recent.slice(0, 8)) {
@@ -155,7 +168,8 @@ async function replayDead(flags, opts = {}) {
155
168
  if (job.remaining.has("forward") && config.forward) {
156
169
  const r = await forwardEvent(config.forward.url, config.forward.secret, job.payload, {
157
170
  timeoutMs: Math.min(timeoutMs, 3e4),
158
- signal
171
+ signal,
172
+ wrap: isHermesRoute(config.forward.url)
159
173
  });
160
174
  if (r.ok) job.remaining.delete("forward");
161
175
  else errors.push(`forward: ${r.error}`);
@@ -197,4 +211,4 @@ async function replayDead(flags, opts = {}) {
197
211
  //#endregion
198
212
  export { clearDead, printDead, printSecret, printStatus, replayDead };
199
213
 
200
- //# sourceMappingURL=admin-CCIR1XvZ.js.map
214
+ //# sourceMappingURL=admin-B-e0fGL8.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-B-e0fGL8.js","names":[],"sources":["../server/listen/admin.ts"],"sourcesContent":["import pc from \"picocolors\";\nimport { ApiError, getSelf } from \"./api.ts\";\nimport { describeGrants } from \"./grants.ts\";\nimport { Dispatcher, type Job, type Target } from \"./dispatcher.ts\";\nimport { runCommand } from \"./exec.ts\";\nimport { ensurePrivateDir } from \"./fsutil.ts\";\nimport { forwardEvent } from \"./forward.ts\";\nimport { describeFilter, type ListenFlags, MAX_BATCH, resolveListen } from \"./options.ts\";\nimport { outputLine } from \"./listen.ts\";\nimport { isHermesRoute } from \"./recipes.ts\";\nimport { DEFAULT_PROFILE, deadPath, logPath, profilePath, validProfileName } from \"./paths.ts\";\nimport { loadProfile, saveProfile } from \"./profile.ts\";\nimport { DEFAULT_LISTEN_TYPES, forwardSecret } from \"./options.ts\";\nimport { isServiceInstalled, launchdLabel, unitName } from \"./service.ts\";\nimport { type DeadEntry, pidAlive, readDead, readStatus, writeDead } from \"./state.ts\";\nimport { checkTransport, TransportError } from \"./transport.ts\";\nimport { formatDuration, safeText } from \"./ui.ts\";\nimport { NPX } from \"./version.ts\";\n\nconst out = (s = \"\") => process.stdout.write(`${s}\\n`);\nconst flagFor = (profile: string) => (profile === DEFAULT_PROFILE ? \"\" : ` --profile ${profile}`);\nconst ago = (iso: string | null | undefined) => (iso ? `${formatDuration(Date.now() - Date.parse(iso))} ago` : \"never\");\n\n// ───────────── listen secret ─────────────\n\n/** Prints the forward-mode signing secret (generating and saving it on first use). */\nexport function printSecret(profileName: string, opts: { rotate?: boolean }): void {\n const name = validProfileName(profileName);\n const profile = loadProfile(name);\n let { secret, created } = forwardSecret(profile);\n if (opts.rotate) {\n secret = forwardSecret({ ...profile, forward: undefined, forwardSecret: undefined }).secret;\n created = true;\n }\n if (created) {\n if (profile.forward) profile.forward = { ...profile.forward, secret };\n else profile.forwardSecret = secret;\n saveProfile(name, profile);\n process.stderr.write(pc.gray(`${opts.rotate ? \"Rotated\" : \"Generated\"} the forward signing secret for profile \"${name}\"${opts.rotate ? \"; restart the listener\" : \"\"}.\\n`));\n }\n // The secret alone on stdout, so `export AGENTINBOX_WEBHOOK_SECRET=$(agentinbox listen secret)` works.\n out(secret);\n}\n\n// ───────────── listen status ─────────────\n\nexport async function printStatus(profileName: string): Promise<void> {\n const name = validProfileName(profileName);\n const profile = loadProfile(name);\n const st = readStatus(name);\n const alive = st ? pidAlive(st.pid) && !st.stoppedAt : false;\n const dead = readDead(name);\n\n out(`${pc.bold(\"Profile\")} ${name} ${pc.gray(profilePath(name))}`);\n out(`${pc.bold(\"Agent\")} ${safeText(profile.agentName)} ${pc.gray(`(${profile.agentId})`)}`);\n out(`${pc.bold(\"Daemon\")} ${profile.url}`);\n out(`${pc.bold(\"Consumer\")} ${st?.consumer ?? profile.consumer}`);\n // What the last run used (flags included), else what the profile has saved.\n const exec = st && st.exec !== undefined ? st.exec : profile.exec;\n const forward = st && st.forward !== undefined ? st.forward : profile.forward?.url;\n const targets = [exec ? `exec ${safeText(exec, 120)}` : null, forward ? `forward ${forward}` : null].filter(Boolean);\n out(`${pc.bold(\"Runs\")} ${targets.length ? targets.join(\" · \") : pc.gray(\"nothing saved (pass --exec/--forward with --save)\")}`);\n out(\n `${pc.bold(\"Events\")} ${\n profile.types?.length\n ? profile.types.join(\", \")\n : `${DEFAULT_LISTEN_TYPES.join(\", \")} ${pc.gray(\"(default types; add --types all --save for every event)\")}`\n }`,\n );\n // The running listener's filters (flags included), else the profile's.\n let saved: ReturnType<typeof resolveListen>[\"config\"] | null = null;\n try {\n saved = resolveListen(name, profile, {}).config;\n } catch {\n // An invalid saved setting: `listen` itself reports it.\n }\n out(`${pc.bold(\"Filters\")} ${(alive && st?.filters) || (saved ? describeFilter(saved) : \"?\")}`);\n const batchSeconds = alive && st && st.batchSeconds !== undefined ? st.batchSeconds : (saved?.batchSeconds ?? 0);\n if (batchSeconds) out(`${pc.bold(\"Batch\")} ${formatDuration(batchSeconds * 1000)} window, up to ${MAX_BATCH} events per --exec run`);\n out(`${pc.bold(\"Output\")} ${outputLine(name, { exec: exec ?? null, forward: forward ? { url: forward } : null }, logPath(name))}`);\n\n let svc = \"not installed\";\n if (process.platform === \"linux\" || process.platform === \"darwin\") {\n if (isServiceInstalled(name)) svc = `installed (${process.platform === \"linux\" ? unitName(name) : launchdLabel(name)}; details: ${NPX} listen service status${flagFor(name)})`;\n }\n out(`${pc.bold(\"Service\")} ${svc}`);\n\n try {\n // Never send the key over a connection `listen` itself would refuse.\n await checkTransport(profile.url, { insecure: profile.insecure });\n const self = await getSelf(profile.url, profile.apiKey, 5000);\n out(`${pc.bold(\"Key\")} ${pc.green(\"valid\")}`);\n // The access the console actually granted, in plain words (what the agent should report to its human).\n const lines = describeGrants(self.grants);\n out(`${pc.bold(\"Access\")} ${self.grants.length ? lines[0] : pc.yellow(lines[0]!)}`);\n for (const l of lines.slice(1)) out(` ${l}`);\n } catch (err) {\n const revoked = err instanceof ApiError && (err.status === 401 || err.status === 403);\n const why = err instanceof ApiError && err.status === 0 ? (err.cause as string) : err instanceof Error ? err.message.split(\"\\n\")[0] : String(err);\n if (err instanceof TransportError) out(`${pc.bold(\"Key\")} ${pc.red(`not checked: ${why}`)}`);\n else out(`${pc.bold(\"Key\")} ${revoked ? pc.red(`rejected: ${(err as Error).message}`) : pc.yellow(`not checked (${why})`)}`);\n }\n\n if (!st) {\n out(`${pc.bold(\"Listener\")} ${pc.gray(\"has not run yet\")}`);\n } else {\n const state = !alive\n ? pc.gray(`not running${st.stoppedAt ? ` (stopped ${ago(st.stoppedAt)}${st.exitReason ? `: ${safeText(st.exitReason, 160)}` : \"\"})` : \" (exited unexpectedly)\"}`)\n : st.connected\n ? pc.green(`running (pid ${st.pid}), connected ${ago(st.connectedSince)}`)\n : pc.yellow(`running (pid ${st.pid}), disconnected${st.lastDisconnect ? ` ${ago(st.lastDisconnect.at)}: ${safeText(st.lastDisconnect.reason, 160)}` : \"\"}`);\n out(`${pc.bold(\"Listener\")} ${state}`);\n out(\n `${pc.bold(\"Cursor\")} acked #${st.ackedSeq} · received #${st.receivedSeq}${alive && st.running ? ` · ${st.running} in progress` : \"\"}${st.skipped ? ` · ${st.skipped} skipped by filters` : \"\"} · last event ${ago(st.lastEventAt)}`,\n );\n if (st.recent.length) {\n out(pc.bold(\"Recent\"));\n for (const r of st.recent.slice(0, 8)) {\n const icon = r.outcome === \"succeeded\" ? pc.green(\"✓\") : r.outcome === \"dead\" ? pc.red(\"✖\") : r.outcome === \"retrying\" ? pc.yellow(\"↻\") : pc.gray(\"·\");\n out(` ${icon} #${r.seq} ${r.type} ${pc.gray(`${ago(r.at)}${r.attempts > 1 ? `, ${r.attempts} attempts` : \"\"}${r.error && r.outcome !== \"succeeded\" ? `, ${safeText(r.error, 100)}` : \"\"}`)}`);\n }\n }\n }\n out(`${pc.bold(\"Dead\")} ${dead.length ? pc.red(`${dead.length} event${dead.length > 1 ? \"s\" : \"\"}`) + pc.gray(` (inspect: ${NPX} listen dead${flagFor(name)})`) : \"0\"}`);\n out(`${pc.bold(\"Log\")} ${logPath(name)}`);\n}\n\n// ───────────── listen dead ─────────────\n\nexport function printDead(profileName: string, opts: { json?: boolean }): void {\n const name = validProfileName(profileName);\n const entries = readDead(name);\n if (opts.json) {\n for (const e of entries) out(JSON.stringify(e));\n return;\n }\n if (!entries.length) {\n out(`No dead events for profile \"${name}\".`);\n return;\n }\n for (const e of entries) {\n const m = e.payload.data.message;\n out(`${pc.red(\"✖\")} #${e.seq} ${e.type} ${pc.gray(e.id)} ${pc.gray(`died ${ago(e.deadAt)} after ${e.attempts} attempts`)}`);\n if (m) out(` from ${safeText(m.from?.email ?? \"?\", 80)} \"${safeText(m.subject, 80)}\"`);\n out(pc.gray(` ${safeText(e.error, 300)}`));\n }\n out();\n out(pc.gray(`${entries.length} dead event${entries.length > 1 ? \"s\" : \"\"} in ${deadPath(name)}.`));\n out(pc.gray(`Replay with: ${NPX} listen dead --replay${flagFor(name)} (one: --id <evt_…>; drop all: --clear)`));\n out(pc.gray(`Replay uses the profile's saved --exec/--forward; if you ran them as flags only, pass them again, e.g. --replay --exec '<command>'.`));\n}\n\nexport function clearDead(profileName: string, id?: string): void {\n const name = validProfileName(profileName);\n const entries = readDead(name);\n const keep = id ? entries.filter((e) => e.id !== id) : [];\n writeDead(name, keep);\n out(`Removed ${entries.length - keep.length} dead event${entries.length - keep.length === 1 ? \"\" : \"s\"}.`);\n}\n\n/**\n * Runs dead events again through the profile's targets (or the ones passed as flags). Successes are\n * removed from dead.jsonl; failures stay. Returns how many still failed.\n */\nexport async function replayDead(flags: ListenFlags & { id?: string }, opts: { retryDelayMs?: (n: number) => number } = {}): Promise<number> {\n const name = validProfileName(flags.profile ?? DEFAULT_PROFILE);\n const profile = loadProfile(name);\n const { config } = resolveListen(name, profile, { ...flags, save: false });\n const all = readDead(name);\n const chosen = all.filter((e) => !flags.id || e.id === flags.id);\n if (!chosen.length) {\n out(flags.id ? `No dead event with id ${flags.id}.` : `No dead events for profile \"${name}\".`);\n return 0;\n }\n const available: Target[] = [];\n if (config.exec) available.push(\"exec\");\n if (config.forward) available.push(\"forward\");\n if (!available.length) throw new Error(`Nothing to replay to: pass --recipe <tool> (claude-code, codex, cursor, hermes), --exec '<command>' and/or --forward <url> (or save them in the profile with \\`${NPX} listen --save …\\`).`);\n if (config.exec && process.platform === \"win32\") throw new Error(\"--exec isn't supported on Windows; replay with --forward instead.\");\n\n const timeoutMs = config.timeoutSeconds * 1000;\n if (config.cwdIsDefault) ensurePrivateDir(config.cwd);\n const failed = new Map<string, DeadEntry>();\n const bySeq = new Map(chosen.map((e) => [e.seq, e]));\n const dispatcher = new Dispatcher({\n targets: available,\n concurrency: config.concurrency,\n maxAttempts: config.maxAttempts,\n retryDelayMs: opts.retryDelayMs,\n run: async (job: Job, signal) => {\n const errors: string[] = [];\n if (job.remaining.has(\"exec\") && config.exec) {\n const r = await runCommand(config.exec, job.payload, { timeoutMs, signal, cwd: config.cwd });\n if (r.ok) job.remaining.delete(\"exec\");\n else errors.push(`command: ${r.error}`);\n }\n if (job.remaining.has(\"forward\") && config.forward) {\n const r = await forwardEvent(config.forward.url, config.forward.secret, job.payload, { timeoutMs: Math.min(timeoutMs, 30_000), signal, wrap: isHermesRoute(config.forward.url) });\n if (r.ok) job.remaining.delete(\"forward\");\n else errors.push(`forward: ${r.error}`);\n }\n return errors;\n },\n onAdvance: () => {},\n onDead: (job) => {\n const e = bySeq.get(job.seq)!;\n failed.set(e.id, { ...e, deadAt: new Date().toISOString(), attempts: e.attempts + job.attempts, error: job.lastError ?? \"failed\" });\n out(`${pc.red(\"✖\")} #${job.seq} still failing: ${safeText(job.lastError ?? \"failed\", 200)}`);\n },\n onFinished: (job) => {\n if (job.outcome === \"succeeded\") out(`${pc.green(\"✓\")} #${job.seq} ${job.payload.type} replayed`);\n },\n });\n out(`Replaying ${chosen.length} dead event${chosen.length > 1 ? \"s\" : \"\"} (up to ${config.maxAttempts} attempts each)…`);\n // Only the targets that never succeeded (a forward that went through isn't POSTed again).\n for (const e of [...chosen].sort((a, b) => a.seq - b.seq)) {\n const targets = e.targets?.length ? e.targets.filter((t) => available.includes(t)) : available;\n if (!targets.length) {\n out(`${pc.yellow(\"!\")} #${e.seq} needs ${e.targets.join(\" and \")}, which isn't configured now; pass --${e.targets[0]} to replay it.`);\n failed.set(e.id, e);\n continue;\n }\n dispatcher.push(e.payload, { targets });\n }\n await dispatcher.idle();\n\n const replayed = new Set(chosen.map((e) => e.id));\n // Re-read so entries added by a running listener meanwhile are kept.\n const current = readDead(name);\n writeDead(name, [...current.filter((e) => !replayed.has(e.id)), ...failed.values()]);\n out(`${chosen.length - failed.size} replayed, ${failed.size} still dead.`);\n return failed.size;\n}\n"],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -1,27 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import "./node-check-D6v5n6d2.js";
2
3
  import { existsSync, readFileSync, statSync } from "node:fs";
3
4
  import { homedir } from "node:os";
4
5
  import { join, resolve, sep } from "node:path";
5
- //#region server/node-check.ts
6
- /** The oldest Node.js agentinbox runs on (node:sqlite unflagged, import.meta.dirname). Keep in sync with package.json engines. */
7
- const MIN_NODE = "22.13.0";
8
- /** An explanation when `version` (e.g. process.versions.node) is too old, else null. */
9
- function nodeVersionError(version) {
10
- const parse = (v) => v.replace(/^v/, "").split(".").map((n) => Number.parseInt(n, 10) || 0);
11
- const have = parse(version);
12
- const need = parse(MIN_NODE);
13
- for (let i = 0; i < 3; i++) {
14
- if ((have[i] ?? 0) > need[i]) return null;
15
- if ((have[i] ?? 0) < need[i]) return `agentinbox needs Node.js 22.13 or newer (you have ${version.replace(/^v?/, "v")}). Install a current Node.js from https://nodejs.org and try again.`;
16
- }
17
- return null;
18
- }
19
- const problem = nodeVersionError(process.versions.node);
20
- if (problem) {
21
- console.error(problem);
22
- process.exit(1);
23
- }
24
- //#endregion
25
6
  //#region server/cli.ts
26
7
  const { Command, InvalidArgumentError } = await import("commander");
27
8
  const { default: pc } = await import("picocolors");
@@ -76,7 +57,7 @@ const SERVER_GROUP = "Run agentinbox:";
76
57
  const AGENT_GROUP = "On an agent's machine:";
77
58
  withServerOptions(program.command("start", { isDefault: true }).description("run agentinbox in this terminal and print the setup link (the default command)").summary("run it in this terminal (the default command)").helpGroup(SERVER_GROUP)).option("--no-open", "don't open a browser on first run").option("--dev", "development: API only, the console runs on Vite (:5173)").allowExcessArguments().action(async (o, cmd) => {
78
59
  if (cmd.args.length) throw new Error(unknownCommand(cmd.args[0]));
79
- const { runForeground } = await import("./server-8N5imyc2.js");
60
+ const { runForeground } = await import("./server-DiPOZSU8.js");
80
61
  await runForeground({
81
62
  ...configInput(o),
82
63
  dev: !!o.dev,
@@ -87,15 +68,15 @@ withServerOptions(program.command("start", { isDefault: true }).description("run
87
68
  const service = program.command("service").description("run agentinbox in the background as a systemd / launchd service, started at boot").summary("run it in the background (systemd / launchd)").helpGroup(SERVER_GROUP);
88
69
  withServerOptions(service.command("install").description("install and start the service; re-run it to change the port or update")).action(async (o) => {
89
70
  const { loadConfig } = await import("./config-DCuYmK68.js");
90
- const { installService } = await import("./service-DkVpScAM.js");
71
+ const { installService } = await import("./service-D75izPEj.js");
91
72
  await installService(loadConfig(configInput(o), version));
92
73
  });
93
74
  service.command("uninstall").description("stop and remove the service (keeps your data)").option("-d, --data <dir>", "data directory, if the installed service doesn't say (default ~/.agentinbox, env AGENTINBOX_DATA)").action(async (o) => {
94
- const { uninstallService } = await import("./service-DkVpScAM.js");
75
+ const { uninstallService } = await import("./service-D75izPEj.js");
95
76
  uninstallService({ dataDir: resolve(o.data ?? process.env.AGENTINBOX_DATA ?? join(homedir(), ".agentinbox")) });
96
77
  });
97
78
  service.command("status").description("show service status").action(async () => {
98
- const { serviceStatus } = await import("./service-DkVpScAM.js");
79
+ const { serviceStatus } = await import("./service-D75izPEj.js");
99
80
  serviceStatus();
100
81
  });
101
82
  const skill = program.command("skill").description("the agentinbox agent skill (SKILL.md): teaches an agent how to use agentinbox's tools").summary("install the agent skill (SKILL.md)").helpGroup(AGENT_GROUP);
@@ -151,7 +132,7 @@ program.command("reset-password").description("forgot the console password? Remo
151
132
  db.close();
152
133
  }
153
134
  });
154
- const { registerListenCommands } = await import("./commands-BRvw2jIt.js");
135
+ const { registerListenCommands } = await import("./commands-B1JRkH7_.js");
155
136
  registerListenCommands(program);
156
137
  const AGENT_SUMMARIES = {
157
138
  connect: "pair an agent; you approve it in the console",
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../server/node-check.ts","../server/cli.ts"],"sourcesContent":["/** The oldest Node.js agentinbox runs on (node:sqlite unflagged, import.meta.dirname). Keep in sync with package.json engines. */\nexport const MIN_NODE = \"22.13.0\";\n\n/** An explanation when `version` (e.g. process.versions.node) is too old, else null. */\nexport function nodeVersionError(version: string): string | null {\n const parse = (v: string) => v.replace(/^v/, \"\").split(\".\").map((n) => Number.parseInt(n, 10) || 0);\n const have = parse(version);\n const need = parse(MIN_NODE);\n for (let i = 0; i < 3; i++) {\n if ((have[i] ?? 0) > need[i]!) return null;\n if ((have[i] ?? 0) < need[i]!) return `agentinbox needs Node.js 22.13 or newer (you have ${version.replace(/^v?/, \"v\")}). Install a current Node.js from https://nodejs.org and try again.`;\n }\n return null;\n}\n\n// Runs on import, before anything that needs a newer Node is loaded.\nconst problem = nodeVersionError(process.versions.node);\nif (problem) {\n console.error(problem);\n process.exit(1);\n}\n","// Must stay the first import: exits with a clear message on a too-old Node.\nimport \"./node-check.ts\";\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport type { Command as CommandType } from \"commander\";\n\n// Loaded after the Node check (static imports are hoisted above it in the bundle).\nconst { Command, InvalidArgumentError } = await import(\"commander\");\nconst { default: pc } = await import(\"picocolors\");\n\nprocess.title = \"agentinbox\";\n\n// node:sqlite is stable enough for us but still warns on Node 22. This runs before any server\n// module loads: everything that touches node:sqlite is imported dynamically below.\nconst emitWarning = process.emitWarning.bind(process);\nprocess.emitWarning = ((warning: string | Error, ...rest: unknown[]) => {\n const message = typeof warning === \"string\" ? warning : warning.message;\n const type = typeof rest[0] === \"string\" ? rest[0] : (rest[0] as { type?: string } | undefined)?.type;\n if ((type === \"ExperimentalWarning\" || (warning as Error).name === \"ExperimentalWarning\") && /SQLite/i.test(message)) return;\n return (emitWarning as (...args: unknown[]) => void)(warning, ...rest);\n}) as typeof process.emitWarning;\n\n/** package.json sits one level above both dist/cli.js and server/cli.ts. */\nfunction packageVersion(): string {\n try {\n return (JSON.parse(readFileSync(join(import.meta.dirname, \"..\", \"package.json\"), \"utf8\")) as { version: string }).version;\n } catch {\n return \"0.0.0\";\n }\n}\n\nconst version = packageVersion();\n\ninterface ServerFlags {\n port?: number;\n host?: string;\n data?: string;\n}\n\nconst validPort = (value: string) => /^\\d+$/.test(value) && Number(value) <= 65535;\n\nfunction parsePort(value: string): number {\n if (!validPort(value)) throw new InvalidArgumentError(\"Port must be a number from 0 to 65535.\");\n return Number(value);\n}\n\n/** --port, else a validated PORT env (a typo there would otherwise become NaN deep inside). */\nfunction portOption(flag: number | undefined): number | undefined {\n if (flag !== undefined) return flag;\n const env = process.env.PORT?.trim();\n if (!env) return undefined;\n if (!validPort(env)) throw new Error(`PORT=\"${process.env.PORT}\" is not a valid port. Use a number from 0 to 65535.`);\n return Number(env);\n}\n\nconst withServerOptions = (cmd: CommandType) =>\n cmd\n .option(\"-p, --port <port>\", \"port to listen on (default 8425, env PORT)\", parsePort)\n .option(\"--host <host>\", \"bind address (default 0.0.0.0, env HOST)\")\n .option(\"-d, --data <dir>\", \"data directory (default ~/.agentinbox, env AGENTINBOX_DATA)\");\n\nconst configInput = (o: ServerFlags) => ({ port: portOption(o.port), host: o.host, dataDir: o.data });\n\nconst program = new Command(\"agentinbox\")\n .description(\n \"Self-hosted Gmail broker for AI agents. Start it, open the link it prints, and the web console \" +\n \"walks you through the rest (Google Cloud, connecting Gmail, your first agent).\",\n )\n .version(version, \"-v, --version\", \"print the version\")\n .helpOption(\"-h, --help\", \"show help\")\n .addHelpText(\n \"after\",\n `\nExamples:\n npx agentinbox-cli start the server and print the setup link\n npx agentinbox-cli service install keep it running in the background, also after a reboot\n npx agentinbox-cli reset-password print a new setup link (forgot the console password)\n npx agentinbox-cli connect https://mail.example.com --tool claude-code --setup-mcp\n on an agent's machine: pair it (you approve in the console)\n npx agentinbox-cli listen --recipe claude-code\n on an agent's machine: wake Claude Code on new mail\n\nRun any command with --help for details. Install it with npm i -g agentinbox-cli to type agentinbox instead.\nDocs: https://github.com/unlaboredlabs/agentinbox/blob/main/docs/reference.md`,\n )\n .showSuggestionAfterError();\n\nconst SERVER_GROUP = \"Run agentinbox:\";\nconst AGENT_GROUP = \"On an agent's machine:\";\n\nwithServerOptions(\n program\n .command(\"start\", { isDefault: true })\n .description(\"run agentinbox in this terminal and print the setup link (the default command)\")\n .summary(\"run it in this terminal (the default command)\")\n .helpGroup(SERVER_GROUP),\n)\n .option(\"--no-open\", \"don't open a browser on first run\")\n .option(\"--dev\", \"development: API only, the console runs on Vite (:5173)\")\n // `agentinbox typo` lands here as an extra argument: report it as the unknown command it is.\n .allowExcessArguments()\n .action(async (o: ServerFlags & { open: boolean; dev?: boolean }, cmd: CommandType) => {\n if (cmd.args.length) throw new Error(unknownCommand(cmd.args[0]!));\n const { runForeground } = await import(\"./server.ts\");\n await runForeground({ ...configInput(o), dev: !!o.dev, open: o.open, version });\n });\n\nconst service = program\n .command(\"service\")\n .description(\"run agentinbox in the background as a systemd / launchd service, started at boot\")\n .summary(\"run it in the background (systemd / launchd)\")\n .helpGroup(SERVER_GROUP);\n\nwithServerOptions(service.command(\"install\").description(\"install and start the service; re-run it to change the port or update\")).action(async (o: ServerFlags) => {\n const { loadConfig } = await import(\"./config.ts\");\n const { installService } = await import(\"./service.ts\");\n await installService(loadConfig(configInput(o), version));\n});\n\nservice\n .command(\"uninstall\")\n .description(\"stop and remove the service (keeps your data)\")\n .option(\"-d, --data <dir>\", \"data directory, if the installed service doesn't say (default ~/.agentinbox, env AGENTINBOX_DATA)\")\n .action(async (o: ServerFlags) => {\n const { uninstallService } = await import(\"./service.ts\");\n // No loadConfig: uninstalling must not create a data directory.\n uninstallService({ dataDir: resolve(o.data ?? process.env.AGENTINBOX_DATA ?? join(homedir(), \".agentinbox\")) });\n });\n\nservice\n .command(\"status\")\n .description(\"show service status\")\n .action(async () => {\n const { serviceStatus } = await import(\"./service.ts\");\n serviceStatus();\n });\n\nconst skill = program\n .command(\"skill\")\n .description(\"the agentinbox agent skill (SKILL.md): teaches an agent how to use agentinbox's tools\")\n .summary(\"install the agent skill (SKILL.md)\")\n .helpGroup(AGENT_GROUP);\n\nskill\n .command(\"print\")\n .description(\"print SKILL.md to stdout\")\n .option(\"--url <url>\", \"agentinbox server URL to fill in (env AGENTINBOX_URL)\")\n .action(async (o: { url?: string }) => {\n const { renderSkill } = await import(\"./skill/index.ts\");\n process.stdout.write(renderSkill(await serverUrl(o.url)));\n });\n\nskill\n .command(\"install\")\n .description(\"install SKILL.md for an agent (no running server needed)\")\n .option(\"-t, --target <target>\", \"claude, codex, agents, or a skills directory path\", \"claude\")\n .option(\"--url <url>\", \"agentinbox server URL agents connect to (env AGENTINBOX_URL)\")\n .action(async (o: { target: string; url?: string }) => {\n const { renderSkill, SKILL_TARGETS, skillPath, writeSkill } = await import(\"./skill/index.ts\");\n checkSkillTarget(o.target, Object.keys(SKILL_TARGETS));\n const url = await serverUrl(o.url);\n const path = skillPath(o.target);\n writeSkill(path, renderSkill(url));\n console.log(`Installed the agentinbox skill to ${pc.cyan(path)} (server ${url}).`);\n if (!o.url && !process.env.AGENTINBOX_URL) {\n console.log(pc.dim(\"Agents on other machines need the server's address: re-run with --url https://your-server.\"));\n }\n });\n\nprogram\n .command(\"reset-password\")\n .description(\"forgot the console password? Removes it and prints a new setup link (or the first-run link)\")\n .summary(\"print a new setup link (forgot the password?)\")\n .helpGroup(SERVER_GROUP)\n .option(\"-d, --data <dir>\", \"data directory (default ~/.agentinbox, env AGENTINBOX_DATA)\")\n .option(\"-p, --port <port>\", \"port of the running instance, used for the printed link\", parsePort)\n .option(\"--host <host>\", \"host of the running instance, used for the printed link\")\n .action(\n async (o: ServerFlags) => {\n // Never create a data directory or master key here: a wrong --data (or a service running as\n // another user) must not silently produce a fresh instance.\n const dataDir = resolve(o.data ?? process.env.AGENTINBOX_DATA ?? join(homedir(), \".agentinbox\"));\n const dbPath = join(dataDir, \"agentinbox.db\");\n if (!existsSync(dbPath)) {\n throw new Error(\n `No agentinbox data in ${dataDir}. If agentinbox runs as a system service, run this with sudo; ` +\n \"otherwise pass the data directory it uses with --data.\",\n );\n }\n const { loadConfig } = await import(\"./config.ts\");\n const { Db } = await import(\"./db/index.ts\");\n const { createBus } = await import(\"./bus.ts\");\n const { SettingsStore } = await import(\"./settings.ts\");\n const { AuditLog } = await import(\"./audit.ts\");\n const { currentSetupToken, isClaimed, resetAdminPassword } = await import(\"./auth/index.ts\");\n const { runningInstance } = await import(\"./instance.ts\");\n const { consoleUrls } = await import(\"./urls.ts\");\n\n const running = runningInstance(dataDir);\n const config = loadConfig(\n { dataDir, port: portOption(o.port) ?? running?.port, host: o.host ?? (process.env.HOST || running?.host) },\n version,\n );\n const db = new Db(dbPath);\n try {\n const bus = createBus();\n const core = { config, db, settings: new SettingsStore(db, bus, config), audit: new AuditLog(db, bus) };\n const claimed = isClaimed(core);\n const token = claimed ? resetAdminPassword(core) : currentSetupToken(core)!;\n console.log(\n claimed\n ? \"\\n The admin password was removed and all console sessions were signed out.\\n Open this link to set a new password:\\n\"\n : \"\\n This instance hasn't been claimed yet, so there is no password to reset.\\n Open this link to claim it:\\n\",\n );\n const urls = consoleUrls(config.host, config.port);\n const publicUrl = core.settings.publicUrl();\n if (!urls.includes(publicUrl)) urls.push(publicUrl);\n for (const url of urls) console.log(` ${pc.cyan(`${url}/setup?token=${token}`)}`);\n console.log(pc.dim(`\\n ${running ? \"The running agentinbox picks this up immediately; no restart needed.\" : \"Start agentinbox to use it.\"}\\n`));\n } finally {\n db.close();\n }\n },\n);\n\n// Agent side: `connect` (device-flow pairing), `setup-mcp`, `mcp-header` and `listen …` (see\n// docs/listen.md). Imported after the Node check, like everything else.\nconst { registerListenCommands } = await import(\"./listen/commands.ts\");\nregisterListenCommands(program);\n// Short one-liners for the command list; each command's own --help keeps its full description.\nconst AGENT_SUMMARIES: Record<string, string> = {\n connect: \"pair an agent; you approve it in the console\",\n \"setup-mcp\": \"add agentinbox to the agent's MCP config\",\n \"mcp-header\": \"print the agent's auth header (MCP clients)\",\n listen: \"wake the agent when new mail arrives\",\n};\nfor (const cmd of program.commands) {\n const summary = AGENT_SUMMARIES[cmd.name()];\n if (summary) cmd.summary(summary).helpGroup(AGENT_GROUP);\n}\nprogram.commandsGroup(SERVER_GROUP).helpCommand(\"help [command]\", \"show help for a command\").helpCommand(true);\n\n/**\n * The URL written into SKILL.md: --url, AGENTINBOX_URL, else the agentinbox running on this\n * machine (its lock file), else http://localhost:8425.\n */\nasync function serverUrl(flag: string | undefined): Promise<string> {\n let raw = flag ?? process.env.AGENTINBOX_URL;\n if (!raw) {\n const { runningInstance } = await import(\"./instance.ts\");\n const running = runningInstance(resolve(process.env.AGENTINBOX_DATA || join(homedir(), \".agentinbox\")));\n const host = running && ![\"0.0.0.0\", \"::\", \"\"].includes(running.host) ? running.host : \"localhost\";\n raw = `http://${host.includes(\":\") ? `[${host}]` : host}:${running?.port || process.env.PORT || 8425}`;\n }\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n throw new Error(`Invalid --url \"${raw}\". Use a full URL such as https://mail.example.com.`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") throw new Error(\"--url must start with http:// or https://\");\n return (url.origin + url.pathname).replace(/\\/+$/, \"\");\n}\n\n/** A known agent name, or something that is clearly a path; typos like \"claud\" are refused. */\nfunction checkSkillTarget(target: string, known: string[]): void {\n if (known.includes(target) || target.includes(\"/\") || target.includes(sep) || target.startsWith(\".\") || isDir(target)) return;\n const near = closest(target, known);\n throw new Error(\n `Unknown skill target \"${target}\".${near ? ` Did you mean ${near}?` : \"\"} Use ${known.join(\", \")}, or a directory path such as ./skills.`,\n );\n}\n\nfunction isDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction unknownCommand(name: string): string {\n const near = closest(name, [...program.commands.map((c) => c.name()), \"help\"]);\n return `unknown command '${name}'${near ? `\\n(Did you mean ${near}?)` : \"\"}\\nRun agentinbox --help for the list of commands.`;\n}\n\n/** The candidate within edit distance 2 (or a prefix match), if any. */\nfunction closest(word: string, candidates: string[]): string | null {\n const distance = (a: string, b: string) => {\n const row = Array.from({ length: b.length + 1 }, (_, j) => j);\n for (let i = 1; i <= a.length; i++) {\n let prev = row[0]!;\n row[0] = i;\n for (let j = 1; j <= b.length; j++) {\n const cur = row[j]!;\n row[j] = Math.min(row[j]! + 1, row[j - 1]! + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));\n prev = cur;\n }\n }\n return row[b.length]!;\n };\n let best: { name: string; d: number } | null = null;\n for (const c of candidates) {\n const d = c.startsWith(word) && word.length >= 3 ? 0 : distance(word.toLowerCase(), c);\n if (d <= 2 && (!best || d < best.d)) best = { name: c, d };\n }\n return best?.name ?? null;\n}\n\ntry {\n await program.parseAsync(process.argv);\n} catch (err) {\n console.error(pc.red(err instanceof Error ? err.message : String(err)));\n if (process.env.AGENTINBOX_DEBUG && err instanceof Error) console.error(err.stack);\n process.exit(1);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../server/cli.ts"],"sourcesContent":["// Must stay the first import: exits with a clear message on a too-old Node.\nimport \"./node-check.ts\";\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport type { Command as CommandType } from \"commander\";\n\n// Loaded after the Node check (static imports are hoisted above it in the bundle).\nconst { Command, InvalidArgumentError } = await import(\"commander\");\nconst { default: pc } = await import(\"picocolors\");\n\nprocess.title = \"agentinbox\";\n\n// node:sqlite is stable enough for us but still warns on Node 22. This runs before any server\n// module loads: everything that touches node:sqlite is imported dynamically below.\nconst emitWarning = process.emitWarning.bind(process);\nprocess.emitWarning = ((warning: string | Error, ...rest: unknown[]) => {\n const message = typeof warning === \"string\" ? warning : warning.message;\n const type = typeof rest[0] === \"string\" ? rest[0] : (rest[0] as { type?: string } | undefined)?.type;\n if ((type === \"ExperimentalWarning\" || (warning as Error).name === \"ExperimentalWarning\") && /SQLite/i.test(message)) return;\n return (emitWarning as (...args: unknown[]) => void)(warning, ...rest);\n}) as typeof process.emitWarning;\n\n/** package.json sits one level above both dist/cli.js and server/cli.ts. */\nfunction packageVersion(): string {\n try {\n return (JSON.parse(readFileSync(join(import.meta.dirname, \"..\", \"package.json\"), \"utf8\")) as { version: string }).version;\n } catch {\n return \"0.0.0\";\n }\n}\n\nconst version = packageVersion();\n\ninterface ServerFlags {\n port?: number;\n host?: string;\n data?: string;\n}\n\nconst validPort = (value: string) => /^\\d+$/.test(value) && Number(value) <= 65535;\n\nfunction parsePort(value: string): number {\n if (!validPort(value)) throw new InvalidArgumentError(\"Port must be a number from 0 to 65535.\");\n return Number(value);\n}\n\n/** --port, else a validated PORT env (a typo there would otherwise become NaN deep inside). */\nfunction portOption(flag: number | undefined): number | undefined {\n if (flag !== undefined) return flag;\n const env = process.env.PORT?.trim();\n if (!env) return undefined;\n if (!validPort(env)) throw new Error(`PORT=\"${process.env.PORT}\" is not a valid port. Use a number from 0 to 65535.`);\n return Number(env);\n}\n\nconst withServerOptions = (cmd: CommandType) =>\n cmd\n .option(\"-p, --port <port>\", \"port to listen on (default 8425, env PORT)\", parsePort)\n .option(\"--host <host>\", \"bind address (default 0.0.0.0, env HOST)\")\n .option(\"-d, --data <dir>\", \"data directory (default ~/.agentinbox, env AGENTINBOX_DATA)\");\n\nconst configInput = (o: ServerFlags) => ({ port: portOption(o.port), host: o.host, dataDir: o.data });\n\nconst program = new Command(\"agentinbox\")\n .description(\n \"Self-hosted Gmail broker for AI agents. Start it, open the link it prints, and the web console \" +\n \"walks you through the rest (Google Cloud, connecting Gmail, your first agent).\",\n )\n .version(version, \"-v, --version\", \"print the version\")\n .helpOption(\"-h, --help\", \"show help\")\n .addHelpText(\n \"after\",\n `\nExamples:\n npx agentinbox-cli start the server and print the setup link\n npx agentinbox-cli service install keep it running in the background, also after a reboot\n npx agentinbox-cli reset-password print a new setup link (forgot the console password)\n npx agentinbox-cli connect https://mail.example.com --tool claude-code --setup-mcp\n on an agent's machine: pair it (you approve in the console)\n npx agentinbox-cli listen --recipe claude-code\n on an agent's machine: wake Claude Code on new mail\n\nRun any command with --help for details. Install it with npm i -g agentinbox-cli to type agentinbox instead.\nDocs: https://github.com/unlaboredlabs/agentinbox/blob/main/docs/reference.md`,\n )\n .showSuggestionAfterError();\n\nconst SERVER_GROUP = \"Run agentinbox:\";\nconst AGENT_GROUP = \"On an agent's machine:\";\n\nwithServerOptions(\n program\n .command(\"start\", { isDefault: true })\n .description(\"run agentinbox in this terminal and print the setup link (the default command)\")\n .summary(\"run it in this terminal (the default command)\")\n .helpGroup(SERVER_GROUP),\n)\n .option(\"--no-open\", \"don't open a browser on first run\")\n .option(\"--dev\", \"development: API only, the console runs on Vite (:5173)\")\n // `agentinbox typo` lands here as an extra argument: report it as the unknown command it is.\n .allowExcessArguments()\n .action(async (o: ServerFlags & { open: boolean; dev?: boolean }, cmd: CommandType) => {\n if (cmd.args.length) throw new Error(unknownCommand(cmd.args[0]!));\n const { runForeground } = await import(\"./server.ts\");\n await runForeground({ ...configInput(o), dev: !!o.dev, open: o.open, version });\n });\n\nconst service = program\n .command(\"service\")\n .description(\"run agentinbox in the background as a systemd / launchd service, started at boot\")\n .summary(\"run it in the background (systemd / launchd)\")\n .helpGroup(SERVER_GROUP);\n\nwithServerOptions(service.command(\"install\").description(\"install and start the service; re-run it to change the port or update\")).action(async (o: ServerFlags) => {\n const { loadConfig } = await import(\"./config.ts\");\n const { installService } = await import(\"./service.ts\");\n await installService(loadConfig(configInput(o), version));\n});\n\nservice\n .command(\"uninstall\")\n .description(\"stop and remove the service (keeps your data)\")\n .option(\"-d, --data <dir>\", \"data directory, if the installed service doesn't say (default ~/.agentinbox, env AGENTINBOX_DATA)\")\n .action(async (o: ServerFlags) => {\n const { uninstallService } = await import(\"./service.ts\");\n // No loadConfig: uninstalling must not create a data directory.\n uninstallService({ dataDir: resolve(o.data ?? process.env.AGENTINBOX_DATA ?? join(homedir(), \".agentinbox\")) });\n });\n\nservice\n .command(\"status\")\n .description(\"show service status\")\n .action(async () => {\n const { serviceStatus } = await import(\"./service.ts\");\n serviceStatus();\n });\n\nconst skill = program\n .command(\"skill\")\n .description(\"the agentinbox agent skill (SKILL.md): teaches an agent how to use agentinbox's tools\")\n .summary(\"install the agent skill (SKILL.md)\")\n .helpGroup(AGENT_GROUP);\n\nskill\n .command(\"print\")\n .description(\"print SKILL.md to stdout\")\n .option(\"--url <url>\", \"agentinbox server URL to fill in (env AGENTINBOX_URL)\")\n .action(async (o: { url?: string }) => {\n const { renderSkill } = await import(\"./skill/index.ts\");\n process.stdout.write(renderSkill(await serverUrl(o.url)));\n });\n\nskill\n .command(\"install\")\n .description(\"install SKILL.md for an agent (no running server needed)\")\n .option(\"-t, --target <target>\", \"claude, codex, agents, or a skills directory path\", \"claude\")\n .option(\"--url <url>\", \"agentinbox server URL agents connect to (env AGENTINBOX_URL)\")\n .action(async (o: { target: string; url?: string }) => {\n const { renderSkill, SKILL_TARGETS, skillPath, writeSkill } = await import(\"./skill/index.ts\");\n checkSkillTarget(o.target, Object.keys(SKILL_TARGETS));\n const url = await serverUrl(o.url);\n const path = skillPath(o.target);\n writeSkill(path, renderSkill(url));\n console.log(`Installed the agentinbox skill to ${pc.cyan(path)} (server ${url}).`);\n if (!o.url && !process.env.AGENTINBOX_URL) {\n console.log(pc.dim(\"Agents on other machines need the server's address: re-run with --url https://your-server.\"));\n }\n });\n\nprogram\n .command(\"reset-password\")\n .description(\"forgot the console password? Removes it and prints a new setup link (or the first-run link)\")\n .summary(\"print a new setup link (forgot the password?)\")\n .helpGroup(SERVER_GROUP)\n .option(\"-d, --data <dir>\", \"data directory (default ~/.agentinbox, env AGENTINBOX_DATA)\")\n .option(\"-p, --port <port>\", \"port of the running instance, used for the printed link\", parsePort)\n .option(\"--host <host>\", \"host of the running instance, used for the printed link\")\n .action(\n async (o: ServerFlags) => {\n // Never create a data directory or master key here: a wrong --data (or a service running as\n // another user) must not silently produce a fresh instance.\n const dataDir = resolve(o.data ?? process.env.AGENTINBOX_DATA ?? join(homedir(), \".agentinbox\"));\n const dbPath = join(dataDir, \"agentinbox.db\");\n if (!existsSync(dbPath)) {\n throw new Error(\n `No agentinbox data in ${dataDir}. If agentinbox runs as a system service, run this with sudo; ` +\n \"otherwise pass the data directory it uses with --data.\",\n );\n }\n const { loadConfig } = await import(\"./config.ts\");\n const { Db } = await import(\"./db/index.ts\");\n const { createBus } = await import(\"./bus.ts\");\n const { SettingsStore } = await import(\"./settings.ts\");\n const { AuditLog } = await import(\"./audit.ts\");\n const { currentSetupToken, isClaimed, resetAdminPassword } = await import(\"./auth/index.ts\");\n const { runningInstance } = await import(\"./instance.ts\");\n const { consoleUrls } = await import(\"./urls.ts\");\n\n const running = runningInstance(dataDir);\n const config = loadConfig(\n { dataDir, port: portOption(o.port) ?? running?.port, host: o.host ?? (process.env.HOST || running?.host) },\n version,\n );\n const db = new Db(dbPath);\n try {\n const bus = createBus();\n const core = { config, db, settings: new SettingsStore(db, bus, config), audit: new AuditLog(db, bus) };\n const claimed = isClaimed(core);\n const token = claimed ? resetAdminPassword(core) : currentSetupToken(core)!;\n console.log(\n claimed\n ? \"\\n The admin password was removed and all console sessions were signed out.\\n Open this link to set a new password:\\n\"\n : \"\\n This instance hasn't been claimed yet, so there is no password to reset.\\n Open this link to claim it:\\n\",\n );\n const urls = consoleUrls(config.host, config.port);\n const publicUrl = core.settings.publicUrl();\n if (!urls.includes(publicUrl)) urls.push(publicUrl);\n for (const url of urls) console.log(` ${pc.cyan(`${url}/setup?token=${token}`)}`);\n console.log(pc.dim(`\\n ${running ? \"The running agentinbox picks this up immediately; no restart needed.\" : \"Start agentinbox to use it.\"}\\n`));\n } finally {\n db.close();\n }\n },\n);\n\n// Agent side: `connect` (device-flow pairing), `setup-mcp`, `mcp-header` and `listen …` (see\n// docs/listen.md). Imported after the Node check, like everything else.\nconst { registerListenCommands } = await import(\"./listen/commands.ts\");\nregisterListenCommands(program);\n// Short one-liners for the command list; each command's own --help keeps its full description.\nconst AGENT_SUMMARIES: Record<string, string> = {\n connect: \"pair an agent; you approve it in the console\",\n \"setup-mcp\": \"add agentinbox to the agent's MCP config\",\n \"mcp-header\": \"print the agent's auth header (MCP clients)\",\n listen: \"wake the agent when new mail arrives\",\n};\nfor (const cmd of program.commands) {\n const summary = AGENT_SUMMARIES[cmd.name()];\n if (summary) cmd.summary(summary).helpGroup(AGENT_GROUP);\n}\nprogram.commandsGroup(SERVER_GROUP).helpCommand(\"help [command]\", \"show help for a command\").helpCommand(true);\n\n/**\n * The URL written into SKILL.md: --url, AGENTINBOX_URL, else the agentinbox running on this\n * machine (its lock file), else http://localhost:8425.\n */\nasync function serverUrl(flag: string | undefined): Promise<string> {\n let raw = flag ?? process.env.AGENTINBOX_URL;\n if (!raw) {\n const { runningInstance } = await import(\"./instance.ts\");\n const running = runningInstance(resolve(process.env.AGENTINBOX_DATA || join(homedir(), \".agentinbox\")));\n const host = running && ![\"0.0.0.0\", \"::\", \"\"].includes(running.host) ? running.host : \"localhost\";\n raw = `http://${host.includes(\":\") ? `[${host}]` : host}:${running?.port || process.env.PORT || 8425}`;\n }\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n throw new Error(`Invalid --url \"${raw}\". Use a full URL such as https://mail.example.com.`);\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") throw new Error(\"--url must start with http:// or https://\");\n return (url.origin + url.pathname).replace(/\\/+$/, \"\");\n}\n\n/** A known agent name, or something that is clearly a path; typos like \"claud\" are refused. */\nfunction checkSkillTarget(target: string, known: string[]): void {\n if (known.includes(target) || target.includes(\"/\") || target.includes(sep) || target.startsWith(\".\") || isDir(target)) return;\n const near = closest(target, known);\n throw new Error(\n `Unknown skill target \"${target}\".${near ? ` Did you mean ${near}?` : \"\"} Use ${known.join(\", \")}, or a directory path such as ./skills.`,\n );\n}\n\nfunction isDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction unknownCommand(name: string): string {\n const near = closest(name, [...program.commands.map((c) => c.name()), \"help\"]);\n return `unknown command '${name}'${near ? `\\n(Did you mean ${near}?)` : \"\"}\\nRun agentinbox --help for the list of commands.`;\n}\n\n/** The candidate within edit distance 2 (or a prefix match), if any. */\nfunction closest(word: string, candidates: string[]): string | null {\n const distance = (a: string, b: string) => {\n const row = Array.from({ length: b.length + 1 }, (_, j) => j);\n for (let i = 1; i <= a.length; i++) {\n let prev = row[0]!;\n row[0] = i;\n for (let j = 1; j <= b.length; j++) {\n const cur = row[j]!;\n row[j] = Math.min(row[j]! + 1, row[j - 1]! + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));\n prev = cur;\n }\n }\n return row[b.length]!;\n };\n let best: { name: string; d: number } | null = null;\n for (const c of candidates) {\n const d = c.startsWith(word) && word.length >= 3 ? 0 : distance(word.toLowerCase(), c);\n if (d <= 2 && (!best || d < best.d)) best = { name: c, d };\n }\n return best?.name ?? null;\n}\n\ntry {\n await program.parseAsync(process.argv);\n} catch (err) {\n console.error(pc.red(err instanceof Error ? err.message : String(err)));\n if (process.env.AGENTINBOX_DEBUG && err instanceof Error) console.error(err.stack);\n process.exit(1);\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { r as EVENT_TYPES } from "./types-2rItLIhH.js";
3
- import { d as NPX } from "./profile-C1u9BrI8.js";
3
+ import { d as NPX } from "./profile-BqGV-DOU.js";
4
+ import { o as TOOLS, r as RECIPE_NAMES, y as recipesHelp } from "./recipes-Cw2ShA42.js";
4
5
  import { t as DEFAULT_PROFILE } from "./paths-DckASYtc.js";
5
- import { c as recipesHelp, n as TOOLS, t as RECIPE_TOOLS } from "./recipes-U2teSD6l.js";
6
6
  import { InvalidArgumentError } from "commander";
7
7
  //#region server/listen/commands.ts
8
8
  /** `agentinbox connect`, `agentinbox setup-mcp` and `agentinbox listen …`, all lazily loaded. */
@@ -18,7 +18,39 @@ const int = (name) => (value) => {
18
18
  };
19
19
  const profileOption = (cmd) => cmd.option("--profile <name>", `profile to use (default "${DEFAULT_PROFILE}")`);
20
20
  function listenFlags(cmd) {
21
- return profileOption(cmd).option("--exec <command>", "run this command for each event (via /bin/sh; the event arrives on stdin as JSON, never in the command)").option("--recipe <tool>", `run the built-in command for ${RECIPE_TOOLS.join(", ")} (instead of --exec; see it with --print-recipe)`).option("--forward <url>", "POST each event to this localhost URL, signed per Standard Webhooks").option("--types <list>", `comma-separated event types, or "all" (default: message.received, new mail only; also ${EVENT_TYPES.filter((t) => t !== "message.received").join(", ")})`).option("--from <glob>", "only senders matching this glob, e.g. \"*@stripe.com\" (repeatable)", collect).option("--to <glob>", "only when a to/cc address matches (repeatable)", collect).option("--label <id>", "only messages with this Gmail label id, e.g. INBOX or Label_123 (repeatable)", collect).option("--subject <regex>", "only subjects matching this case-insensitive regular expression").option("--include-body", "include the cleaned message body in each event").option("--no-include-body", "don't include bodies (overrides a saved setting)").option("--concurrency <n>", "events handled at once (default 2)", int("--concurrency")).option("--timeout <seconds>", "per-event time limit; the whole process group is killed after it (default 300)", int("--timeout")).option("--max-attempts <n>", "attempts before an event goes to dead letters (default 5)", int("--max-attempts")).option("--consumer <name>", "server-side cursor name (default <hostname>-<profile>)").option("--cwd <dir>", "directory --exec commands run in (default: a private dir in the state dir; must be yours and not group/world-writable)").option("--insecure", "allow plain http to a non-loopback, non-Tailscale daemon (loud warning)").option("--save", "save these settings to the profile");
21
+ return profileOption(cmd).option("--exec <command>", "run this command for each event (via /bin/sh; the event arrives on stdin as JSON, never in the command)").option("--recipe <name>", `use a built-in target: ${RECIPE_NAMES.join(", ")} (hermes forwards to your Hermes gateway; see it with --print-recipe)`).option("--forward <url>", "POST each event to this localhost URL, signed per Standard Webhooks").option("--types <list>", `comma-separated event types, or "all" (default: message.received, new mail only; also ${EVENT_TYPES.filter((t) => t !== "message.received").join(", ")})`).option("--from <glob>", "only senders matching this glob, e.g. \"*@stripe.com\" (repeatable)", collect).option("--to <glob>", "only when a to/cc address matches (repeatable)", collect).option("--label <id>", "only messages with this Gmail label id, e.g. INBOX or Label_123 (repeatable)", collect).option("--subject <regex>", "only subjects matching this case-insensitive regular expression").option("--not-from <glob>", "skip senders matching this glob, e.g. \"*@github.com\" (repeatable; --not-from \"\" --save clears saved exclusions)", collect).option("--not-label <id>", "skip messages with this Gmail label id, e.g. CATEGORY_UPDATES (repeatable)", collect).option("--all-categories", "don't skip Gmail's Promotions, Social and Forums tabs (skipped by default)").option("--include-category <name>", "take one category back from the default skip: promotions, social or forums (repeatable)", collect).option("--default-categories", "back to the default: skip Promotions, Social and Forums (undoes a saved --all-categories / --include-category)").option("--batch <duration>", `collect events this long (e.g. 60s, 2m) and run --exec once for all of them (up to 20); 0 turns it off`).option("--include-body", "include the cleaned message body in each event").option("--no-include-body", "don't include bodies (overrides a saved setting)").option("--concurrency <n>", "events handled at once (default 2)", int("--concurrency")).option("--timeout <seconds>", "per-event time limit; the whole process group is killed after it (default 300)", int("--timeout")).option("--max-attempts <n>", "attempts before an event goes to dead letters (default 5)", int("--max-attempts")).option("--consumer <name>", "server-side cursor name (default <hostname>-<profile>)").option("--cwd <dir>", "directory --exec commands run in (default: a private dir in the state dir; must be yours and not group/world-writable)").option("--insecure", "allow plain http to a non-loopback, non-Tailscale daemon (loud warning)").option("--save", "save these settings to the profile");
22
+ }
23
+ /** `listen hermes --help`. */
24
+ function hermesHelp() {
25
+ return `
26
+ --recipe hermes forwards each event to your running Hermes gateway (http://127.0.0.1:8644/webhooks/agentinbox; for
27
+ another profile the route is agentinbox-<profile>). Hermes verifies the Standard Webhooks signature with the
28
+ listener's secret, runs the triage, and delivers the result where this route says. Mail that isn't important gets
29
+ a [SILENT] reply, which Hermes doesn't deliver.
30
+
31
+ A Hermes webhook run normally gets web tools (web_search, web_extract, vision_analyze, clarify) and every MCP
32
+ server enabled in Hermes: with email as the trigger, an attacker could make it read your mail and send it out.
33
+ --run therefore also limits the route to the agentinbox MCP server ("toolsets": ["mcp-agentinbox"] in
34
+ webhook_subscriptions.json, which \`hermes webhook subscribe\` can't set). That limit only holds when agentinbox is an
35
+ enabled MCP server in Hermes' config.yaml (else Hermes adds every MCP server), so this refuses until
36
+ \`${NPX} setup-mcp --tool hermes\` has added it. --run creates the route disabled with the real secret under Hermes'
37
+ lock (python3), runs \`hermes webhook subscribe\` without --secret (hermes keeps the secret and the disabled state),
38
+ then sets the toolsets and enables it. The secret is never in a command line, the route never runs unconfined, and
39
+ any failure removes it again. Re-run it after any \`hermes webhook subscribe\` for this route (that resets the
40
+ toolsets). The Hermes home follows HERMES_HOME or Hermes' sticky active_profile.
41
+
42
+ Without --run it prints both steps for you to do by hand; the toolsets edit is required.
43
+
44
+ --cron-job hands the email to that job's own tools, so it is accepted only when the job's enabled_toolsets is
45
+ exactly ["agentinbox"] (the bare server name; "mcp-agentinbox" doesn't narrow MCP servers for cron jobs).
46
+
47
+ Needs python3, the gateway's webhook platform (hermes gateway setup, or WEBHOOK_ENABLED=true in ~/.hermes/.env) and
48
+ a running gateway. Check it: curl http://127.0.0.1:8644/health
49
+
50
+ Examples:
51
+ ${NPX} listen hermes --deliver telegram --run
52
+ ${NPX} listen hermes --cron-job email-watch --run # only for a job limited to ["agentinbox"]
53
+ ${NPX} listen service install --recipe hermes`;
22
54
  }
23
55
  /** `setup-mcp --help`: exactly what it changes, per tool. */
24
56
  function mcpSetupHelp() {
@@ -48,19 +80,19 @@ Exit codes: 0 approved, 2 denied, 3 expired, 4 already consumed, 130 cancelled,
48
80
 
49
81
  Example:
50
82
  ${NPX} connect https://mail.example.com --tool claude-code --setup-mcp`).action(async (url, flags) => {
51
- const { runConnect } = await import("./connect-DR3YrwvV.js");
83
+ const { runConnect } = await import("./connect-DbfCEHOf.js");
52
84
  process.exit(await runConnect(url, flags, { handleSignals: true }));
53
85
  });
54
86
  profileOption(program.command("setup-mcp").description("register the agentinbox MCP server in your agent's tool, without showing the key")).option("--tool <tool>", `${TOOLS.filter((t) => t !== "other").join(", ")} (default: the tool given to connect)`).option("--dry-run", "print the exact commands and file changes, and change nothing").addHelpText("after", mcpSetupHelp()).action(async (flags) => {
55
- const { parseTool, printMcpResult } = await import("./connect-DR3YrwvV.js");
56
- const { loadProfile } = await import("./profile-BL6jqiTB.js");
57
- const { setupMcp, mcpTarget } = await import("./mcpsetup-CPxIa7U3.js");
87
+ const { parseTool, printMcpResult } = await import("./connect-DbfCEHOf.js");
88
+ const { loadProfile } = await import("./profile-C38suDkJ.js");
89
+ const { setupMcp, mcpTarget } = await import("./mcpsetup-RpaNjEw_.js");
58
90
  const { profilePath } = await import("./paths-BMavi0Uq.js");
59
91
  const name = flags.profile ?? "default";
60
92
  const profile = loadProfile(name);
61
93
  const tool = flags.tool ? parseTool(flags.tool) : profile.tool ?? "other";
62
94
  if (tool === "other") throw new Error(`Which tool? Pass --tool ${TOOLS.filter((t) => t !== "other").join("|")}.`);
63
- const { claudeMcpConfigPath, writeClaudeMcpConfig } = await import("./mcpheader-H0mMJYYw.js");
95
+ const { claudeMcpConfigPath, writeClaudeMcpConfig } = await import("./mcpheader-BNjmjI1b.js");
64
96
  const r = setupMcp(tool, mcpTarget(name, profile), profilePath(name), { dryRun: flags.dryRun });
65
97
  if (flags.dryRun) r.changes = [...r.changes ?? [], `refresh ${claudeMcpConfigPath(name)} (keyless MCP config the Claude Code listen recipe loads)`];
66
98
  else writeClaudeMcpConfig(name, `${profile.url}/mcp`);
@@ -68,17 +100,18 @@ Example:
68
100
  if (!r.ok) process.exitCode = 1;
69
101
  });
70
102
  profileOption(program.command("mcp-header").description("print the agent's Authorization header as JSON for an MCP client's header helper (refuses to print to a terminal)")).action(async (flags) => {
71
- const { printMcpHeader } = await import("./mcpheader-H0mMJYYw.js");
103
+ const { printMcpHeader } = await import("./mcpheader-BNjmjI1b.js");
72
104
  process.exitCode = printMcpHeader(flags.profile ?? "default");
73
105
  });
74
- const listen = listenFlags(program.command("listen").description("wake a local agent on new mail: hold an outbound stream to the daemon and run a command or POST to localhost per event")).option("--dry-run", "print matching events without running anything (uses a throwaway <consumer>-dry-run cursor)").option("--from-start", "a NEW consumer starts at the oldest stored event (no effect once it exists: use --backfill)").option("--backfill", "run the mail from before this listener started through --exec/--forward once, oldest first, then exit; safe while the listener runs (own cursor)").option("--until <seq>", "with --backfill: replay up to this event number instead of where the listener started", int("--until")).option("--print-recipe <tool>", `print the command --recipe <tool> runs, for ${RECIPE_TOOLS.join(", ")} (with this machine's paths), and exit`).addHelpText("after", recipesHelp()).action(async (flags) => {
106
+ const listen = listenFlags(program.command("listen").description("wake a local agent on new mail: hold an outbound stream to the daemon and run a command or POST to localhost per event")).option("--dry-run", "print matching events without running anything (uses a throwaway <consumer>-dry-run cursor)").option("--from-start", "a NEW consumer starts at the oldest stored event (no effect once it exists: use --backfill)").option("--backfill", "run the mail from before this listener started through --exec/--forward once, oldest first, then exit; safe while the listener runs (own cursor)").option("--until <seq>", "with --backfill: replay up to this event number instead of where the listener started", int("--until")).option("--print-recipe <name>", `print what --recipe <name> runs (hermes: its URL), for ${RECIPE_NAMES.join(", ")} (with this machine's paths), and exit`).addHelpText("after", recipesHelp()).action(async (flags) => {
75
107
  if (flags.printRecipe !== void 0) {
76
- const { parseTool } = await import("./connect-DR3YrwvV.js");
77
- const { recipe } = await import("./recipes-Bn3ttR3i.js");
78
- process.stdout.write(`${recipe(parseTool(flags.printRecipe), flags.profile ?? "default").exec}\n`);
108
+ const { parseRecipeTool, recipe } = await import("./recipes-DlhXH1O8.js");
109
+ const name = flags.printRecipe.trim().toLowerCase();
110
+ const r = recipe(name === "other" ? "other" : parseRecipeTool(name), flags.profile ?? "default");
111
+ process.stdout.write(`${r.exec ?? r.forward}\n`);
79
112
  return;
80
113
  }
81
- const { runListener } = await import("./listen-Cjsv8Gwy.js");
114
+ const { runListener } = await import("./listen-K5SDQlRA.js");
82
115
  process.exit(await runListener({
83
116
  flags,
84
117
  handleSignals: true
@@ -86,17 +119,22 @@ Example:
86
119
  });
87
120
  profileOption(listen.command("status").description("show the listener's connection, cursor, recent events and dead letters")).action(async (_o, cmd) => {
88
121
  const flags = all(cmd);
89
- const { printStatus } = await import("./admin-CCIR1XvZ.js");
122
+ const { printStatus } = await import("./admin-B-e0fGL8.js");
90
123
  await printStatus(flags.profile ?? "default");
91
124
  });
92
125
  profileOption(listen.command("secret").description("print the forward-mode signing secret (whsec_…) for your local receiver")).option("--rotate", "generate a new secret (restart the listener afterwards)").action(async (_o, cmd) => {
93
126
  const flags = all(cmd);
94
- const { printSecret } = await import("./admin-CCIR1XvZ.js");
127
+ const { printSecret } = await import("./admin-B-e0fGL8.js");
95
128
  printSecret(flags.profile ?? "default", flags);
96
129
  });
130
+ profileOption(listen.command("hermes").description("create the Hermes gateway webhook route that --recipe hermes forwards to, limited to the agentinbox tools")).option("--deliver <target>", "where Hermes sends its triage: telegram, discord, slack… (a platform connected to your gateway), or log").option("--deliver-chat-id <id>", "with --deliver: a specific chat instead of the platform's home channel").option("--cron-job <job>", "instead of --deliver: fire this existing Hermes cron job (id or name; `hermes cron list`); its prompt, tools and delivery apply, so its enabled_toolsets must be exactly [\"agentinbox\"]").option("--script <file>", "a Hermes filter script under ~/.hermes/scripts (runs before the agent; can drop events at no LLM cost)").option("--run", "set the route up now: run hermes, then set the real secret and limit the route to the agentinbox tools (recommended)").addHelpText("after", hermesHelp()).action(async (_o, cmd) => {
131
+ const flags = all(cmd);
132
+ const { hermesSubscribe } = await import("./hermes-DiW4LyFm.js");
133
+ process.exitCode = await hermesSubscribe(flags.profile ?? "default", flags);
134
+ });
97
135
  listenFlags(listen.command("dead").description("list events that failed every attempt; --replay runs them again")).option("--replay", "run dead events again (successes are removed)").option("--id <eventId>", "only this event (with --replay or --clear)").option("--clear", "delete dead events without running them").option("--json", "print raw JSON lines").action(async (_o, cmd) => {
98
136
  const flags = all(cmd);
99
- const admin = await import("./admin-CCIR1XvZ.js");
137
+ const admin = await import("./admin-B-e0fGL8.js");
100
138
  const profile = flags.profile ?? "default";
101
139
  if (flags.clear) admin.clearDead(profile, flags.id);
102
140
  else if (flags.replay) {
@@ -106,21 +144,21 @@ Example:
106
144
  const service = listen.command("service").description("run the listener in the background (systemd user service / launchd agent, one per profile)");
107
145
  listenFlags(service.command("install").description("install and start the listener service; flags are saved to the profile. Re-run to update")).action(async (_o, cmd) => {
108
146
  const flags = all(cmd);
109
- const { installListenService } = await import("./service-B5T24GYF.js");
147
+ const { installListenService } = await import("./service-nQ2gc_4x.js");
110
148
  await installListenService(flags);
111
149
  });
112
150
  profileOption(service.command("uninstall").description("stop and remove the listener service (keeps the profile)")).action(async (_o, cmd) => {
113
151
  const flags = all(cmd);
114
- const { uninstallListenService } = await import("./service-B5T24GYF.js");
152
+ const { uninstallListenService } = await import("./service-nQ2gc_4x.js");
115
153
  uninstallListenService(flags.profile ?? "default");
116
154
  });
117
155
  profileOption(service.command("status").description("show the service manager's status for the listener")).action(async (_o, cmd) => {
118
156
  const flags = all(cmd);
119
- const { listenServiceStatus } = await import("./service-B5T24GYF.js");
157
+ const { listenServiceStatus } = await import("./service-nQ2gc_4x.js");
120
158
  listenServiceStatus(flags.profile ?? "default");
121
159
  });
122
160
  }
123
161
  //#endregion
124
162
  export { registerListenCommands };
125
163
 
126
- //# sourceMappingURL=commands-BRvw2jIt.js.map
164
+ //# sourceMappingURL=commands-B1JRkH7_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-B1JRkH7_.js","names":[],"sources":["../server/listen/commands.ts"],"sourcesContent":["import { type Command, InvalidArgumentError } from \"commander\";\nimport { EVENT_TYPES } from \"../../shared/types.ts\";\nimport type { ConnectFlags } from \"./connect.ts\";\nimport type { HermesFlags } from \"./hermes.ts\";\nimport type { ListenFlags } from \"./options.ts\";\nimport { DEFAULT_PROFILE } from \"./paths.ts\";\nimport { RECIPE_NAMES, recipesHelp, TOOLS } from \"./recipes.ts\";\nimport { NPX } from \"./version.ts\";\n\n/** `agentinbox connect`, `agentinbox setup-mcp` and `agentinbox listen …`, all lazily loaded. */\n\n/**\n * Options of a `listen` subcommand plus any its ancestors parsed: `listen` declares the same flags\n * (--profile, --exec…), and commander lets the parent claim them wherever they appear.\n */\nconst all = <T>(cmd: Command): T => cmd.optsWithGlobals() as T;\n\nconst collect = (value: string, previous: string[] | undefined) => [...(previous ?? []), value];\n\nconst int = (name: string) => (value: string) => {\n if (!/^\\d+$/.test(value)) throw new InvalidArgumentError(`${name} must be a whole number.`);\n return Number(value);\n};\n\nconst profileOption = (cmd: Command) => cmd.option(\"--profile <name>\", `profile to use (default \"${DEFAULT_PROFILE}\")`);\n\nfunction listenFlags(cmd: Command): Command {\n return profileOption(cmd)\n .option(\"--exec <command>\", \"run this command for each event (via /bin/sh; the event arrives on stdin as JSON, never in the command)\")\n .option(\"--recipe <name>\", `use a built-in target: ${RECIPE_NAMES.join(\", \")} (hermes forwards to your Hermes gateway; see it with --print-recipe)`)\n .option(\"--forward <url>\", \"POST each event to this localhost URL, signed per Standard Webhooks\")\n .option(\"--types <list>\", `comma-separated event types, or \"all\" (default: message.received, new mail only; also ${EVENT_TYPES.filter((t) => t !== \"message.received\").join(\", \")})`)\n .option(\"--from <glob>\", 'only senders matching this glob, e.g. \"*@stripe.com\" (repeatable)', collect)\n .option(\"--to <glob>\", \"only when a to/cc address matches (repeatable)\", collect)\n .option(\"--label <id>\", \"only messages with this Gmail label id, e.g. INBOX or Label_123 (repeatable)\", collect)\n .option(\"--subject <regex>\", \"only subjects matching this case-insensitive regular expression\")\n .option(\"--not-from <glob>\", 'skip senders matching this glob, e.g. \"*@github.com\" (repeatable; --not-from \"\" --save clears saved exclusions)', collect)\n .option(\"--not-label <id>\", \"skip messages with this Gmail label id, e.g. CATEGORY_UPDATES (repeatable)\", collect)\n .option(\"--all-categories\", \"don't skip Gmail's Promotions, Social and Forums tabs (skipped by default)\")\n .option(\"--include-category <name>\", \"take one category back from the default skip: promotions, social or forums (repeatable)\", collect)\n .option(\"--default-categories\", \"back to the default: skip Promotions, Social and Forums (undoes a saved --all-categories / --include-category)\")\n .option(\"--batch <duration>\", `collect events this long (e.g. 60s, 2m) and run --exec once for all of them (up to 20); 0 turns it off`)\n .option(\"--include-body\", \"include the cleaned message body in each event\")\n .option(\"--no-include-body\", \"don't include bodies (overrides a saved setting)\")\n .option(\"--concurrency <n>\", \"events handled at once (default 2)\", int(\"--concurrency\"))\n .option(\"--timeout <seconds>\", \"per-event time limit; the whole process group is killed after it (default 300)\", int(\"--timeout\"))\n .option(\"--max-attempts <n>\", \"attempts before an event goes to dead letters (default 5)\", int(\"--max-attempts\"))\n .option(\"--consumer <name>\", \"server-side cursor name (default <hostname>-<profile>)\")\n .option(\"--cwd <dir>\", \"directory --exec commands run in (default: a private dir in the state dir; must be yours and not group/world-writable)\")\n .option(\"--insecure\", \"allow plain http to a non-loopback, non-Tailscale daemon (loud warning)\")\n .option(\"--save\", \"save these settings to the profile\");\n}\n\n/** `listen hermes --help`. */\nfunction hermesHelp(): string {\n return `\n--recipe hermes forwards each event to your running Hermes gateway (http://127.0.0.1:8644/webhooks/agentinbox; for\nanother profile the route is agentinbox-<profile>). Hermes verifies the Standard Webhooks signature with the\nlistener's secret, runs the triage, and delivers the result where this route says. Mail that isn't important gets\na [SILENT] reply, which Hermes doesn't deliver.\n\nA Hermes webhook run normally gets web tools (web_search, web_extract, vision_analyze, clarify) and every MCP\nserver enabled in Hermes: with email as the trigger, an attacker could make it read your mail and send it out.\n--run therefore also limits the route to the agentinbox MCP server (\"toolsets\": [\"mcp-agentinbox\"] in\nwebhook_subscriptions.json, which \\`hermes webhook subscribe\\` can't set). That limit only holds when agentinbox is an\nenabled MCP server in Hermes' config.yaml (else Hermes adds every MCP server), so this refuses until\n\\`${NPX} setup-mcp --tool hermes\\` has added it. --run creates the route disabled with the real secret under Hermes'\nlock (python3), runs \\`hermes webhook subscribe\\` without --secret (hermes keeps the secret and the disabled state),\nthen sets the toolsets and enables it. The secret is never in a command line, the route never runs unconfined, and\nany failure removes it again. Re-run it after any \\`hermes webhook subscribe\\` for this route (that resets the\ntoolsets). The Hermes home follows HERMES_HOME or Hermes' sticky active_profile.\n\nWithout --run it prints both steps for you to do by hand; the toolsets edit is required.\n\n--cron-job hands the email to that job's own tools, so it is accepted only when the job's enabled_toolsets is\nexactly [\"agentinbox\"] (the bare server name; \"mcp-agentinbox\" doesn't narrow MCP servers for cron jobs).\n\nNeeds python3, the gateway's webhook platform (hermes gateway setup, or WEBHOOK_ENABLED=true in ~/.hermes/.env) and\na running gateway. Check it: curl http://127.0.0.1:8644/health\n\nExamples:\n ${NPX} listen hermes --deliver telegram --run\n ${NPX} listen hermes --cron-job email-watch --run # only for a job limited to [\"agentinbox\"]\n ${NPX} listen service install --recipe hermes`;\n}\n\n/** `setup-mcp --help`: exactly what it changes, per tool. */\nfunction mcpSetupHelp(): string {\n return `\nWhat it changes (the server is named \"agentinbox\", or \"agentinbox-<profile>\" for --profile):\n claude-code runs \\`claude mcp remove agentinbox --scope user\\` then\n \\`claude mcp add-json --scope user agentinbox '{\"type\":\"http\",\"url\":\"<daemon>/mcp\",\"headersHelper\":\"…\"}'\\`.\n The header helper (~/.config/agentinbox/bin/mcp-header.mjs) reads the key from your profile, so\n the key is in neither the command line nor ~/.claude.json. Backs up ~/.claude.json first\n ($CLAUDE_CONFIG_DIR/.claude.json if set).\n codex adds or replaces [mcp_servers.agentinbox] in ~/.codex/config.toml ($CODEX_HOME), with the key in\n http_headers; the file becomes 0600.\n cursor adds or replaces mcpServers.agentinbox in ~/.cursor/mcp.json, with the key in headers; 0600.\n hermes adds or replaces mcp_servers.agentinbox in ~/.hermes/config.yaml ($HERMES_HOME) and puts the key in\n ~/.hermes/.env as AGENTINBOX_API_KEY; both 0600.\nEvery file is backed up first as <file>.agentinbox-backup-<timestamp> (0600; backups of files holding the key hold it\ntoo). It also refreshes ~/.config/agentinbox/mcp/<profile>.claude.json (no key), which the listen recipe uses.\n\nCheck it afterwards: claude mcp list · codex mcp list · agent mcp list (Cursor) · hermes mcp test agentinbox\n\nExample:\n ${NPX} setup-mcp --tool claude-code --dry-run`;\n}\n\nexport function registerListenCommands(program: Command): void {\n program\n .command(\"connect\")\n .description(\"pair this machine's agent with an agentinbox daemon (approve the code in the console)\")\n .argument(\"<daemon-url>\", \"the agentinbox daemon, e.g. https://mail.example.com or http://100.101.102.103:8425\")\n .option(\"--name <name>\", 'how the agent appears in the console (default \"<Tool> on <hostname>\")')\n .option(\"--tool <tool>\", `the agent's tool: ${TOOLS.join(\", \")}; tailors the next steps`)\n .option(\"--account <email>\", \"mailbox to request access to (repeatable; the approver decides)\", collect)\n .option(\"--capabilities <list>\", \"capabilities to request, e.g. read,draft (the approver decides)\")\n .option(\"--reason <text>\", \"why the agent needs access (shown to the approver)\")\n .option(\"--setup-mcp\", \"also register the MCP server in the chosen tool (the key is never shown; `setup-mcp --help` lists exactly what changes)\")\n .option(\"--profile <name>\", `profile to save the key in (default \"${DEFAULT_PROFILE}\")`)\n .option(\"--consumer <name>\", \"listener cursor name (default <hostname>-<profile>)\")\n .option(\"--log <file>\", \"also write the output to this file (created 0600; for running connect in the background)\")\n .option(\"--insecure\", \"allow plain http to a non-loopback, non-Tailscale daemon (loud warning)\")\n .option(\"--force\", \"re-pair an existing profile (keeps its listener settings)\")\n .addHelpText(\n \"after\",\n `\nExit codes: 0 approved, 2 denied, 3 expired, 4 already consumed, 130 cancelled, 1 error.\n\nExample:\n ${NPX} connect https://mail.example.com --tool claude-code --setup-mcp`,\n )\n .action(async (url: string, flags: ConnectFlags) => {\n const { runConnect } = await import(\"./connect.ts\");\n process.exit(await runConnect(url, flags, { handleSignals: true }));\n });\n\n profileOption(program.command(\"setup-mcp\").description(\"register the agentinbox MCP server in your agent's tool, without showing the key\"))\n .option(\"--tool <tool>\", `${TOOLS.filter((t) => t !== \"other\").join(\", \")} (default: the tool given to connect)`)\n .option(\"--dry-run\", \"print the exact commands and file changes, and change nothing\")\n .addHelpText(\"after\", mcpSetupHelp())\n .action(async (flags: { tool?: string; profile?: string; dryRun?: boolean }) => {\n const { parseTool, printMcpResult } = await import(\"./connect.ts\");\n const { loadProfile } = await import(\"./profile.ts\");\n const { setupMcp, mcpTarget } = await import(\"./mcpsetup.ts\");\n const { profilePath } = await import(\"./paths.ts\");\n const name = flags.profile ?? DEFAULT_PROFILE;\n const profile = loadProfile(name);\n const tool = flags.tool ? parseTool(flags.tool) : (profile.tool ?? \"other\");\n if (tool === \"other\") throw new Error(`Which tool? Pass --tool ${TOOLS.filter((t) => t !== \"other\").join(\"|\")}.`);\n const { claudeMcpConfigPath, writeClaudeMcpConfig } = await import(\"./mcpheader.ts\");\n const r = setupMcp(tool, mcpTarget(name, profile), profilePath(name), { dryRun: flags.dryRun });\n if (flags.dryRun) r.changes = [...(r.changes ?? []), `refresh ${claudeMcpConfigPath(name)} (keyless MCP config the Claude Code listen recipe loads)`];\n else writeClaudeMcpConfig(name, `${profile.url}/mcp`);\n printMcpResult(r);\n if (!r.ok) process.exitCode = 1;\n });\n\n profileOption(\n program.command(\"mcp-header\").description(\"print the agent's Authorization header as JSON for an MCP client's header helper (refuses to print to a terminal)\"),\n ).action(async (flags: { profile?: string }) => {\n const { printMcpHeader } = await import(\"./mcpheader.ts\");\n process.exitCode = printMcpHeader(flags.profile ?? DEFAULT_PROFILE);\n });\n\n const listen = listenFlags(\n program\n .command(\"listen\")\n .description(\"wake a local agent on new mail: hold an outbound stream to the daemon and run a command or POST to localhost per event\"),\n )\n .option(\"--dry-run\", \"print matching events without running anything (uses a throwaway <consumer>-dry-run cursor)\")\n .option(\"--from-start\", \"a NEW consumer starts at the oldest stored event (no effect once it exists: use --backfill)\")\n .option(\"--backfill\", \"run the mail from before this listener started through --exec/--forward once, oldest first, then exit; safe while the listener runs (own cursor)\")\n .option(\"--until <seq>\", \"with --backfill: replay up to this event number instead of where the listener started\", int(\"--until\"))\n .option(\"--print-recipe <name>\", `print what --recipe <name> runs (hermes: its URL), for ${RECIPE_NAMES.join(\", \")} (with this machine's paths), and exit`)\n .addHelpText(\"after\", recipesHelp())\n .action(async (flags: ListenFlags & { printRecipe?: string }) => {\n if (flags.printRecipe !== undefined) {\n const { parseRecipeTool, recipe } = await import(\"./recipes.ts\");\n const name = flags.printRecipe.trim().toLowerCase();\n const r = recipe(name === \"other\" ? \"other\" : parseRecipeTool(name), flags.profile ?? DEFAULT_PROFILE);\n // Exec recipes print the bare command (to edit and pass back with --exec); hermes its forward URL.\n process.stdout.write(`${r.exec ?? r.forward}\\n`);\n return;\n }\n const { runListener } = await import(\"./listen.ts\");\n process.exit(await runListener({ flags, handleSignals: true }));\n });\n\n profileOption(listen.command(\"status\").description(\"show the listener's connection, cursor, recent events and dead letters\")).action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string }>(cmd);\n const { printStatus } = await import(\"./admin.ts\");\n await printStatus(flags.profile ?? DEFAULT_PROFILE);\n });\n\n profileOption(listen.command(\"secret\").description(\"print the forward-mode signing secret (whsec_…) for your local receiver\"))\n .option(\"--rotate\", \"generate a new secret (restart the listener afterwards)\")\n .action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string; rotate?: boolean }>(cmd);\n const { printSecret } = await import(\"./admin.ts\");\n printSecret(flags.profile ?? DEFAULT_PROFILE, flags);\n });\n\n profileOption(\n listen\n .command(\"hermes\")\n .description(\"create the Hermes gateway webhook route that --recipe hermes forwards to, limited to the agentinbox tools\"),\n )\n .option(\"--deliver <target>\", \"where Hermes sends its triage: telegram, discord, slack… (a platform connected to your gateway), or log\")\n .option(\"--deliver-chat-id <id>\", \"with --deliver: a specific chat instead of the platform's home channel\")\n .option(\"--cron-job <job>\", \"instead of --deliver: fire this existing Hermes cron job (id or name; `hermes cron list`); its prompt, tools and delivery apply, so its enabled_toolsets must be exactly [\\\"agentinbox\\\"]\")\n .option(\"--script <file>\", \"a Hermes filter script under ~/.hermes/scripts (runs before the agent; can drop events at no LLM cost)\")\n .option(\"--run\", \"set the route up now: run hermes, then set the real secret and limit the route to the agentinbox tools (recommended)\")\n .addHelpText(\"after\", hermesHelp())\n .action(async (_o: unknown, cmd: Command) => {\n const flags = all<HermesFlags>(cmd);\n const { hermesSubscribe } = await import(\"./hermes.ts\");\n process.exitCode = await hermesSubscribe(flags.profile ?? DEFAULT_PROFILE, flags);\n });\n\n listenFlags(listen.command(\"dead\").description(\"list events that failed every attempt; --replay runs them again\"))\n .option(\"--replay\", \"run dead events again (successes are removed)\")\n .option(\"--id <eventId>\", \"only this event (with --replay or --clear)\")\n .option(\"--clear\", \"delete dead events without running them\")\n .option(\"--json\", \"print raw JSON lines\")\n .action(async (_o: unknown, cmd: Command) => {\n const flags = all<ListenFlags & { replay?: boolean; id?: string; clear?: boolean; json?: boolean }>(cmd);\n const admin = await import(\"./admin.ts\");\n const profile = flags.profile ?? DEFAULT_PROFILE;\n if (flags.clear) admin.clearDead(profile, flags.id);\n else if (flags.replay) {\n if ((await admin.replayDead(flags)) > 0) process.exitCode = 1;\n } else admin.printDead(profile, flags);\n });\n\n const service = listen.command(\"service\").description(\"run the listener in the background (systemd user service / launchd agent, one per profile)\");\n listenFlags(service.command(\"install\").description(\"install and start the listener service; flags are saved to the profile. Re-run to update\")).action(\n async (_o: unknown, cmd: Command) => {\n const flags = all<ListenFlags>(cmd);\n const { installListenService } = await import(\"./service.ts\");\n await installListenService(flags);\n },\n );\n profileOption(service.command(\"uninstall\").description(\"stop and remove the listener service (keeps the profile)\")).action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string }>(cmd);\n const { uninstallListenService } = await import(\"./service.ts\");\n uninstallListenService(flags.profile ?? DEFAULT_PROFILE);\n });\n profileOption(service.command(\"status\").description(\"show the service manager's status for the listener\")).action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string }>(cmd);\n const { listenServiceStatus } = await import(\"./service.ts\");\n listenServiceStatus(flags.profile ?? DEFAULT_PROFILE);\n });\n}\n"],"mappings":";;;;;;;;;;;;AAeA,MAAM,OAAU,QAAoB,IAAI,gBAAgB;AAExD,MAAM,WAAW,OAAe,aAAmC,CAAC,GAAI,YAAY,CAAC,GAAI,KAAK;AAE9F,MAAM,OAAO,UAAkB,UAAkB;CAC/C,IAAI,CAAC,QAAQ,KAAK,KAAK,GAAG,MAAM,IAAI,qBAAqB,GAAG,KAAK,yBAAyB;CAC1F,OAAO,OAAO,KAAK;AACrB;AAEA,MAAM,iBAAiB,QAAiB,IAAI,OAAO,oBAAoB,4BAA4B,gBAAgB,GAAG;AAEtH,SAAS,YAAY,KAAuB;CAC1C,OAAO,cAAc,GAAG,CAAC,CACtB,OAAO,oBAAoB,yGAAyG,CAAC,CACrI,OAAO,mBAAmB,0BAA0B,aAAa,KAAK,IAAI,EAAE,sEAAsE,CAAC,CACnJ,OAAO,mBAAmB,qEAAqE,CAAC,CAChG,OAAO,kBAAkB,yFAAyF,YAAY,QAAQ,MAAM,MAAM,kBAAkB,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CACpL,OAAO,iBAAiB,uEAAqE,OAAO,CAAC,CACrG,OAAO,eAAe,kDAAkD,OAAO,CAAC,CAChF,OAAO,gBAAgB,gFAAgF,OAAO,CAAC,CAC/G,OAAO,qBAAqB,iEAAiE,CAAC,CAC9F,OAAO,qBAAqB,uHAAmH,OAAO,CAAC,CACvJ,OAAO,oBAAoB,8EAA8E,OAAO,CAAC,CACjH,OAAO,oBAAoB,4EAA4E,CAAC,CACxG,OAAO,6BAA6B,2FAA2F,OAAO,CAAC,CACvI,OAAO,wBAAwB,gHAAgH,CAAC,CAChJ,OAAO,sBAAsB,wGAAwG,CAAC,CACtI,OAAO,kBAAkB,gDAAgD,CAAC,CAC1E,OAAO,qBAAqB,kDAAkD,CAAC,CAC/E,OAAO,qBAAqB,sCAAsC,IAAI,eAAe,CAAC,CAAC,CACvF,OAAO,uBAAuB,kFAAkF,IAAI,WAAW,CAAC,CAAC,CACjI,OAAO,sBAAsB,6DAA6D,IAAI,gBAAgB,CAAC,CAAC,CAChH,OAAO,qBAAqB,wDAAwD,CAAC,CACrF,OAAO,eAAe,wHAAwH,CAAC,CAC/I,OAAO,cAAc,yEAAyE,CAAC,CAC/F,OAAO,UAAU,oCAAoC;AAC1D;;AAGA,SAAS,aAAqB;CAC5B,OAAO;;;;;;;;;;;IAWL,IAAI;;;;;;;;;;;;;;;IAeJ,IAAI;IACJ,IAAI;IACJ,IAAI;AACR;;AAGA,SAAS,eAAuB;CAC9B,OAAO;;;;;;;;;;;;;;;;;;IAkBL,IAAI;AACR;AAEA,SAAgB,uBAAuB,SAAwB;CAC7D,QACG,QAAQ,SAAS,CAAC,CAClB,YAAY,uFAAuF,CAAC,CACpG,SAAS,gBAAgB,qFAAqF,CAAC,CAC/G,OAAO,iBAAiB,yEAAuE,CAAC,CAChG,OAAO,iBAAiB,qBAAqB,MAAM,KAAK,IAAI,EAAE,yBAAyB,CAAC,CACxF,OAAO,qBAAqB,mEAAmE,OAAO,CAAC,CACvG,OAAO,yBAAyB,iEAAiE,CAAC,CAClG,OAAO,mBAAmB,oDAAoD,CAAC,CAC/E,OAAO,eAAe,yHAAyH,CAAC,CAChJ,OAAO,oBAAoB,wCAAwC,gBAAgB,GAAG,CAAC,CACvF,OAAO,qBAAqB,qDAAqD,CAAC,CAClF,OAAO,gBAAgB,0FAA0F,CAAC,CAClH,OAAO,cAAc,yEAAyE,CAAC,CAC/F,OAAO,WAAW,2DAA2D,CAAC,CAC9E,YACC,SACA;;;;IAIF,IAAI,iEACJ,CAAC,CACA,OAAO,OAAO,KAAa,UAAwB;EAClD,MAAM,EAAE,eAAe,MAAM,OAAO;EACpC,QAAQ,KAAK,MAAM,WAAW,KAAK,OAAO,EAAE,eAAe,KAAK,CAAC,CAAC;CACpE,CAAC;CAEH,cAAc,QAAQ,QAAQ,WAAW,CAAC,CAAC,YAAY,kFAAkF,CAAC,CAAC,CACxI,OAAO,iBAAiB,GAAG,MAAM,QAAQ,MAAM,MAAM,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,sCAAsC,CAAC,CAChH,OAAO,aAAa,+DAA+D,CAAC,CACpF,YAAY,SAAS,aAAa,CAAC,CAAC,CACpC,OAAO,OAAO,UAAiE;EAC9E,MAAM,EAAE,WAAW,mBAAmB,MAAM,OAAO;EACnD,MAAM,EAAE,gBAAgB,MAAM,OAAO;EACrC,MAAM,EAAE,UAAU,cAAc,MAAM,OAAO;EAC7C,MAAM,EAAE,gBAAgB,MAAM,OAAO;EACrC,MAAM,OAAO,MAAM,WAAA;EACnB,MAAM,UAAU,YAAY,IAAI;EAChC,MAAM,OAAO,MAAM,OAAO,UAAU,MAAM,IAAI,IAAK,QAAQ,QAAQ;EACnE,IAAI,SAAS,SAAS,MAAM,IAAI,MAAM,2BAA2B,MAAM,QAAQ,MAAM,MAAM,OAAO,CAAC,CAAC,KAAK,GAAG,EAAE,EAAE;EAChH,MAAM,EAAE,qBAAqB,yBAAyB,MAAM,OAAO;EACnE,MAAM,IAAI,SAAS,MAAM,UAAU,MAAM,OAAO,GAAG,YAAY,IAAI,GAAG,EAAE,QAAQ,MAAM,OAAO,CAAC;EAC9F,IAAI,MAAM,QAAQ,EAAE,UAAU,CAAC,GAAI,EAAE,WAAW,CAAC,GAAI,WAAW,oBAAoB,IAAI,EAAE,0DAA0D;OAC/I,qBAAqB,MAAM,GAAG,QAAQ,IAAI,KAAK;EACpD,eAAe,CAAC;EAChB,IAAI,CAAC,EAAE,IAAI,QAAQ,WAAW;CAChC,CAAC;CAEH,cACE,QAAQ,QAAQ,YAAY,CAAC,CAAC,YAAY,mHAAmH,CAC/J,CAAC,CAAC,OAAO,OAAO,UAAgC;EAC9C,MAAM,EAAE,mBAAmB,MAAM,OAAO;EACxC,QAAQ,WAAW,eAAe,MAAM,WAAA,SAA0B;CACpE,CAAC;CAED,MAAM,SAAS,YACb,QACG,QAAQ,QAAQ,CAAC,CACjB,YAAY,wHAAwH,CACzI,CAAC,CACE,OAAO,aAAa,6FAA6F,CAAC,CAClH,OAAO,gBAAgB,6FAA6F,CAAC,CACrH,OAAO,cAAc,kJAAkJ,CAAC,CACxK,OAAO,iBAAiB,yFAAyF,IAAI,SAAS,CAAC,CAAC,CAChI,OAAO,yBAAyB,0DAA0D,aAAa,KAAK,IAAI,EAAE,uCAAuC,CAAC,CAC1J,YAAY,SAAS,YAAY,CAAC,CAAC,CACnC,OAAO,OAAO,UAAkD;EAC/D,IAAI,MAAM,gBAAgB,KAAA,GAAW;GACnC,MAAM,EAAE,iBAAiB,WAAW,MAAM,OAAO;GACjD,MAAM,OAAO,MAAM,YAAY,KAAK,CAAC,CAAC,YAAY;GAClD,MAAM,IAAI,OAAO,SAAS,UAAU,UAAU,gBAAgB,IAAI,GAAG,MAAM,WAAA,SAA0B;GAErG,QAAQ,OAAO,MAAM,GAAG,EAAE,QAAQ,EAAE,QAAQ,GAAG;GAC/C;EACF;EACA,MAAM,EAAE,gBAAgB,MAAM,OAAO;EACrC,QAAQ,KAAK,MAAM,YAAY;GAAE;GAAO,eAAe;EAAK,CAAC,CAAC;CAChE,CAAC;CAEH,cAAc,OAAO,QAAQ,QAAQ,CAAC,CAAC,YAAY,wEAAwE,CAAC,CAAC,CAAC,OAAO,OAAO,IAAa,QAAiB;EACxK,MAAM,QAAQ,IAA0B,GAAG;EAC3C,MAAM,EAAE,gBAAgB,MAAM,OAAO;EACrC,MAAM,YAAY,MAAM,WAAA,SAA0B;CACpD,CAAC;CAED,cAAc,OAAO,QAAQ,QAAQ,CAAC,CAAC,YAAY,yEAAyE,CAAC,CAAC,CAC3H,OAAO,YAAY,yDAAyD,CAAC,CAC7E,OAAO,OAAO,IAAa,QAAiB;EAC3C,MAAM,QAAQ,IAA4C,GAAG;EAC7D,MAAM,EAAE,gBAAgB,MAAM,OAAO;EACrC,YAAY,MAAM,WAAA,WAA4B,KAAK;CACrD,CAAC;CAEH,cACE,OACG,QAAQ,QAAQ,CAAC,CACjB,YAAY,2GAA2G,CAC5H,CAAC,CACE,OAAO,sBAAsB,yGAAyG,CAAC,CACvI,OAAO,0BAA0B,wEAAwE,CAAC,CAC1G,OAAO,oBAAoB,2LAA2L,CAAC,CACvN,OAAO,mBAAmB,wGAAwG,CAAC,CACnI,OAAO,SAAS,sHAAsH,CAAC,CACvI,YAAY,SAAS,WAAW,CAAC,CAAC,CAClC,OAAO,OAAO,IAAa,QAAiB;EAC3C,MAAM,QAAQ,IAAiB,GAAG;EAClC,MAAM,EAAE,oBAAoB,MAAM,OAAO;EACzC,QAAQ,WAAW,MAAM,gBAAgB,MAAM,WAAA,WAA4B,KAAK;CAClF,CAAC;CAEH,YAAY,OAAO,QAAQ,MAAM,CAAC,CAAC,YAAY,iEAAiE,CAAC,CAAC,CAC/G,OAAO,YAAY,+CAA+C,CAAC,CACnE,OAAO,kBAAkB,4CAA4C,CAAC,CACtE,OAAO,WAAW,yCAAyC,CAAC,CAC5D,OAAO,UAAU,sBAAsB,CAAC,CACxC,OAAO,OAAO,IAAa,QAAiB;EAC3C,MAAM,QAAQ,IAAsF,GAAG;EACvG,MAAM,QAAQ,MAAM,OAAO;EAC3B,MAAM,UAAU,MAAM,WAAA;EACtB,IAAI,MAAM,OAAO,MAAM,UAAU,SAAS,MAAM,EAAE;OAC7C,IAAI,MAAM,QACR;OAAA,MAAM,MAAM,WAAW,KAAK,IAAK,GAAG,QAAQ,WAAW;EAAA,OACvD,MAAM,UAAU,SAAS,KAAK;CACvC,CAAC;CAEH,MAAM,UAAU,OAAO,QAAQ,SAAS,CAAC,CAAC,YAAY,4FAA4F;CAClJ,YAAY,QAAQ,QAAQ,SAAS,CAAC,CAAC,YAAY,0FAA0F,CAAC,CAAC,CAAC,OAC9I,OAAO,IAAa,QAAiB;EACnC,MAAM,QAAQ,IAAiB,GAAG;EAClC,MAAM,EAAE,yBAAyB,MAAM,OAAO;EAC9C,MAAM,qBAAqB,KAAK;CAClC,CACF;CACA,cAAc,QAAQ,QAAQ,WAAW,CAAC,CAAC,YAAY,0DAA0D,CAAC,CAAC,CAAC,OAAO,OAAO,IAAa,QAAiB;EAC9J,MAAM,QAAQ,IAA0B,GAAG;EAC3C,MAAM,EAAE,2BAA2B,MAAM,OAAO;EAChD,uBAAuB,MAAM,WAAA,SAA0B;CACzD,CAAC;CACD,cAAc,QAAQ,QAAQ,QAAQ,CAAC,CAAC,YAAY,oDAAoD,CAAC,CAAC,CAAC,OAAO,OAAO,IAAa,QAAiB;EACrJ,MAAM,QAAQ,IAA0B,GAAG;EAC3C,MAAM,EAAE,wBAAwB,MAAM,OAAO;EAC7C,oBAAoB,MAAM,WAAA,SAA0B;CACtD,CAAC;AACH"}
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { n as CAPABILITIES } from "./types-2rItLIhH.js";
3
- import { C as clientInfo, E as startPairing, S as ApiError, T as pollPairing, _ as insecureBanner, g as checkTransport, p as validConsumer, u as defaultConsumer, v as normalizeDaemonUrl, w as getSelf, x as describeGrants } from "./listen-CvRrKzBz.js";
4
- import { i as safeText, n as box, r as formatDuration, t as StatusLine } from "./ui-B8Sd4Y7Y.js";
5
- import { d as NPX, i as saveProfile, n as loadProfile, r as profileExists, t as listProfiles } from "./profile-C1u9BrI8.js";
3
+ import { A as getSelf, M as startPairing, O as clientInfo, g as validConsumer, j as pollPairing, u as defaultConsumer, w as ApiError } from "./hermes-BobpCc4t.js";
4
+ import { f as StatusLine, h as safeText, l as setupMcp, m as formatDuration, p as box, s as mcpTarget } from "./mcpsetup-d1PRQk9r.js";
5
+ import { d as NPX, i as saveProfile, n as loadProfile, r as profileExists, t as listProfiles } from "./profile-BqGV-DOU.js";
6
+ import { p as describeGrants } from "./listen-CE_6o-WO.js";
7
+ import { C as insecureBanner, S as checkTransport, T as normalizeDaemonUrl, b as shellQuote, g as recipe, o as TOOLS, s as TOOL_LABELS } from "./recipes-Cw2ShA42.js";
6
8
  import { c as profilePath, p as validProfileName } from "./paths-DckASYtc.js";
7
- import { d as writeClaudeMcpConfig } from "./mcpheader-Cccnqodg.js";
8
- import { l as shellQuote, n as TOOLS, o as recipe, r as TOOL_LABELS } from "./recipes-U2teSD6l.js";
9
- import { n as isServiceInstalled } from "./service-iiykwB5r.js";
10
- import { l as setupMcp, s as mcpTarget } from "./mcpsetup-CvRN7NPm.js";
9
+ import { m as writeClaudeMcpConfig } from "./mcpheader-8Mqlqp1h.js";
10
+ import { n as isServiceInstalled } from "./service-DHBfOtp7.js";
11
11
  import { closeSync, constants, fchmodSync, lstatSync, openSync, writeSync } from "node:fs";
12
12
  import { hostname } from "node:os";
13
13
  import pc from "picocolors";
@@ -300,6 +300,8 @@ function skillCommand(tool, url) {
300
300
  default: return `${NPX} skill install --target ./skills --url ${url}`;
301
301
  }
302
302
  }
303
+ /** `listen hermes … --run`: creates the Hermes route (the console shows the same command). */
304
+ const hermesRouteCommand = (profileName) => `${NPX} listen hermes${profileName === "default" ? "" : ` --profile ${profileName}`} --deliver telegram --run`;
303
305
  function printNextSteps(profileName, profile, tool, mcp) {
304
306
  const p = profileName === "default" ? "" : ` --profile ${profileName}`;
305
307
  const label = tool === "other" ? "your agent" : TOOL_LABELS[tool];
@@ -318,17 +320,24 @@ function printNextSteps(profileName, profile, tool, mcp) {
318
320
  }
319
321
  out(` ${n++}. Install the agentinbox skill so ${label} knows the rules:`);
320
322
  out(` ${pc.cyan(skillCommand(tool, profile.url))}`);
323
+ if (tool === "hermes") {
324
+ out(` ${n++}. Create the Hermes gateway route the listener forwards to, saying where Hermes should tell you (once; needs the gateway's webhook platform on):`);
325
+ out(` ${pc.cyan(hermesRouteCommand(profileName))}`);
326
+ out(pc.gray(` Or --deliver discord|slack|…, or --deliver-chat-id <id>. It sets the listener's secret without showing it and limits the route to the agentinbox tools.`));
327
+ }
321
328
  out(` ${n++}. Wake ${label} when mail arrives. First try it in the foreground (Ctrl-C stops it; --save keeps the command in the profile):`);
322
329
  out(` ${pc.cyan(`${NPX} listen${p} --save ${target}`)}`);
323
330
  out(pc.gray(` Only new mail wakes it (message.received), not mail you send. Change it with --types, e.g. --types thread.reply_received (only replies to threads you sent) or --types all.`));
331
+ out(pc.gray(` Gmail's Promotions, Social and Forums tabs are skipped (--all-categories to include them); skip more with --not-from '*@github.com'. --batch 60s runs a burst of mail once.`));
324
332
  out(pc.gray(` What the woken agent can use: ${r.confinement}.`));
325
- for (const note of r.notes) out(pc.gray(` ${note}`));
333
+ out(pc.gray(` Where its output goes: ${r.output}`));
334
+ for (const note of r.notes.filter((x) => tool !== "hermes" || !x.startsWith("Create the Hermes route"))) out(pc.gray(` ${note}`));
326
335
  if (tool !== "other") {
327
- out(pc.gray(` It runs: ${r.exec}`));
328
- out(pc.gray(` To change it: ${NPX} listen${p} --print-recipe ${tool} prints it; pass your edit with --exec '…' instead of --recipe.`));
336
+ out(pc.gray(` It runs: ${r.runs}`));
337
+ if (r.exec) out(pc.gray(` To change it: ${NPX} listen${p} --print-recipe ${tool} prints it; pass your edit with --exec '…' instead of --recipe.`));
329
338
  }
330
339
  out(` ${n++}. Check that it works: in the console's setup, the "Check that it works" step sends a test email.`);
331
- out(` Watch it arrive in the foreground listener as ${pc.cyan("→ #… message.received")} followed by one ${pc.green("✓")} line once ${label} handled it.`);
340
+ out(` Watch it arrive in the foreground listener as ${pc.cyan("→ #… message.received")} followed by one ${pc.green("✓")} line once ${tool === "hermes" ? "Hermes accepted it (Hermes then triages it and tells you if it matters)" : `${label} handled it`}.`);
332
341
  out(` ${n++}. Then keep it running in the background (systemd / launchd, starts at login; stop the foreground one first):`);
333
342
  out(` ${pc.cyan(`${NPX} listen service install${p}`)}`);
334
343
  out(` ${pc.cyan(`${NPX} listen status${p}`)} ${pc.gray("(connection, cursor, recent events and the access granted)")}`);
@@ -337,4 +346,4 @@ function printNextSteps(profileName, profile, tool, mcp) {
337
346
  //#endregion
338
347
  export { parseTool, printMcpResult, runConnect };
339
348
 
340
- //# sourceMappingURL=connect-DR3YrwvV.js.map
349
+ //# sourceMappingURL=connect-DbfCEHOf.js.map