agentinbox-cli 0.1.0-nightly.34 → 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.
- package/dist/{admin-BJNe41GS.js → admin-B-e0fGL8.js} +21 -7
- package/dist/admin-B-e0fGL8.js.map +1 -0
- package/dist/{audit-CueC9wmy.js → audit-CDBJ60bx.js} +2 -2
- package/dist/{audit-CueC9wmy.js.map → audit-CDBJ60bx.js.map} +1 -1
- package/dist/audit-LsAWaKJT.js +2 -0
- package/dist/cli.js +13 -32
- package/dist/cli.js.map +1 -1
- package/dist/{commands-D6cZgm-K.js → commands-B1JRkH7_.js} +60 -22
- package/dist/commands-B1JRkH7_.js.map +1 -0
- package/dist/{config-7aAYcVSK.js → config-B4yystk9.js} +3 -2
- package/dist/config-B4yystk9.js.map +1 -0
- package/dist/config-DCuYmK68.js +2 -0
- package/dist/{connect-CneO_Ap0.js → connect-DbfCEHOf.js} +22 -13
- package/dist/{connect-CneO_Ap0.js.map → connect-DbfCEHOf.js.map} +1 -1
- package/dist/db-CaPyxUtw.js +2 -0
- package/dist/{db-CTUkHFMr.js → db-XVZ0JWgA.js} +62 -1
- package/dist/{db-CTUkHFMr.js.map → db-XVZ0JWgA.js.map} +1 -1
- package/dist/{filter-B_6zV-Lf.js → filter-BGDAG4Q8.js} +2 -2
- package/dist/{filter-B_6zV-Lf.js.map → filter-BGDAG4Q8.js.map} +1 -1
- package/dist/hermes-BobpCc4t.js +940 -0
- package/dist/hermes-BobpCc4t.js.map +1 -0
- package/dist/hermes-DiW4LyFm.js +3 -0
- package/dist/instance-BW7hjbyx.js +2 -0
- package/dist/{instance-kVNvsbrl.js → instance-BZFlLsIv.js} +3 -3
- package/dist/{instance-kVNvsbrl.js.map → instance-BZFlLsIv.js.map} +1 -1
- package/dist/{listen-BRc0sjh1.js → listen-CE_6o-WO.js} +195 -667
- package/dist/listen-CE_6o-WO.js.map +1 -0
- package/dist/listen-K5SDQlRA.js +2 -0
- package/dist/{mcpheader-C4j_SH1P.js → mcpheader-8Mqlqp1h.js} +68 -5
- package/dist/mcpheader-8Mqlqp1h.js.map +1 -0
- package/dist/mcpheader-BNjmjI1b.js +2 -0
- package/dist/mcpsetup-RpaNjEw_.js +2 -0
- package/dist/{mcpsetup-DvMOc6Wq.js → mcpsetup-d1PRQk9r.js} +139 -7
- package/dist/mcpsetup-d1PRQk9r.js.map +1 -0
- package/dist/node-check-D6v5n6d2.js +24 -0
- package/dist/node-check-D6v5n6d2.js.map +1 -0
- package/dist/{profile-BBSpPKmq.js → profile-BqGV-DOU.js} +9 -3
- package/dist/profile-BqGV-DOU.js.map +1 -0
- package/dist/profile-C38suDkJ.js +2 -0
- package/dist/recipes-Cw2ShA42.js +310 -0
- package/dist/recipes-Cw2ShA42.js.map +1 -0
- package/dist/recipes-DlhXH1O8.js +2 -0
- package/dist/{server-DhmOZECp.js → server-DiPOZSU8.js} +1111 -53
- package/dist/server-DiPOZSU8.js.map +1 -0
- package/dist/{service-BSwqVeN4.js → service-D75izPEj.js} +1 -1
- package/dist/{service-DYYbUYWS.js → service-DHBfOtp7.js} +155 -52
- package/dist/service-DHBfOtp7.js.map +1 -0
- package/dist/{service-D9ncVbsu.js → service-VEbnQILm.js} +13 -7
- package/dist/service-VEbnQILm.js.map +1 -0
- package/dist/service-nQ2gc_4x.js +2 -0
- package/dist/settings-YVzbOMYE.js +2 -0
- package/dist/{settings-BfFrufSv.js → settings-fSFKUWNC.js} +6 -4
- package/dist/settings-fSFKUWNC.js.map +1 -0
- package/dist/skill/SKILL.md +35 -16
- package/dist/types-2rItLIhH.js +74 -0
- package/dist/types-2rItLIhH.js.map +1 -0
- package/dist/web/assets/{_agentId-Bs6VMvzg.js → _agentId-S1HPvZ-A.js} +1 -1
- package/dist/web/assets/{_app-B3oYXJLj.js → _app-9OiYPzoE.js} +2 -2
- package/dist/web/assets/{_app-oXUDHnih.js → _app-CTqw82IX.js} +1 -1
- package/dist/web/assets/{_webhookId-BBZ1kRap.js → _webhookId-ZgpFgu5b.js} +1 -1
- package/dist/web/assets/{account-status-CMRwz9hr.js → account-status-D30kFHUc.js} +1 -1
- package/dist/web/assets/{accounts-CC0ZDOzk.js → accounts-CnIPa0qh.js} +1 -1
- package/dist/web/assets/{accounts-list-BaJi13b2.js → accounts-list-BtQxpmGm.js} +1 -1
- package/dist/web/assets/{agent-create-form-NqewkSRp.js → agent-create-form-DpzMNzHr.js} +1 -1
- package/dist/web/assets/{agents-DVaedQkP.js → agents-BD-NIb5j.js} +1 -1
- package/dist/web/assets/{approvals-D0jnIsXU.js → approvals-B6wHykyi.js} +1 -1
- package/dist/web/assets/{attention-CSuWOYr9.js → attention-DMA02b1f.js} +1 -1
- package/dist/web/assets/{audit-BWHSZOwv.js → audit-BUc7vZhg.js} +1 -1
- package/dist/web/assets/{audit-bits-CBtiPARw.js → audit-bits-BYFcaQSf.js} +1 -1
- package/dist/web/assets/{chips-input-DYNJBEab.js → chips-input-DDDBXHB7.js} +1 -1
- package/dist/web/assets/{choice-cards-Cb3l6Brt.js → choice-cards-nNXow1Od.js} +1 -1
- package/dist/web/assets/cli-d49Yn6md.js +1 -0
- package/dist/web/assets/{command-a_tUwHEf.js → command-DdmekLLh.js} +1 -1
- package/dist/web/assets/{common-oy0p5mca.js → common-C0QNVOcQ.js} +1 -1
- package/dist/web/assets/{connect-agent-guide-BAk9_3cC.js → connect-agent-guide-BCKNX8yq.js} +1 -1
- package/dist/web/assets/{connect-host-DnsBZHv1.js → connect-host-CiD91Gso.js} +1 -1
- package/dist/web/assets/{data-table-BnmgPx-p.js → data-table-B1VUusw5.js} +1 -1
- package/dist/web/assets/events-DDQlbNRb.js +1 -0
- package/dist/web/assets/get-started-B3_jDaTo.js +1 -0
- package/dist/web/assets/{index-COFVU9FF.js → index-DESr3-Rq.js} +5 -5
- package/dist/web/assets/{label-multi-select-CqqyXZZQ.js → label-multi-select-DYnV5CnF.js} +1 -1
- package/dist/web/assets/labels-Br0BOR_d.js +1 -0
- package/dist/web/assets/{last-call-DXzu-lgy.js → last-call-DQHmzSx9.js} +1 -1
- package/dist/web/assets/{login-DCh-HlWK.js → login-BAnCYytu.js} +1 -1
- package/dist/web/assets/{mutations-Dj5x6tSJ.js → mutations-B3jbqBsA.js} +1 -1
- package/dist/web/assets/{pairing-E4vbULM4.js → pairing-C1S88iMj.js} +1 -1
- package/dist/web/assets/{public-url-CCaLIiMZ.js → public-url-BoSol5Rt.js} +1 -1
- package/dist/web/assets/{select-6g9M6sE3.js → select-CjDJAlMf.js} +1 -1
- package/dist/web/assets/{settings-DXB-Aio7.js → settings-DTprvEn3.js} +1 -1
- package/dist/web/assets/{setup-DaByJmX2.js → setup-DkeFAoTi.js} +1 -1
- package/dist/web/assets/{sheet-B8d0NSgM.js → sheet-CQ1hG6mF.js} +1 -1
- package/dist/web/assets/{step-url-Dx6UlEE5.js → step-url-B_HuVNnd.js} +1 -1
- package/dist/web/assets/test-email-button-D3GmMouA.js +1 -0
- package/dist/web/assets/{toggle-group-CnBUKeeA.js → toggle-group-jgPklWgu.js} +1 -1
- package/dist/web/assets/{use-delivery-speed-3E7cSRZE.js → use-delivery-speed-n5-lnVz6.js} +1 -1
- package/dist/web/assets/{webhook-bits-D9CdojP0.js → webhook-bits-BtV3Echq.js} +1 -1
- package/dist/web/assets/{webhook-sheet-Cc5RfKBJ.js → webhook-sheet-ByWrp_sw.js} +1 -1
- package/dist/web/assets/{webhooks-DDu_k-nG.js → webhooks-DmHVQ9L0.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/admin-BJNe41GS.js.map +0 -1
- package/dist/audit-DCvHAahA.js +0 -2
- package/dist/commands-D6cZgm-K.js.map +0 -1
- package/dist/config-7aAYcVSK.js.map +0 -1
- package/dist/config-DS2ClYL5.js +0 -2
- package/dist/db-Ddb-yVQt.js +0 -2
- package/dist/instance-2HS-Rgwc.js +0 -2
- package/dist/listen-BRc0sjh1.js.map +0 -1
- package/dist/listen-KUzDHKrZ.js +0 -2
- package/dist/mcpheader-BPhjNLzu.js +0 -2
- package/dist/mcpheader-C4j_SH1P.js.map +0 -1
- package/dist/mcpsetup-CTi6Y9EY.js +0 -2
- package/dist/mcpsetup-DvMOc6Wq.js.map +0 -1
- package/dist/profile-BBSpPKmq.js.map +0 -1
- package/dist/profile-CY4RnknJ.js +0 -2
- package/dist/recipes-C0ZTufFs.js +0 -2
- package/dist/recipes-nmhjn9gG.js +0 -123
- package/dist/recipes-nmhjn9gG.js.map +0 -1
- package/dist/server-DhmOZECp.js.map +0 -1
- package/dist/service-B3E_3pph.js +0 -2
- package/dist/service-D9ncVbsu.js.map +0 -1
- package/dist/service-DYYbUYWS.js.map +0 -1
- package/dist/settings-BfFrufSv.js.map +0 -1
- package/dist/settings-CqouaxRg.js +0 -2
- package/dist/types-CRJeB5ns.js +0 -39
- package/dist/types-CRJeB5ns.js.map +0 -1
- package/dist/ui-B8Sd4Y7Y.js +0 -81
- package/dist/ui-B8Sd4Y7Y.js.map +0 -1
- package/dist/web/assets/cli-DcQ046Hh.js +0 -1
- package/dist/web/assets/events-CineWDK3.js +0 -1
- package/dist/web/assets/get-started-Qx94po_5.js +0 -1
- package/dist/web/assets/labels-BUTDNNJE.js +0 -1
- package/dist/web/assets/test-email-button-BGKbedCk.js +0 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { d as NPX, i as saveProfile, n as loadProfile, s as ensurePrivateDir } from "./profile-
|
|
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 {
|
|
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-
|
|
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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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as now, r as json } from "./db-
|
|
2
|
+
import { i as now, r as json } from "./db-XVZ0JWgA.js";
|
|
3
3
|
//#region server/audit.ts
|
|
4
4
|
/**
|
|
5
5
|
* SQL condition for an MCP tool call in audit_log: an agent actor and an action without a "." (tool
|
|
@@ -76,4 +76,4 @@ var AuditLog = class {
|
|
|
76
76
|
//#endregion
|
|
77
77
|
export { mcpToolCallSql as n, AuditLog as t };
|
|
78
78
|
|
|
79
|
-
//# sourceMappingURL=audit-
|
|
79
|
+
//# sourceMappingURL=audit-CDBJ60bx.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-
|
|
1
|
+
{"version":3,"file":"audit-CDBJ60bx.js","names":[],"sources":["../server/audit.ts"],"sourcesContent":["import type { ActorType, AuditEntry, AuditOutcome, Page } from \"../shared/types.ts\";\nimport type { Bus } from \"./bus.ts\";\nimport { type Db, json, now } from \"./db/index.ts\";\n\nexport interface AuditInput {\n actorType: ActorType;\n actorId?: string | null;\n /** MCP tool name or console action, e.g. \"send_message\", \"agent.create\", \"account.connect\". */\n action: string;\n accountId?: string | null;\n target?: string | null;\n outcome: AuditOutcome;\n /** Required for denials: the guardrail that blocked it (\"allow_to\", \"label_scope\", \"rate_limit\", …). */\n reason?: string | null;\n durationMs?: number | null;\n /** Small, non-sensitive context. Never message bodies, keys or tokens. */\n detail?: Record<string, unknown> | null;\n}\n\n/**\n * SQL condition for an MCP tool call in audit_log: an agent actor and an action without a \".\" (tool\n * names are like \"send_message\"; \"pairing.key_delivered\" and console actions have a dot). The same\n * rule as isMcpToolAction in shared/types.ts (used by the console). `t` is the table alias, if any.\n *\n * Every outcome counts, including calls rejected before a tool ran (unknown tool, invalid arguments,\n * a malformed tools/call): those are recorded with outcome \"error\" (see rejectedCall in\n * server/mcp/server.ts), so the Overview's \"Tool calls\" counts them. Anything that needs proof that\n * an agent works (anyAgentVerified, the wizard's checks) adds `outcome = 'ok'`.\n */\nexport function mcpToolCallSql(t?: string): string {\n const c = t ? `${t}.` : \"\";\n return `${c}actor_type = 'agent' AND instr(${c}action, '.') = 0`;\n}\n\nexport interface AuditQuery {\n agentId?: string;\n accountId?: string;\n outcome?: AuditOutcome;\n action?: string;\n /** Opaque cursor from a previous page. */\n cursor?: string | null;\n limit?: number;\n}\n\ninterface AuditRow {\n id: number;\n ts: string;\n actor_type: ActorType;\n actor_id: string | null;\n actor_name: string | null;\n action: string;\n account_id: string | null;\n target: string | null;\n outcome: AuditOutcome;\n reason: string | null;\n duration_ms: number | null;\n detail: string | null;\n}\n\nconst SELECT = `SELECT a.*, CASE a.actor_type WHEN 'agent' THEN ag.name WHEN 'admin' THEN 'admin' ELSE NULL END AS actor_name\n FROM audit_log a LEFT JOIN agents ag ON a.actor_type = 'agent' AND ag.id = a.actor_id`;\n\nconst toEntry = (r: AuditRow): AuditEntry => ({\n id: r.id,\n ts: r.ts,\n actorType: r.actor_type,\n actorId: r.actor_id,\n actorName: r.actor_name,\n action: r.action,\n accountId: r.account_id,\n target: r.target,\n outcome: r.outcome,\n reason: r.reason,\n durationMs: r.duration_ms,\n detail: json.parse<Record<string, unknown> | null>(r.detail, null),\n});\n\n/** Append-only audit log. Every agent tool call and every admin mutation is recorded. */\nexport class AuditLog {\n constructor(\n private readonly db: Db,\n private readonly bus: Bus,\n ) {}\n\n record(input: AuditInput): AuditEntry {\n const { lastInsertRowid } = this.db.run(\n `INSERT INTO audit_log (ts, actor_type, actor_id, action, account_id, target, outcome, reason, duration_ms, detail)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n now(),\n input.actorType,\n input.actorId ?? null,\n input.action,\n input.accountId ?? null,\n input.target ?? null,\n input.outcome,\n input.reason ?? null,\n input.durationMs ?? null,\n input.detail ? json.str(input.detail) : null,\n );\n const entry = toEntry(this.db.get<AuditRow>(`${SELECT} WHERE a.id = ?`, lastInsertRowid)!);\n this.bus.emit(\"audit\", entry);\n return entry;\n }\n\n /** Newest first. */\n list(q: AuditQuery = {}): Page<AuditEntry> {\n const where: string[] = [];\n const params: (string | number)[] = [];\n const add = (clause: string, value: string | number) => {\n where.push(clause);\n params.push(value);\n };\n if (q.agentId) add(\"a.actor_id = ?\", q.agentId);\n if (q.accountId) add(\"a.account_id = ?\", q.accountId);\n if (q.outcome) add(\"a.outcome = ?\", q.outcome);\n if (q.action) add(\"a.action = ?\", q.action);\n const before = Number(q.cursor);\n if (q.cursor && Number.isInteger(before)) add(\"a.id < ?\", before);\n const limit = Math.min(Math.max(q.limit ?? 50, 1), 200);\n const rows = this.db.all<AuditRow>(\n `${SELECT} ${where.length ? \"WHERE \" + where.join(\" AND \") : \"\"} ORDER BY a.id DESC LIMIT ?`,\n ...params,\n limit + 1,\n );\n const items = rows.slice(0, limit).map(toEntry);\n return { items, nextCursor: rows.length > limit ? String(items.at(-1)!.id) : null };\n }\n\n /** Deletes entries older than `beforeIso`. Returns the number removed. */\n prune(beforeIso: string): number {\n return this.db.run(\"DELETE FROM audit_log WHERE ts < ?\", beforeIso).changes;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AA6BA,SAAgB,eAAe,GAAoB;CACjD,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK;CACxB,OAAO,GAAG,EAAE,iCAAiC,EAAE;AACjD;AA2BA,MAAM,SAAS;;AAGf,MAAM,WAAW,OAA6B;CAC5C,IAAI,EAAE;CACN,IAAI,EAAE;CACN,WAAW,EAAE;CACb,SAAS,EAAE;CACX,WAAW,EAAE;CACb,QAAQ,EAAE;CACV,WAAW,EAAE;CACb,QAAQ,EAAE;CACV,SAAS,EAAE;CACX,QAAQ,EAAE;CACV,YAAY,EAAE;CACd,QAAQ,KAAK,MAAsC,EAAE,QAAQ,IAAI;AACnE;;AAGA,IAAa,WAAb,MAAsB;CAED;CACA;CAFnB,YACE,IACA,KACA;EAFiB,KAAA,KAAA;EACA,KAAA,MAAA;CAChB;CAEH,OAAO,OAA+B;EACpC,MAAM,EAAE,oBAAoB,KAAK,GAAG,IAClC;+CAEA,IAAI,GACJ,MAAM,WACN,MAAM,WAAW,MACjB,MAAM,QACN,MAAM,aAAa,MACnB,MAAM,UAAU,MAChB,MAAM,SACN,MAAM,UAAU,MAChB,MAAM,cAAc,MACpB,MAAM,SAAS,KAAK,IAAI,MAAM,MAAM,IAAI,IAC1C;EACA,MAAM,QAAQ,QAAQ,KAAK,GAAG,IAAc,GAAG,OAAO,kBAAkB,eAAe,CAAE;EACzF,KAAK,IAAI,KAAK,SAAS,KAAK;EAC5B,OAAO;CACT;;CAGA,KAAK,IAAgB,CAAC,GAAqB;EACzC,MAAM,QAAkB,CAAC;EACzB,MAAM,SAA8B,CAAC;EACrC,MAAM,OAAO,QAAgB,UAA2B;GACtD,MAAM,KAAK,MAAM;GACjB,OAAO,KAAK,KAAK;EACnB;EACA,IAAI,EAAE,SAAS,IAAI,kBAAkB,EAAE,OAAO;EAC9C,IAAI,EAAE,WAAW,IAAI,oBAAoB,EAAE,SAAS;EACpD,IAAI,EAAE,SAAS,IAAI,iBAAiB,EAAE,OAAO;EAC7C,IAAI,EAAE,QAAQ,IAAI,gBAAgB,EAAE,MAAM;EAC1C,MAAM,SAAS,OAAO,EAAE,MAAM;EAC9B,IAAI,EAAE,UAAU,OAAO,UAAU,MAAM,GAAG,IAAI,YAAY,MAAM;EAChE,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,EAAE,SAAS,IAAI,CAAC,GAAG,GAAG;EACtD,MAAM,OAAO,KAAK,GAAG,IACnB,GAAG,OAAO,GAAG,MAAM,SAAS,WAAW,MAAM,KAAK,OAAO,IAAI,GAAG,8BAChE,GAAG,QACH,QAAQ,CACV;EACA,MAAM,QAAQ,KAAK,MAAM,GAAG,KAAK,CAAC,CAAC,IAAI,OAAO;EAC9C,OAAO;GAAE;GAAO,YAAY,KAAK,SAAS,QAAQ,OAAO,MAAM,GAAG,EAAE,CAAC,CAAE,EAAE,IAAI;EAAK;CACpF;;CAGA,MAAM,WAA2B;EAC/B,OAAO,KAAK,GAAG,IAAI,sCAAsC,SAAS,CAAC,CAAC;CACtE;AACF"}
|
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-
|
|
60
|
+
const { runForeground } = await import("./server-DiPOZSU8.js");
|
|
80
61
|
await runForeground({
|
|
81
62
|
...configInput(o),
|
|
82
63
|
dev: !!o.dev,
|
|
@@ -86,16 +67,16 @@ withServerOptions(program.command("start", { isDefault: true }).description("run
|
|
|
86
67
|
});
|
|
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
|
-
const { loadConfig } = await import("./config-
|
|
90
|
-
const { installService } = await import("./service-
|
|
70
|
+
const { loadConfig } = await import("./config-DCuYmK68.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-
|
|
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-
|
|
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);
|
|
@@ -116,13 +97,13 @@ program.command("reset-password").description("forgot the console password? Remo
|
|
|
116
97
|
const dataDir = resolve(o.data ?? process.env.AGENTINBOX_DATA ?? join(homedir(), ".agentinbox"));
|
|
117
98
|
const dbPath = join(dataDir, "agentinbox.db");
|
|
118
99
|
if (!existsSync(dbPath)) throw new Error(`No agentinbox data in ${dataDir}. If agentinbox runs as a system service, run this with sudo; otherwise pass the data directory it uses with --data.`);
|
|
119
|
-
const { loadConfig } = await import("./config-
|
|
120
|
-
const { Db } = await import("./db-
|
|
100
|
+
const { loadConfig } = await import("./config-DCuYmK68.js");
|
|
101
|
+
const { Db } = await import("./db-CaPyxUtw.js");
|
|
121
102
|
const { createBus } = await import("./bus-OKIGut72.js");
|
|
122
|
-
const { SettingsStore } = await import("./settings-
|
|
123
|
-
const { AuditLog } = await import("./audit-
|
|
103
|
+
const { SettingsStore } = await import("./settings-YVzbOMYE.js");
|
|
104
|
+
const { AuditLog } = await import("./audit-LsAWaKJT.js");
|
|
124
105
|
const { currentSetupToken, isClaimed, resetAdminPassword } = await import("./auth-D_FWbtRd.js");
|
|
125
|
-
const { runningInstance } = await import("./instance-
|
|
106
|
+
const { runningInstance } = await import("./instance-BW7hjbyx.js");
|
|
126
107
|
const { consoleUrls } = await import("./urls-Dp8pBGMU.js");
|
|
127
108
|
const running = runningInstance(dataDir);
|
|
128
109
|
const config = loadConfig({
|
|
@@ -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-
|
|
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",
|
|
@@ -171,7 +152,7 @@ program.commandsGroup(SERVER_GROUP).helpCommand("help [command]", "show help for
|
|
|
171
152
|
async function serverUrl(flag) {
|
|
172
153
|
let raw = flag ?? process.env.AGENTINBOX_URL;
|
|
173
154
|
if (!raw) {
|
|
174
|
-
const { runningInstance } = await import("./instance-
|
|
155
|
+
const { runningInstance } = await import("./instance-BW7hjbyx.js");
|
|
175
156
|
const running = runningInstance(resolve(process.env.AGENTINBOX_DATA || join(homedir(), ".agentinbox")));
|
|
176
157
|
const host = running && ![
|
|
177
158
|
"0.0.0.0",
|
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
|
-
import {
|
|
3
|
-
import { d as NPX } from "./profile-
|
|
2
|
+
import { r as EVENT_TYPES } from "./types-2rItLIhH.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-nmhjn9gG.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 <
|
|
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-
|
|
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-
|
|
56
|
-
const { loadProfile } = await import("./profile-
|
|
57
|
-
const { setupMcp, mcpTarget } = await import("./mcpsetup-
|
|
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-
|
|
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-
|
|
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 <
|
|
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 {
|
|
77
|
-
const
|
|
78
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
164
|
+
//# sourceMappingURL=commands-B1JRkH7_.js.map
|