xaq-cli 0.1.0-nightly.89 → 0.1.0-nightly.91

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 (64) hide show
  1. package/dist/{admin-B0qZYQ8g.js → admin-UKJE67mn.js} +6 -7
  2. package/dist/{admin-B0qZYQ8g.js.map → admin-UKJE67mn.js.map} +1 -1
  3. package/dist/{cli-DozpH5Tw.js → cli-C9lES1ug.js} +2 -2
  4. package/dist/{cli-DozpH5Tw.js.map → cli-C9lES1ug.js.map} +1 -1
  5. package/dist/cli.js +11 -11
  6. package/dist/cli.js.map +1 -1
  7. package/dist/{commands-Bb3Jp0f_.js → commands-BKr8Ejx0.js} +2 -2
  8. package/dist/{commands-Bb3Jp0f_.js.map → commands-BKr8Ejx0.js.map} +1 -1
  9. package/dist/{commands-vEfok6bQ.js → commands-Bo6-7SBs.js} +17 -17
  10. package/dist/{commands-vEfok6bQ.js.map → commands-Bo6-7SBs.js.map} +1 -1
  11. package/dist/{connect-DzW9840r.js → connect-xUMBNHSZ.js} +8 -8
  12. package/dist/{connect-DzW9840r.js.map → connect-xUMBNHSZ.js.map} +1 -1
  13. package/dist/hermes-DcrI-TtP.js +3 -0
  14. package/dist/{hermes-Ccdi1g6M.js → hermes-Dic9rVz6.js} +4 -5
  15. package/dist/{hermes-Ccdi1g6M.js.map → hermes-Dic9rVz6.js.map} +1 -1
  16. package/dist/{import-B-xgD799.js → import-cL9vj0jq.js} +4 -4
  17. package/dist/{import-B-xgD799.js.map → import-cL9vj0jq.js.map} +1 -1
  18. package/dist/{listen-B6u7Gt6X.js → listen-C642JHIc.js} +5 -6
  19. package/dist/{listen-B6u7Gt6X.js.map → listen-C642JHIc.js.map} +1 -1
  20. package/dist/listen-CcZUPf3p.js +2 -0
  21. package/dist/{mcpheader-Asnd_g6P.js → mcpheader-CK2dhg-I.js} +1 -1
  22. package/dist/{mcpheader-Cx70TCbz.js → mcpheader-D94qF32t.js} +2 -3
  23. package/dist/{mcpheader-Cx70TCbz.js.map → mcpheader-D94qF32t.js.map} +1 -1
  24. package/dist/mcpsetup-C9mGhinf.js +2 -0
  25. package/dist/{mcpsetup-BymOG2gO.js → mcpsetup-xVCFyAEU.js} +4 -5
  26. package/dist/{mcpsetup-BymOG2gO.js.map → mcpsetup-xVCFyAEU.js.map} +1 -1
  27. package/dist/{own-dirs-3-IxMhGv.js → own-dirs-D61k1PPA.js} +2 -2
  28. package/dist/{own-dirs-3-IxMhGv.js.map → own-dirs-D61k1PPA.js.map} +1 -1
  29. package/dist/profile-BWK08YwL.js +2 -0
  30. package/dist/{profile-B8LfeVb-.js → profile-QqEY5L3k.js} +115 -4
  31. package/dist/profile-QqEY5L3k.js.map +1 -0
  32. package/dist/recipes-CwyZRyXM.js +3 -0
  33. package/dist/{recipes-D4dn2FgR.js → recipes-V8_-S1TM.js} +3 -3
  34. package/dist/{recipes-D4dn2FgR.js.map → recipes-V8_-S1TM.js.map} +1 -1
  35. package/dist/{run-Naf4FpSh.js → run-C0fpnYAb.js} +2 -2
  36. package/dist/{run-Naf4FpSh.js.map → run-C0fpnYAb.js.map} +1 -1
  37. package/dist/{server-PBZlvr8o.js → server-DTxOHzZJ.js} +5 -4
  38. package/dist/{server-PBZlvr8o.js.map → server-DTxOHzZJ.js.map} +1 -1
  39. package/dist/{service-B4g01DFf.js → service-C-bf-vFa.js} +7 -8
  40. package/dist/{service-B4g01DFf.js.map → service-C-bf-vFa.js.map} +1 -1
  41. package/dist/service-C2nRdQnH.js +2 -0
  42. package/dist/{service-D-verWHJ.js → service-CaLi0ECi.js} +1 -1
  43. package/dist/{service-CY2d9kj-.js → service-D5AMNljC.js} +308 -9
  44. package/dist/service-D5AMNljC.js.map +1 -0
  45. package/dist/{settings-C0rWKyEE.js → settings-CDJkgV6P.js} +2 -2
  46. package/dist/{settings-C0rWKyEE.js.map → settings-CDJkgV6P.js.map} +1 -1
  47. package/dist/settings-DlwSOO5Y.js +2 -0
  48. package/dist/{smoke-C2Zm2jbn.js → smoke-Db1MSKwT.js} +6 -139
  49. package/dist/smoke-Db1MSKwT.js.map +1 -0
  50. package/dist/spawn-CAmF_QFI.js +141 -0
  51. package/dist/spawn-CAmF_QFI.js.map +1 -0
  52. package/package.json +1 -1
  53. package/dist/fsutil-DGrtqggb.js +0 -117
  54. package/dist/fsutil-DGrtqggb.js.map +0 -1
  55. package/dist/hermes-neOJoelw.js +0 -3
  56. package/dist/listen-BgNbGAri.js +0 -2
  57. package/dist/mcpsetup-CT7AvSdb.js +0 -2
  58. package/dist/profile-APHtZgAg.js +0 -2
  59. package/dist/profile-B8LfeVb-.js.map +0 -1
  60. package/dist/recipes-D0Qmc75i.js +0 -3
  61. package/dist/service-CCbVYqVp.js +0 -2
  62. package/dist/service-CY2d9kj-.js.map +0 -1
  63. package/dist/settings-Dlhgb3bB.js +0 -2
  64. package/dist/smoke-C2Zm2jbn.js.map +0 -1
@@ -1,13 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as NPX } from "./version-BxH7OuWD.js";
3
- import { i as ensurePrivateDir } from "./fsutil-DGrtqggb.js";
3
+ import { i as saveProfile, n as loadProfile, v as ensurePrivateDir } from "./profile-QqEY5L3k.js";
4
4
  import { c as profilePath, i as deadPath, o as logPath, p as validProfileName } from "./paths-Bo6qtWNh.js";
5
- import { i as saveProfile, n as loadProfile } from "./profile-B8LfeVb-.js";
6
- import { b as TransportError, f as isHermesRoute, x as checkTransport } from "./recipes-D4dn2FgR.js";
5
+ import { b as TransportError, f as isHermesRoute, x as checkTransport } from "./recipes-V8_-S1TM.js";
7
6
  import { i as safeText, r as formatDuration } from "./ui-B8Sd4Y7Y.js";
8
- import { D as ApiError, N as getSelf, b as forwardEvent, g as resolveListen, h as forwardSecret, m as describeFilter, o as routeWarning, u as DEFAULT_LISTEN_TYPES } from "./hermes-Ccdi1g6M.js";
9
- import { c as readDead, d as runCommand, f as Dispatcher, i as outputLine, l as readStatus, m as hasAccess, p as describeGrants, s as pidAlive, u as writeDead } from "./listen-B6u7Gt6X.js";
10
- import { r as installedServiceLabel } from "./service-B4g01DFf.js";
7
+ import { D as ApiError, N as getSelf, b as forwardEvent, g as resolveListen, h as forwardSecret, m as describeFilter, o as routeWarning, u as DEFAULT_LISTEN_TYPES } from "./hermes-Dic9rVz6.js";
8
+ import { c as readDead, d as runCommand, f as Dispatcher, i as outputLine, l as readStatus, m as hasAccess, p as describeGrants, s as pidAlive, u as writeDead } from "./listen-C642JHIc.js";
9
+ import { r as installedServiceLabel } from "./service-C-bf-vFa.js";
11
10
  import pc from "picocolors";
12
11
  //#region server/listen/admin.ts
13
12
  const out = (s = "") => process.stdout.write(`${s}\n`);
@@ -216,4 +215,4 @@ async function replayDead(flags, opts = {}) {
216
215
  //#endregion
217
216
  export { clearDead, printDead, printSecret, printStatus, replayDead };
218
217
 
219
- //# sourceMappingURL=admin-B0qZYQ8g.js.map
218
+ //# sourceMappingURL=admin-UKJE67mn.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"admin-B0qZYQ8g.js","names":[],"sources":["../server/listen/admin.ts"],"sourcesContent":["import pc from \"picocolors\";\nimport { ApiError, getSelf } from \"./api.ts\";\nimport { describeGrants, hasAccess } 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 { routeWarning } from \"./hermes.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 { installedServiceLabel } 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 XAQ_WEBHOOK_SECRET=$(xaq 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 const route = forward && isHermesRoute(forward) ? routeWarning(name, forward) : null;\n if (route?.level === \"warn\") out(`${pc.bold(\"Route\")} ${pc.yellow(route.message)}`);\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 const installed = installedServiceLabel(name);\n if (installed) svc = `installed (${installed}; 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, self.connections);\n out(`${pc.bold(\"Access\")} ${hasAccess(self) ? 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
+ {"version":3,"file":"admin-UKJE67mn.js","names":[],"sources":["../server/listen/admin.ts"],"sourcesContent":["import pc from \"picocolors\";\nimport { ApiError, getSelf } from \"./api.ts\";\nimport { describeGrants, hasAccess } 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 { routeWarning } from \"./hermes.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 { installedServiceLabel } 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 XAQ_WEBHOOK_SECRET=$(xaq 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 const route = forward && isHermesRoute(forward) ? routeWarning(name, forward) : null;\n if (route?.level === \"warn\") out(`${pc.bold(\"Route\")} ${pc.yellow(route.message)}`);\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 const installed = installedServiceLabel(name);\n if (installed) svc = `installed (${installed}; 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, self.connections);\n out(`${pc.bold(\"Access\")} ${hasAccess(self) ? 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":";;;;;;;;;;;AAoBA,MAAM,OAAO,IAAI,OAAO,QAAQ,OAAO,MAAM,GAAG,EAAE,GAAG;AACrD,MAAM,WAAW,YAAqB,YAAA,YAA8B,KAAK,cAAc;AACvF,MAAM,OAAO,QAAoC,MAAM,GAAG,eAAe,KAAK,IAAI,IAAI,KAAK,MAAM,GAAG,CAAC,EAAE,QAAQ;;AAK/G,SAAgB,YAAY,aAAqB,MAAkC;CACjF,MAAM,OAAO,iBAAiB,WAAW;CACzC,MAAM,UAAU,YAAY,IAAI;CAChC,IAAI,EAAE,QAAQ,YAAY,cAAc,OAAO;CAC/C,IAAI,KAAK,QAAQ;EACf,SAAS,cAAc;GAAE,GAAG;GAAS,SAAS,KAAA;GAAW,eAAe,KAAA;EAAU,CAAC,CAAC,CAAC;EACrF,UAAU;CACZ;CACA,IAAI,SAAS;EACX,IAAI,QAAQ,SAAS,QAAQ,UAAU;GAAE,GAAG,QAAQ;GAAS;EAAO;OAC/D,QAAQ,gBAAgB;EAC7B,YAAY,MAAM,OAAO;EACzB,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG,KAAK,SAAS,YAAY,YAAY,2CAA2C,KAAK,GAAG,KAAK,SAAS,2BAA2B,GAAG,IAAI,CAAC;CAC5K;CAEA,IAAI,MAAM;AACZ;AAIA,eAAsB,YAAY,aAAoC;CACpE,MAAM,OAAO,iBAAiB,WAAW;CACzC,MAAM,UAAU,YAAY,IAAI;CAChC,MAAM,KAAK,WAAW,IAAI;CAC1B,MAAM,QAAQ,KAAK,SAAS,GAAG,GAAG,KAAK,CAAC,GAAG,YAAY;CACvD,MAAM,OAAO,SAAS,IAAI;CAE1B,IAAI,GAAG,GAAG,KAAK,SAAS,EAAE,KAAK,KAAK,IAAI,GAAG,KAAK,YAAY,IAAI,CAAC,GAAG;CACpE,IAAI,GAAG,GAAG,KAAK,OAAO,EAAE,OAAO,SAAS,QAAQ,SAAS,EAAE,GAAG,GAAG,KAAK,IAAI,QAAQ,QAAQ,EAAE,GAAG;CAC/F,IAAI,GAAG,GAAG,KAAK,QAAQ,EAAE,MAAM,QAAQ,KAAK;CAC5C,IAAI,GAAG,GAAG,KAAK,UAAU,EAAE,IAAI,IAAI,YAAY,QAAQ,UAAU;CAEjE,MAAM,OAAO,MAAM,GAAG,SAAS,KAAA,IAAY,GAAG,OAAO,QAAQ;CAC7D,MAAM,UAAU,MAAM,GAAG,YAAY,KAAA,IAAY,GAAG,UAAU,QAAQ,SAAS;CAC/E,MAAM,UAAU,CAAC,OAAO,QAAQ,SAAS,MAAM,GAAG,MAAM,MAAM,UAAU,WAAW,YAAY,IAAI,CAAC,CAAC,OAAO,OAAO;CACnH,IAAI,GAAG,GAAG,KAAK,MAAM,EAAE,QAAQ,QAAQ,SAAS,QAAQ,KAAK,KAAK,IAAI,GAAG,KAAK,mDAAmD,GAAG;CACpI,IACE,GAAG,GAAG,KAAK,QAAQ,EAAE,MACnB,QAAQ,OAAO,SACX,QAAQ,MAAM,KAAK,IAAI,IACvB,GAAG,qBAAqB,KAAK,IAAI,EAAE,GAAG,GAAG,KAAK,yDAAyD,KAE/G;CAEA,IAAI,QAA2D;CAC/D,IAAI;EACF,QAAQ,cAAc,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC;CAC3C,QAAQ,CAER;CACA,IAAI,GAAG,GAAG,KAAK,SAAS,EAAE,KAAM,SAAS,IAAI,YAAa,QAAQ,eAAe,KAAK,IAAI,MAAM;CAChG,MAAM,eAAe,SAAS,MAAM,GAAG,iBAAiB,KAAA,IAAY,GAAG,eAAgB,OAAO,gBAAgB;CAC9G,IAAI,cAAc,IAAI,GAAG,GAAG,KAAK,OAAO,EAAE,OAAO,eAAe,eAAe,GAAI,EAAE,wCAAkD;CACvI,MAAM,QAAQ,WAAW,cAAc,OAAO,IAAI,aAAa,MAAM,OAAO,IAAI;CAChF,IAAI,OAAO,UAAU,QAAQ,IAAI,GAAG,GAAG,KAAK,OAAO,EAAE,OAAO,GAAG,OAAO,MAAM,OAAO,GAAG;CACtF,IAAI,GAAG,GAAG,KAAK,QAAQ,EAAE,MAAM,WAAW,MAAM;EAAE,MAAM,QAAQ;EAAM,SAAS,UAAU,EAAE,KAAK,QAAQ,IAAI;CAAK,GAAG,QAAQ,IAAI,CAAC,GAAG;CAEpI,IAAI,MAAM;CACV,IAAI,QAAQ,aAAa,WAAW,QAAQ,aAAa,UAAU;EACjE,MAAM,YAAY,sBAAsB,IAAI;EAC5C,IAAI,WAAW,MAAM,cAAc,UAAU,aAAa,IAAI,wBAAwB,QAAQ,IAAI,EAAE;CACtG;CACA,IAAI,GAAG,GAAG,KAAK,SAAS,EAAE,KAAK,KAAK;CAEpC,IAAI;EAEF,MAAM,eAAe,QAAQ,KAAK,EAAE,UAAU,QAAQ,SAAS,CAAC;EAChE,MAAM,OAAO,MAAM,QAAQ,QAAQ,KAAK,QAAQ,QAAQ,GAAI;EAC5D,IAAI,GAAG,GAAG,KAAK,KAAK,EAAE,SAAS,GAAG,MAAM,OAAO,GAAG;EAElD,MAAM,QAAQ,eAAe,KAAK,QAAQ,KAAK,WAAW;EAC1D,IAAI,GAAG,GAAG,KAAK,QAAQ,EAAE,MAAM,UAAU,IAAI,IAAI,MAAM,KAAK,GAAG,OAAO,MAAM,EAAG,GAAG;EAClF,KAAK,MAAM,KAAK,MAAM,MAAM,CAAC,GAAG,IAAI,aAAa,GAAG;CACtD,SAAS,KAAK;EACZ,MAAM,UAAU,eAAe,aAAa,IAAI,WAAW,OAAO,IAAI,WAAW;EACjF,MAAM,MAAM,eAAe,YAAY,IAAI,WAAW,IAAK,IAAI,QAAmB,eAAe,QAAQ,IAAI,QAAQ,MAAM,IAAI,CAAC,CAAC,KAAK,OAAO,GAAG;EAChJ,IAAI,eAAe,gBAAgB,IAAI,GAAG,GAAG,KAAK,KAAK,EAAE,SAAS,GAAG,IAAI,gBAAgB,KAAK,GAAG;OAC5F,IAAI,GAAG,GAAG,KAAK,KAAK,EAAE,SAAS,UAAU,GAAG,IAAI,aAAc,IAAc,SAAS,IAAI,GAAG,OAAO,gBAAgB,IAAI,EAAE,GAAG;CACnI;CAEA,IAAI,CAAC,IACH,IAAI,GAAG,GAAG,KAAK,UAAU,EAAE,IAAI,GAAG,KAAK,iBAAiB,GAAG;MACtD;EACL,MAAM,QAAQ,CAAC,QACX,GAAG,KAAK,cAAc,GAAG,YAAY,aAAa,IAAI,GAAG,SAAS,IAAI,GAAG,aAAa,KAAK,SAAS,GAAG,YAAY,GAAG,MAAM,GAAG,KAAK,0BAA0B,IAC9J,GAAG,YACD,GAAG,MAAM,gBAAgB,GAAG,IAAI,eAAe,IAAI,GAAG,cAAc,GAAG,IACvE,GAAG,OAAO,gBAAgB,GAAG,IAAI,iBAAiB,GAAG,iBAAiB,IAAI,IAAI,GAAG,eAAe,EAAE,EAAE,IAAI,SAAS,GAAG,eAAe,QAAQ,GAAG,MAAM,IAAI;EAC9J,IAAI,GAAG,GAAG,KAAK,UAAU,EAAE,IAAI,OAAO;EACtC,IACE,GAAG,GAAG,KAAK,QAAQ,EAAE,aAAa,GAAG,SAAS,eAAe,GAAG,cAAc,SAAS,GAAG,UAAU,MAAM,GAAG,QAAQ,gBAAgB,KAAK,GAAG,UAAU,MAAM,GAAG,QAAQ,uBAAuB,GAAG,gBAAgB,IAAI,GAAG,WAAW,GACtO;EACA,IAAI,GAAG,OAAO,QAAQ;GACpB,IAAI,GAAG,KAAK,QAAQ,CAAC;GACrB,KAAK,MAAM,KAAK,GAAG,OAAO,MAAM,GAAG,CAAC,GAAG;IACrC,MAAM,OAAO,EAAE,YAAY,cAAc,GAAG,MAAM,GAAG,IAAI,EAAE,YAAY,SAAS,GAAG,IAAI,GAAG,IAAI,EAAE,YAAY,aAAa,GAAG,OAAO,GAAG,IAAI,GAAG,KAAK,GAAG;IACrJ,IAAI,KAAK,KAAK,IAAI,EAAE,IAAI,GAAG,EAAE,KAAK,GAAG,GAAG,KAAK,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,IAAI,KAAK,EAAE,SAAS,aAAa,KAAK,EAAE,SAAS,EAAE,YAAY,cAAc,KAAK,SAAS,EAAE,OAAO,GAAG,MAAM,IAAI,GAAG;GAC/L;EACF;CACF;CACA,IAAI,GAAG,GAAG,KAAK,MAAM,EAAE,QAAQ,KAAK,SAAS,GAAG,IAAI,GAAG,KAAK,OAAO,QAAQ,KAAK,SAAS,IAAI,MAAM,IAAI,IAAI,GAAG,KAAK,cAAc,IAAI,cAAc,QAAQ,IAAI,EAAE,EAAE,IAAI,KAAK;CAC5K,IAAI,GAAG,GAAG,KAAK,KAAK,EAAE,SAAS,QAAQ,IAAI,GAAG;AAChD;AAIA,SAAgB,UAAU,aAAqB,MAAgC;CAC7E,MAAM,OAAO,iBAAiB,WAAW;CACzC,MAAM,UAAU,SAAS,IAAI;CAC7B,IAAI,KAAK,MAAM;EACb,KAAK,MAAM,KAAK,SAAS,IAAI,KAAK,UAAU,CAAC,CAAC;EAC9C;CACF;CACA,IAAI,CAAC,QAAQ,QAAQ;EACnB,IAAI,+BAA+B,KAAK,GAAG;EAC3C;CACF;CACA,KAAK,MAAM,KAAK,SAAS;EACvB,MAAM,IAAI,EAAE,QAAQ,KAAK;EACzB,IAAI,GAAG,GAAG,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,KAAK,GAAG,GAAG,KAAK,EAAE,EAAE,EAAE,IAAI,GAAG,KAAK,QAAQ,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,UAAU,GAAG;EAC3H,IAAI,GAAG,IAAI,YAAY,SAAS,EAAE,MAAM,SAAS,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE;EACzF,IAAI,GAAG,KAAK,OAAO,SAAS,EAAE,OAAO,GAAG,GAAG,CAAC;CAC9C;CACA,IAAI;CACJ,IAAI,GAAG,KAAK,GAAG,QAAQ,OAAO,aAAa,QAAQ,SAAS,IAAI,MAAM,GAAG,MAAM,SAAS,IAAI,EAAE,EAAE,CAAC;CACjG,IAAI,GAAG,KAAK,gBAAgB,IAAI,uBAAuB,QAAQ,IAAI,EAAE,0CAA0C,CAAC;CAChH,IAAI,GAAG,KAAK,qIAAqI,CAAC;AACpJ;AAEA,SAAgB,UAAU,aAAqB,IAAmB;CAChE,MAAM,OAAO,iBAAiB,WAAW;CACzC,MAAM,UAAU,SAAS,IAAI;CAC7B,MAAM,OAAO,KAAK,QAAQ,QAAQ,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;CACxD,UAAU,MAAM,IAAI;CACpB,IAAI,WAAW,QAAQ,SAAS,KAAK,OAAO,aAAa,QAAQ,SAAS,KAAK,WAAW,IAAI,KAAK,IAAI,EAAE;AAC3G;;;;;AAMA,eAAsB,WAAW,OAAsC,OAAiD,CAAC,GAAoB;CAC3I,MAAM,OAAO,iBAAiB,MAAM,WAAA,SAA0B;CAC9D,MAAM,UAAU,YAAY,IAAI;CAChC,MAAM,EAAE,WAAW,cAAc,MAAM,SAAS;EAAE,GAAG;EAAO,MAAM;CAAM,CAAC;CAEzE,MAAM,SADM,SAAS,IACJ,CAAC,CAAC,QAAQ,MAAM,CAAC,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE;CAC/D,IAAI,CAAC,OAAO,QAAQ;EAClB,IAAI,MAAM,KAAK,yBAAyB,MAAM,GAAG,KAAK,+BAA+B,KAAK,GAAG;EAC7F,OAAO;CACT;CACA,MAAM,YAAsB,CAAC;CAC7B,IAAI,OAAO,MAAM,UAAU,KAAK,MAAM;CACtC,IAAI,OAAO,SAAS,UAAU,KAAK,SAAS;CAC5C,IAAI,CAAC,UAAU,QAAQ,MAAM,IAAI,MAAM,kKAAkK,IAAI,qBAAqB;CAClO,IAAI,OAAO,QAAQ,QAAQ,aAAa,SAAS,MAAM,IAAI,MAAM,mEAAmE;CAEpI,MAAM,YAAY,OAAO,iBAAiB;CAC1C,IAAI,OAAO,cAAc,iBAAiB,OAAO,GAAG;CACpD,MAAM,yBAAS,IAAI,IAAuB;CAC1C,MAAM,QAAQ,IAAI,IAAI,OAAO,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;CACnD,MAAM,aAAa,IAAI,WAAW;EAChC,SAAS;EACT,aAAa,OAAO;EACpB,aAAa,OAAO;EACpB,cAAc,KAAK;EACnB,KAAK,OAAO,KAAU,WAAW;GAC/B,MAAM,SAAmB,CAAC;GAC1B,IAAI,IAAI,UAAU,IAAI,MAAM,KAAK,OAAO,MAAM;IAC5C,MAAM,IAAI,MAAM,WAAW,OAAO,MAAM,IAAI,SAAS;KAAE;KAAW;KAAQ,KAAK,OAAO;IAAI,CAAC;IAC3F,IAAI,EAAE,IAAI,IAAI,UAAU,OAAO,MAAM;SAChC,OAAO,KAAK,YAAY,EAAE,OAAO;GACxC;GACA,IAAI,IAAI,UAAU,IAAI,SAAS,KAAK,OAAO,SAAS;IAClD,MAAM,IAAI,MAAM,aAAa,OAAO,QAAQ,KAAK,OAAO,QAAQ,QAAQ,IAAI,SAAS;KAAE,WAAW,KAAK,IAAI,WAAW,GAAM;KAAG;KAAQ,MAAM,cAAc,OAAO,QAAQ,GAAG;IAAE,CAAC;IAChL,IAAI,EAAE,IAAI,IAAI,UAAU,OAAO,SAAS;SACnC,OAAO,KAAK,YAAY,EAAE,OAAO;GACxC;GACA,OAAO;EACT;EACA,iBAAiB,CAAC;EAClB,SAAS,QAAQ;GACf,MAAM,IAAI,MAAM,IAAI,IAAI,GAAG;GAC3B,OAAO,IAAI,EAAE,IAAI;IAAE,GAAG;IAAG,yBAAQ,IAAI,KAAK,EAAA,CAAE,YAAY;IAAG,UAAU,EAAE,WAAW,IAAI;IAAU,OAAO,IAAI,aAAa;GAAS,CAAC;GAClI,IAAI,GAAG,GAAG,IAAI,GAAG,EAAE,IAAI,IAAI,IAAI,kBAAkB,SAAS,IAAI,aAAa,UAAU,GAAG,GAAG;EAC7F;EACA,aAAa,QAAQ;GACnB,IAAI,IAAI,YAAY,aAAa,IAAI,GAAG,GAAG,MAAM,GAAG,EAAE,IAAI,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK,UAAU;EAClG;CACF,CAAC;CACD,IAAI,aAAa,OAAO,OAAO,aAAa,OAAO,SAAS,IAAI,MAAM,GAAG,UAAU,OAAO,YAAY,iBAAiB;CAEvH,KAAK,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG;EACzD,MAAM,UAAU,EAAE,SAAS,SAAS,EAAE,QAAQ,QAAQ,MAAM,UAAU,SAAS,CAAC,CAAC,IAAI;EACrF,IAAI,CAAC,QAAQ,QAAQ;GACnB,IAAI,GAAG,GAAG,OAAO,GAAG,EAAE,IAAI,EAAE,IAAI,SAAS,EAAE,QAAQ,KAAK,OAAO,EAAE,uCAAuC,EAAE,QAAQ,GAAG,eAAe;GACpI,OAAO,IAAI,EAAE,IAAI,CAAC;GAClB;EACF;EACA,WAAW,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC;CACxC;CACA,MAAM,WAAW,KAAK;CAEtB,MAAM,WAAW,IAAI,IAAI,OAAO,KAAK,MAAM,EAAE,EAAE,CAAC;CAEhD,MAAM,UAAU,SAAS,IAAI;CAC7B,UAAU,MAAM,CAAC,GAAG,QAAQ,QAAQ,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,OAAO,OAAO,CAAC,CAAC;CACnF,IAAI,GAAG,OAAO,SAAS,OAAO,KAAK,aAAa,OAAO,KAAK,aAAa;CACzE,OAAO,OAAO;AAChB"}
@@ -74,7 +74,7 @@ Example:
74
74
  const { openAdminChannel } = await import("./admin-DbJXEo2d.js");
75
75
  const { TerminalPrompter } = await import("./prompt-BEH311I7.js");
76
76
  const { connectAgentMcp } = await import("./agent-B8a-Ivyd.js");
77
- const { SmokeRun } = await import("./run-Naf4FpSh.js");
77
+ const { SmokeRun } = await import("./run-C0fpnYAb.js");
78
78
  const { renderReport } = await import("./report-D2D_6E5O.js");
79
79
  if (!o.scratch) throw new Error("smoke google-workspace runs live on the connected Google account: it reads existing files and mail, and writes only into a new scratch folder and ONE draft to the account itself, which it removes again. Pass --scratch to run it.");
80
80
  const out = safeWriter(o.json ? process.stderr : process.stdout);
@@ -123,4 +123,4 @@ Example:
123
123
  //#endregion
124
124
  export { registerSmokeCommands };
125
125
 
126
- //# sourceMappingURL=cli-DozpH5Tw.js.map
126
+ //# sourceMappingURL=cli-C9lES1ug.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-DozpH5Tw.js","names":[],"sources":["../server/smoke/cli.ts"],"sourcesContent":["// `xaq smoke google-workspace --scratch`: run on xaq's machine, through the daemon's admin API over the local admin\n// channel (server/connections-cli/admin.ts) and /mcp as a temporary agent. See run.ts for what it does.\n\nimport type { Command } from \"commander\";\nimport { LEGACY_PRODUCT } from \"../brand.ts\";\nimport { resolveDataDir } from \"../config.ts\";\nimport { NPX } from \"../listen/version.ts\";\nimport type { SmokeFlags } from \"./run.ts\";\n\nconst GROUP = \"MCP connections (on xaq's machine):\";\n\n/**\n * A line printer that can't kill the run: once the stream fails (EIO or EPIPE from a terminal that went away, e.g.\n * after SIGHUP), later lines are dropped instead of throwing or crashing on an unhandled 'error'.\n */\nexport function safeWriter(stream: NodeJS.WritableStream): { print: (line?: string) => void; dispose: () => void } {\n let dead = false;\n const onError = () => {\n dead = true;\n };\n stream.on(\"error\", onError);\n return {\n print(line = \"\") {\n if (dead) return;\n try {\n stream.write(`${line}\\n`, (err) => {\n if (err) dead = true;\n });\n } catch {\n dead = true;\n }\n },\n dispose: () => stream.removeListener(\"error\", onError),\n };\n}\n\nexport interface SmokeSignalOptions {\n print: (line: string) => void;\n exit: (code: number) => void;\n /** The second Ctrl-C: the quick part of cleanup (agent, attachmentDirs), bounded. */\n fastCleanup: () => Promise<void>;\n /** What may still be there, in a sentence. */\n leftovers: () => string;\n /** Upper bound on the second Ctrl-C's cleanup before quitting anyway (default 8 s). */\n quitWithinMs?: number;\n}\n\n/**\n * Signals during a run. SIGTERM and SIGHUP (a closed terminal, a stopped service) always act like the first Ctrl-C:\n * no new step starts and the run's full cleanup runs. The first Ctrl-C does the same; a second one runs the quick\n * cleanup (delete the agent, restore attachmentDirs) with a short timeout, says what may be left and quits.\n * Returns the remover.\n */\nexport function installSmokeSignals(controller: AbortController, opts: SmokeSignalOptions): () => void {\n let interrupts = 0;\n let quitting = false;\n const stop = (why: string) => {\n if (controller.signal.aborted) return;\n opts.print(`\\n${why}: stopping after the current call, then cleaning up.${why === \"Ctrl-C\" ? \" Press Ctrl-C again to quit sooner (only the agent and attachmentDirs are cleaned up then).\" : \"\"}`);\n controller.abort();\n };\n const onInt = () => {\n interrupts++;\n if (interrupts === 1) return stop(\"Ctrl-C\");\n if (quitting) return;\n quitting = true;\n opts.print(\"\\nQuitting: deleting the temporary agent and restoring attachmentDirs first…\");\n const deadline = new Promise<void>((r) => setTimeout(r, opts.quitWithinMs ?? 8000).unref?.());\n void Promise.race([opts.fastCleanup().catch(() => {}), deadline]).then(() => {\n opts.print(`Quit before the cleanup finished. ${opts.leftovers()}`);\n opts.exit(130);\n });\n };\n const onTerm = () => stop(\"SIGTERM\");\n const onHup = () => stop(\"SIGHUP\");\n process.on(\"SIGINT\", onInt);\n process.on(\"SIGTERM\", onTerm);\n process.on(\"SIGHUP\", onHup);\n return () => {\n process.removeListener(\"SIGINT\", onInt);\n process.removeListener(\"SIGTERM\", onTerm);\n process.removeListener(\"SIGHUP\", onHup);\n };\n}\n\nexport function registerSmokeCommands(program: Command): void {\n const smoke = program\n .command(\"smoke\")\n .description(\"live end-to-end checks against the connected accounts, safe by construction\")\n .summary(\"live end-to-end check of a connection\")\n .helpGroup(GROUP);\n\n smoke\n .command(\"google-workspace\")\n .description(\"check Gmail attachments and the google-workspace extension end to end on the real account: reads anything, writes only into a new scratch folder and ONE draft to itself, cleans up\")\n .option(\"--scratch\", \"required: confirms the run may create its scratch folder, its draft and its temporary agent (all removed again)\")\n .option(\"--account <email>\", \"the Gmail account (default: the only one, or the one the Workspace connection is signed in as)\")\n .option(\"--connection <slug>\", \"the google-workspace connection (default: the only one)\")\n .option(\"--json\", \"print the result table as JSON on stdout (progress goes to stderr)\")\n .option(\"-y, --yes\", \"don't ask before running\")\n .option(\"-d, --data <dir>\", `xaq's data directory (default ~/.xaq, or an existing ~/.${LEGACY_PRODUCT}; env XAQ_DATA)`)\n .addHelpText(\n \"after\",\n `\nPrints the plan first and asks (or --yes). Exit code 0 only when every step passes and nothing is left behind.\n\nExample:\n ${NPX} smoke google-workspace --scratch`,\n )\n .action(async (o: SmokeFlags & { data?: string }) => {\n const { openAdminChannel } = await import(\"../connections-cli/admin.ts\");\n const { TerminalPrompter } = await import(\"../connections-cli/prompt.ts\");\n const { connectAgentMcp } = await import(\"./agent.ts\");\n const { SmokeRun } = await import(\"./run.ts\");\n const { renderReport } = await import(\"./report.ts\");\n if (!o.scratch) {\n throw new Error(\n \"smoke google-workspace runs live on the connected Google account: it reads existing files and mail, and writes only into a new scratch folder and ONE draft to the account itself, which it removes again. Pass --scratch to run it.\",\n );\n }\n const out = safeWriter(o.json ? process.stderr : process.stdout);\n const err = o.json ? out : safeWriter(process.stderr);\n const json = o.json ? safeWriter(process.stdout) : null;\n const channel = openAdminChannel({ dataDir: resolveDataDir(o.data, { quiet: true }) });\n const prompter = new TerminalPrompter(!!o.yes, { input: process.stdin, output: o.json ? process.stderr : process.stdout });\n const controller = new AbortController();\n const run = new SmokeRun(o, {\n admin: channel,\n connectMcp: (key) => connectAgentMcp(channel.baseUrl, key),\n print: out.print,\n confirm: (q) => prompter.confirm(q, false),\n signal: controller.signal,\n });\n const remove = installSmokeSignals(controller, {\n print: (l) => err.print(l),\n fastCleanup: () => run.fastCleanup(3000),\n exit: (code) => {\n channel.close();\n process.exit(code);\n },\n leftovers: () => {\n const left = run.pendingLeftovers();\n return left.length ? `These may be left: ${left.join(\"; \")}. The next run removes the agent and the attachmentDirs entry and lists the rest.` : \"Nothing was left.\";\n },\n });\n try {\n const report = await run.run();\n if (json) json.print(JSON.stringify(report, null, 2));\n else for (const l of [\"\", ...renderReport(report)]) out.print(l);\n process.exitCode = report.ok ? 0 : report.interrupted ? 130 : 1;\n } finally {\n remove();\n prompter.close();\n channel.close();\n out.dispose();\n if (err !== out) err.dispose();\n json?.dispose();\n }\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli-C9lES1ug.js","names":[],"sources":["../server/smoke/cli.ts"],"sourcesContent":["// `xaq smoke google-workspace --scratch`: run on xaq's machine, through the daemon's admin API over the local admin\n// channel (server/connections-cli/admin.ts) and /mcp as a temporary agent. See run.ts for what it does.\n\nimport type { Command } from \"commander\";\nimport { LEGACY_PRODUCT } from \"../brand.ts\";\nimport { resolveDataDir } from \"../config.ts\";\nimport { NPX } from \"../listen/version.ts\";\nimport type { SmokeFlags } from \"./run.ts\";\n\nconst GROUP = \"MCP connections (on xaq's machine):\";\n\n/**\n * A line printer that can't kill the run: once the stream fails (EIO or EPIPE from a terminal that went away, e.g.\n * after SIGHUP), later lines are dropped instead of throwing or crashing on an unhandled 'error'.\n */\nexport function safeWriter(stream: NodeJS.WritableStream): { print: (line?: string) => void; dispose: () => void } {\n let dead = false;\n const onError = () => {\n dead = true;\n };\n stream.on(\"error\", onError);\n return {\n print(line = \"\") {\n if (dead) return;\n try {\n stream.write(`${line}\\n`, (err) => {\n if (err) dead = true;\n });\n } catch {\n dead = true;\n }\n },\n dispose: () => stream.removeListener(\"error\", onError),\n };\n}\n\nexport interface SmokeSignalOptions {\n print: (line: string) => void;\n exit: (code: number) => void;\n /** The second Ctrl-C: the quick part of cleanup (agent, attachmentDirs), bounded. */\n fastCleanup: () => Promise<void>;\n /** What may still be there, in a sentence. */\n leftovers: () => string;\n /** Upper bound on the second Ctrl-C's cleanup before quitting anyway (default 8 s). */\n quitWithinMs?: number;\n}\n\n/**\n * Signals during a run. SIGTERM and SIGHUP (a closed terminal, a stopped service) always act like the first Ctrl-C:\n * no new step starts and the run's full cleanup runs. The first Ctrl-C does the same; a second one runs the quick\n * cleanup (delete the agent, restore attachmentDirs) with a short timeout, says what may be left and quits.\n * Returns the remover.\n */\nexport function installSmokeSignals(controller: AbortController, opts: SmokeSignalOptions): () => void {\n let interrupts = 0;\n let quitting = false;\n const stop = (why: string) => {\n if (controller.signal.aborted) return;\n opts.print(`\\n${why}: stopping after the current call, then cleaning up.${why === \"Ctrl-C\" ? \" Press Ctrl-C again to quit sooner (only the agent and attachmentDirs are cleaned up then).\" : \"\"}`);\n controller.abort();\n };\n const onInt = () => {\n interrupts++;\n if (interrupts === 1) return stop(\"Ctrl-C\");\n if (quitting) return;\n quitting = true;\n opts.print(\"\\nQuitting: deleting the temporary agent and restoring attachmentDirs first…\");\n const deadline = new Promise<void>((r) => setTimeout(r, opts.quitWithinMs ?? 8000).unref?.());\n void Promise.race([opts.fastCleanup().catch(() => {}), deadline]).then(() => {\n opts.print(`Quit before the cleanup finished. ${opts.leftovers()}`);\n opts.exit(130);\n });\n };\n const onTerm = () => stop(\"SIGTERM\");\n const onHup = () => stop(\"SIGHUP\");\n process.on(\"SIGINT\", onInt);\n process.on(\"SIGTERM\", onTerm);\n process.on(\"SIGHUP\", onHup);\n return () => {\n process.removeListener(\"SIGINT\", onInt);\n process.removeListener(\"SIGTERM\", onTerm);\n process.removeListener(\"SIGHUP\", onHup);\n };\n}\n\nexport function registerSmokeCommands(program: Command): void {\n const smoke = program\n .command(\"smoke\")\n .description(\"live end-to-end checks against the connected accounts, safe by construction\")\n .summary(\"live end-to-end check of a connection\")\n .helpGroup(GROUP);\n\n smoke\n .command(\"google-workspace\")\n .description(\"check Gmail attachments and the google-workspace extension end to end on the real account: reads anything, writes only into a new scratch folder and ONE draft to itself, cleans up\")\n .option(\"--scratch\", \"required: confirms the run may create its scratch folder, its draft and its temporary agent (all removed again)\")\n .option(\"--account <email>\", \"the Gmail account (default: the only one, or the one the Workspace connection is signed in as)\")\n .option(\"--connection <slug>\", \"the google-workspace connection (default: the only one)\")\n .option(\"--json\", \"print the result table as JSON on stdout (progress goes to stderr)\")\n .option(\"-y, --yes\", \"don't ask before running\")\n .option(\"-d, --data <dir>\", `xaq's data directory (default ~/.xaq, or an existing ~/.${LEGACY_PRODUCT}; env XAQ_DATA)`)\n .addHelpText(\n \"after\",\n `\nPrints the plan first and asks (or --yes). Exit code 0 only when every step passes and nothing is left behind.\n\nExample:\n ${NPX} smoke google-workspace --scratch`,\n )\n .action(async (o: SmokeFlags & { data?: string }) => {\n const { openAdminChannel } = await import(\"../connections-cli/admin.ts\");\n const { TerminalPrompter } = await import(\"../connections-cli/prompt.ts\");\n const { connectAgentMcp } = await import(\"./agent.ts\");\n const { SmokeRun } = await import(\"./run.ts\");\n const { renderReport } = await import(\"./report.ts\");\n if (!o.scratch) {\n throw new Error(\n \"smoke google-workspace runs live on the connected Google account: it reads existing files and mail, and writes only into a new scratch folder and ONE draft to the account itself, which it removes again. Pass --scratch to run it.\",\n );\n }\n const out = safeWriter(o.json ? process.stderr : process.stdout);\n const err = o.json ? out : safeWriter(process.stderr);\n const json = o.json ? safeWriter(process.stdout) : null;\n const channel = openAdminChannel({ dataDir: resolveDataDir(o.data, { quiet: true }) });\n const prompter = new TerminalPrompter(!!o.yes, { input: process.stdin, output: o.json ? process.stderr : process.stdout });\n const controller = new AbortController();\n const run = new SmokeRun(o, {\n admin: channel,\n connectMcp: (key) => connectAgentMcp(channel.baseUrl, key),\n print: out.print,\n confirm: (q) => prompter.confirm(q, false),\n signal: controller.signal,\n });\n const remove = installSmokeSignals(controller, {\n print: (l) => err.print(l),\n fastCleanup: () => run.fastCleanup(3000),\n exit: (code) => {\n channel.close();\n process.exit(code);\n },\n leftovers: () => {\n const left = run.pendingLeftovers();\n return left.length ? `These may be left: ${left.join(\"; \")}. The next run removes the agent and the attachmentDirs entry and lists the rest.` : \"Nothing was left.\";\n },\n });\n try {\n const report = await run.run();\n if (json) json.print(JSON.stringify(report, null, 2));\n else for (const l of [\"\", ...renderReport(report)]) out.print(l);\n process.exitCode = report.ok ? 0 : report.interrupted ? 130 : 1;\n } finally {\n remove();\n prompter.close();\n channel.close();\n out.dispose();\n if (err !== out) err.dispose();\n json?.dispose();\n }\n });\n}\n"],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -59,7 +59,7 @@ const SERVER_GROUP = "Run xaq:";
59
59
  const AGENT_GROUP = "On an agent's machine:";
60
60
  withServerOptions(program.command("start", { isDefault: true }).description("run xaq 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) => {
61
61
  if (cmd.args.length) throw new Error(unknownCommand(cmd.args[0]));
62
- const { runForeground } = await import("./server-PBZlvr8o.js");
62
+ const { runForeground } = await import("./server-DTxOHzZJ.js");
63
63
  await runForeground({
64
64
  ...configInput(o),
65
65
  dev: !!o.dev,
@@ -68,18 +68,18 @@ withServerOptions(program.command("start", { isDefault: true }).description("run
68
68
  });
69
69
  });
70
70
  const service = program.command("service").description("run xaq in the background as a systemd / launchd service, started at boot").summary("run it in the background (systemd / launchd)").helpGroup(SERVER_GROUP);
71
- withServerOptions(service.command("install").description("install and start the service; re-run it to change the port or update (replaces an agentinbox service, keeping its data)")).action(async (o) => {
71
+ withServerOptions(service.command("install").description("install and start the service; re-run it to change the port or update (replaces an agentinbox service, keeping its data)")).option("--node <path>", "the Node.js binary the service runs (default: this one if new enough, else the previous service's, else the newest found)").action(async (o) => {
72
72
  const { loadConfig } = await import("./config-CAqDP8xi.js");
73
- const { installService, serviceInstallInput, systemOps } = await import("./service-CCbVYqVp.js");
74
- await installService(loadConfig(serviceInstallInput(configInput(o), systemOps()), version));
73
+ const { installService, serviceInstallInput, systemOps } = await import("./service-C2nRdQnH.js");
74
+ await installService(loadConfig(serviceInstallInput(configInput(o), systemOps()), version), void 0, { node: o.node });
75
75
  });
76
76
  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 ~/.xaq, or an existing ~/.agentinbox; env XAQ_DATA)").action(async (o) => {
77
- const { uninstallService } = await import("./service-CCbVYqVp.js");
77
+ const { uninstallService } = await import("./service-C2nRdQnH.js");
78
78
  const { resolveDataDir } = await import("./config-CAqDP8xi.js");
79
79
  uninstallService({ dataDir: resolveDataDir(o.data, { quiet: true }) });
80
80
  });
81
- service.command("status").description("show service status").action(async () => {
82
- const { serviceStatus } = await import("./service-CCbVYqVp.js");
81
+ service.command("status").description("show service status, and check the Node.js it runs (code extensions need a recent one)").action(async () => {
82
+ const { serviceStatus } = await import("./service-C2nRdQnH.js");
83
83
  serviceStatus();
84
84
  });
85
85
  const skill = program.command("skill").description("the xaq agent skill (SKILL.md): teaches an agent how to use xaq's tools").summary("install the agent skill (SKILL.md)").helpGroup(AGENT_GROUP);
@@ -106,7 +106,7 @@ program.command("reset-password").description("forgot the console password? Remo
106
106
  const { loadConfig } = await import("./config-CAqDP8xi.js");
107
107
  const { Db } = await import("./db-Br2FHvQ-.js");
108
108
  const { createBus } = await import("./bus-OKIGut72.js");
109
- const { SettingsStore } = await import("./settings-Dlhgb3bB.js");
109
+ const { SettingsStore } = await import("./settings-DlwSOO5Y.js");
110
110
  const { AuditLog } = await import("./audit-hQnqfGxA.js");
111
111
  const { currentSetupToken, isClaimed, resetAdminPassword } = await import("./auth-CcvstbI5.js");
112
112
  const { runningInstance } = await import("./instance-BsILpEQ7.js");
@@ -138,13 +138,13 @@ program.command("reset-password").description("forgot the console password? Remo
138
138
  db.close();
139
139
  }
140
140
  });
141
- const { registerListenCommands } = await import("./commands-vEfok6bQ.js");
141
+ const { registerListenCommands } = await import("./commands-Bo6-7SBs.js");
142
142
  registerListenCommands(program);
143
- const { registerConnectionsCommands } = await import("./commands-Bb3Jp0f_.js");
143
+ const { registerConnectionsCommands } = await import("./commands-BKr8Ejx0.js");
144
144
  registerConnectionsCommands(program);
145
145
  const { registerExtensionCommands } = await import("./cli-B8cuKWiS.js");
146
146
  registerExtensionCommands(program);
147
- const { registerSmokeCommands } = await import("./cli-DozpH5Tw.js");
147
+ const { registerSmokeCommands } = await import("./cli-C9lES1ug.js");
148
148
  registerSmokeCommands(program);
149
149
  const { registerSettingsCommands } = await import("./settings-cli-DfWc-yWJ.js");
150
150
  registerSettingsCommands(program);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
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 { basename, join, sep } from \"node:path\";\nimport type { Command as CommandType } from \"commander\";\nimport { envVar, underService } from \"./brand.ts\";\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 = \"xaq\";\n\n// The `agentinbox` command now comes from the agentinbox-cli shim, which says this itself and sets the\n// flag before running us; the check stays for anything else that starts us under that name.\nif (basename(process.argv[1] ?? \"\") === \"agentinbox\" && !(globalThis as { __xaqShimNotice?: boolean }).__xaqShimNotice && !underService()) {\n process.stderr.write(\"agentinbox is now xaq: use `npx xaq-cli …` (or `xaq …` once installed with npm i -g xaq-cli).\\n\");\n}\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 ~/.xaq, or an existing ~/.agentinbox; env XAQ_DATA)\");\n\nconst configInput = (o: ServerFlags) => ({ port: portOption(o.port), host: o.host, dataDir: o.data });\n\nconst program = new Command(\"xaq\")\n .description(\n \"Self-hosted MCP broker for AI agents (Notion, WHOOP, any MCP server, Gmail and Calendar). Start it, open the \" +\n \"link it prints, and the web console walks you through the rest (what to connect, 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 xaq-cli start the server and print the setup link\n npx xaq-cli service install keep it running in the background, also after a reboot\n npx xaq-cli reset-password print a new setup link (forgot the console password)\n npx xaq-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 xaq-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 xaq-cli to type xaq instead.\nComing from agentinbox? Your data, keys and services carry over: see \"Upgrading from agentinbox\" in the README.\nDocs: https://github.com/wynn-dev/xaq/blob/main/docs/reference.md`,\n )\n .showSuggestionAfterError();\n\nconst SERVER_GROUP = \"Run xaq:\";\nconst AGENT_GROUP = \"On an agent's machine:\";\n\nwithServerOptions(\n program\n .command(\"start\", { isDefault: true })\n .description(\"run xaq 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 // `xaq 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 xaq 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(\n service.command(\"install\").description(\"install and start the service; re-run it to change the port or update (replaces an agentinbox service, keeping its data)\"),\n).action(async (o: ServerFlags) => {\n const { loadConfig } = await import(\"./config.ts\");\n const { installService, serviceInstallInput, systemOps } = await import(\"./service.ts\");\n // Replacing a service from before the rename keeps its data directory, port and host unless told otherwise.\n await installService(loadConfig(serviceInstallInput(configInput(o), systemOps()), 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 ~/.xaq, or an existing ~/.agentinbox; env XAQ_DATA)\")\n .action(async (o: ServerFlags) => {\n const { uninstallService } = await import(\"./service.ts\");\n const { resolveDataDir } = await import(\"./config.ts\");\n // No loadConfig: uninstalling must not create a data directory.\n uninstallService({ dataDir: resolveDataDir(o.data, { quiet: true }) });\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 xaq agent skill (SKILL.md): teaches an agent how to use xaq'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>\", \"xaq server URL to fill in (env XAQ_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>\", \"xaq server URL agents connect to (env XAQ_URL)\")\n .action(async (o: { target: string; url?: string }) => {\n const { removeLegacySkill, 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 xaq skill to ${pc.cyan(path)} (server ${url}).`);\n const replaced = removeLegacySkill(o.target);\n if (replaced) console.log(`Removed the agentinbox skill it replaces (${replaced}).`);\n if (!o.url && !envVar(\"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 ~/.xaq, or an existing ~/.agentinbox; env XAQ_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 { dataFiles, resolveDataDir } = await import(\"./config.ts\");\n const dataDir = resolveDataDir(o.data);\n const dbPath = dataFiles(dataDir).db;\n if (!existsSync(dbPath)) {\n throw new Error(\n `No xaq data in ${dataDir}. If xaq 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 xaq picks this up immediately; no restart needed.\" : \"Start xaq 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// Daemon side, behind the brokerUpstreams setting: `connections …` and `import --from …` (server/connections-cli).\nconst { registerConnectionsCommands } = await import(\"./connections-cli/commands.ts\");\nregisterConnectionsCommands(program);\n// `ext add | list | update | remove` (docs/EXTENSIONS.md), through the daemon's /api/extensions.\nconst { registerExtensionCommands } = await import(\"./extensions/cli.ts\");\nregisterExtensionCommands(program);\n// `smoke google-workspace --scratch`: the live end-to-end check (server/smoke), through the daemon's admin API and /mcp.\nconst { registerSmokeCommands } = await import(\"./smoke/cli.ts\");\nregisterSmokeCommands(program);\n// `settings attachment-dirs list | add | remove`, through the daemon's /api/settings.\nconst { registerSettingsCommands } = await import(\"./settings-cli.ts\");\nregisterSettingsCommands(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 xaq 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, XAQ_URL (AGENTINBOX_URL), else the xaq 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 ?? envVar(\"URL\");\n if (!raw) {\n const { runningInstance } = await import(\"./instance.ts\");\n const { resolveDataDir } = await import(\"./config.ts\");\n const running = runningInstance(resolveDataDir(undefined, { quiet: true }));\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 xaq --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 (envVar(\"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 { basename, join, sep } from \"node:path\";\nimport type { Command as CommandType } from \"commander\";\nimport { envVar, underService } from \"./brand.ts\";\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 = \"xaq\";\n\n// The `agentinbox` command now comes from the agentinbox-cli shim, which says this itself and sets the\n// flag before running us; the check stays for anything else that starts us under that name.\nif (basename(process.argv[1] ?? \"\") === \"agentinbox\" && !(globalThis as { __xaqShimNotice?: boolean }).__xaqShimNotice && !underService()) {\n process.stderr.write(\"agentinbox is now xaq: use `npx xaq-cli …` (or `xaq …` once installed with npm i -g xaq-cli).\\n\");\n}\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 ~/.xaq, or an existing ~/.agentinbox; env XAQ_DATA)\");\n\nconst configInput = (o: ServerFlags) => ({ port: portOption(o.port), host: o.host, dataDir: o.data });\n\nconst program = new Command(\"xaq\")\n .description(\n \"Self-hosted MCP broker for AI agents (Notion, WHOOP, any MCP server, Gmail and Calendar). Start it, open the \" +\n \"link it prints, and the web console walks you through the rest (what to connect, 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 xaq-cli start the server and print the setup link\n npx xaq-cli service install keep it running in the background, also after a reboot\n npx xaq-cli reset-password print a new setup link (forgot the console password)\n npx xaq-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 xaq-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 xaq-cli to type xaq instead.\nComing from agentinbox? Your data, keys and services carry over: see \"Upgrading from agentinbox\" in the README.\nDocs: https://github.com/wynn-dev/xaq/blob/main/docs/reference.md`,\n )\n .showSuggestionAfterError();\n\nconst SERVER_GROUP = \"Run xaq:\";\nconst AGENT_GROUP = \"On an agent's machine:\";\n\nwithServerOptions(\n program\n .command(\"start\", { isDefault: true })\n .description(\"run xaq 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 // `xaq 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 xaq 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(\n service.command(\"install\").description(\"install and start the service; re-run it to change the port or update (replaces an agentinbox service, keeping its data)\"),\n)\n .option(\"--node <path>\", \"the Node.js binary the service runs (default: this one if new enough, else the previous service's, else the newest found)\")\n .action(async (o: ServerFlags & { node?: string }) => {\n const { loadConfig } = await import(\"./config.ts\");\n const { installService, serviceInstallInput, systemOps } = await import(\"./service.ts\");\n // Replacing a service from before the rename keeps its data directory, port and host unless told otherwise.\n await installService(loadConfig(serviceInstallInput(configInput(o), systemOps()), version), undefined, { node: o.node });\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 ~/.xaq, or an existing ~/.agentinbox; env XAQ_DATA)\")\n .action(async (o: ServerFlags) => {\n const { uninstallService } = await import(\"./service.ts\");\n const { resolveDataDir } = await import(\"./config.ts\");\n // No loadConfig: uninstalling must not create a data directory.\n uninstallService({ dataDir: resolveDataDir(o.data, { quiet: true }) });\n });\n\nservice\n .command(\"status\")\n .description(\"show service status, and check the Node.js it runs (code extensions need a recent one)\")\n .action(async () => {\n const { serviceStatus } = await import(\"./service.ts\");\n serviceStatus();\n });\n\nconst skill = program\n .command(\"skill\")\n .description(\"the xaq agent skill (SKILL.md): teaches an agent how to use xaq'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>\", \"xaq server URL to fill in (env XAQ_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>\", \"xaq server URL agents connect to (env XAQ_URL)\")\n .action(async (o: { target: string; url?: string }) => {\n const { removeLegacySkill, 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 xaq skill to ${pc.cyan(path)} (server ${url}).`);\n const replaced = removeLegacySkill(o.target);\n if (replaced) console.log(`Removed the agentinbox skill it replaces (${replaced}).`);\n if (!o.url && !envVar(\"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 ~/.xaq, or an existing ~/.agentinbox; env XAQ_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 { dataFiles, resolveDataDir } = await import(\"./config.ts\");\n const dataDir = resolveDataDir(o.data);\n const dbPath = dataFiles(dataDir).db;\n if (!existsSync(dbPath)) {\n throw new Error(\n `No xaq data in ${dataDir}. If xaq 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 xaq picks this up immediately; no restart needed.\" : \"Start xaq 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// Daemon side, behind the brokerUpstreams setting: `connections …` and `import --from …` (server/connections-cli).\nconst { registerConnectionsCommands } = await import(\"./connections-cli/commands.ts\");\nregisterConnectionsCommands(program);\n// `ext add | list | update | remove` (docs/EXTENSIONS.md), through the daemon's /api/extensions.\nconst { registerExtensionCommands } = await import(\"./extensions/cli.ts\");\nregisterExtensionCommands(program);\n// `smoke google-workspace --scratch`: the live end-to-end check (server/smoke), through the daemon's admin API and /mcp.\nconst { registerSmokeCommands } = await import(\"./smoke/cli.ts\");\nregisterSmokeCommands(program);\n// `settings attachment-dirs list | add | remove`, through the daemon's /api/settings.\nconst { registerSettingsCommands } = await import(\"./settings-cli.ts\");\nregisterSettingsCommands(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 xaq 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, XAQ_URL (AGENTINBOX_URL), else the xaq 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 ?? envVar(\"URL\");\n if (!raw) {\n const { runningInstance } = await import(\"./instance.ts\");\n const { resolveDataDir } = await import(\"./config.ts\");\n const running = runningInstance(resolveDataDir(undefined, { quiet: true }));\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 xaq --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 (envVar(\"DEBUG\") && err instanceof Error) console.error(err.stack);\n process.exit(1);\n}\n"],"mappings":"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"}
@@ -87,7 +87,7 @@ with the single xaq entry, after a timestamped backup. The entry keeps the name
87
87
  Examples:
88
88
  ${NPX} import --from hermes --dry-run
89
89
  ${NPX} import --from hermes`).action(async (o) => {
90
- const { runImport } = await import("./import-B-xgD799.js");
90
+ const { runImport } = await import("./import-cL9vj0jq.js");
91
91
  const self = await selfOrigins(dataDirOf(o));
92
92
  if (o.dryRun) {
93
93
  const { TerminalPrompter } = await import("./prompt-BEH311I7.js");
@@ -115,4 +115,4 @@ Examples:
115
115
  //#endregion
116
116
  export { registerConnectionsCommands };
117
117
 
118
- //# sourceMappingURL=commands-Bb3Jp0f_.js.map
118
+ //# sourceMappingURL=commands-BKr8Ejx0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"commands-Bb3Jp0f_.js","names":[],"sources":["../server/connections-cli/commands.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { NPX } from \"../listen/version.ts\";\nimport { LEGACY_PRODUCT } from \"../brand.ts\";\nimport { resolveDataDir } from \"../config.ts\";\n\n/**\n * `connections …` and `import --from …`: run on the daemon's machine, talking to its admin API through the\n * one-time local admin session (admin.ts). Listed in --help since the console (#65) shipped; while the daemon's\n * `brokerUpstreams` setting is off they say so (CONNECTIONS_VISIBLE).\n */\nexport const CONNECTIONS_VISIBLE = true;\nconst GROUP = \"MCP connections (on xaq's machine):\";\n\nconst collect = (value: string, previous: string[] | undefined) => [...(previous ?? []), value];\n// --data, else XAQ_DATA (AGENTINBOX_DATA), else ~/.xaq or an existing pre-rename ~/.agentinbox (config.ts; rename-xaq: keep).\nconst dataDirOf = (o: { data?: string }) => resolveDataDir(o.data, { quiet: true });\nconst dataOption = (cmd: Command) => cmd.option(\"-d, --data <dir>\", `xaq's data directory (default ~/.xaq, or an existing ~/.${LEGACY_PRODUCT}; env XAQ_DATA)`);\n\nasync function withApi<T>(o: { data?: string; yes?: boolean }, run: (deps: { api: import(\"./api.ts\").ConnectionsApi; prompter: import(\"./prompt.ts\").Prompter }) => Promise<T>): Promise<T> {\n const { CLEANUP_SIGNALS, openAdminChannel } = await import(\"./admin.ts\");\n const { ConnectionsApi } = await import(\"./api.ts\");\n const { TerminalPrompter } = await import(\"./prompt.ts\");\n const channel = openAdminChannel({ dataDir: dataDirOf(o) });\n const handlers = CLEANUP_SIGNALS.map((sig) => {\n const h = () => {\n channel.close();\n process.exit(sig === \"SIGINT\" ? 130 : 128 + (sig === \"SIGTERM\" ? 15 : 1));\n };\n process.once(sig, h);\n return [sig, h] as const;\n });\n try {\n return await run({ api: new ConnectionsApi(channel), prompter: new TerminalPrompter(!!o.yes) });\n } finally {\n for (const [sig, h] of handlers) process.removeListener(sig, h);\n channel.close();\n }\n}\n\n/** This xaq's own MCP origins, so `import` never imports its own entry. */\nasync function selfOrigins(dataDir: string): Promise<string[]> {\n const { runningInstance } = await import(\"../instance.ts\");\n const { daemonOrigin } = await import(\"./admin.ts\");\n const running = runningInstance(dataDir);\n if (!running) return [];\n return [daemonOrigin(running), `http://localhost:${running.port}`, `http://127.0.0.1:${running.port}`, `http://[::1]:${running.port}`];\n}\n\nexport function registerConnectionsCommands(program: Command): void {\n const connections = program\n .command(\"connections\", { hidden: !CONNECTIONS_VISIBLE })\n .description(\"the MCP servers xaq connects agents to (Notion, T3 Code, any MCP URL, installed extensions); run on xaq's machine\")\n .summary(\"add, list, reconnect or remove connected MCP servers\")\n .helpGroup(GROUP);\n\n dataOption(\n connections\n .command(\"add\")\n .description(\"connect an installed extension (install it first: `ext add notion`) or any MCP server URL, interactively\")\n .argument(\"<integration-or-url>\", \"an installed extension (`ext add notion|t3code|whoop|brightspace` first), or an MCP server URL such as https://mcp.example.com/mcp\"),\n )\n .option(\"--url <address>\", \"t3code: your T3 Code server's address, e.g. http://100.101.102.103:3773 (asked when omitted)\")\n .option(\"--slug <name>\", \"its short name: agents see its tools as <name>__<tool>\")\n .option(\"--name <name>\", \"its display name (unique; default: the server's host, or the integration's name)\")\n .option(\"--access <level>\", \"full, ask (ask before risky actions; the default) or read\")\n .option(\"--agent <name>\", 'an agent that gets it (repeatable; default: all agents; \"all\")', collect)\n .option(\"--header <name>\", \"header for a server that wants a static key (default Authorization)\")\n .option(\"--account <email>\", \"a Google extension (google-workspace): the connected Google account it works as (asked when omitted)\")\n .option(\"--paste\", \"paste the address the browser lands on after signing in, instead of waiting for the redirect (automatic over SSH)\")\n .option(\"--allow-private <origin>\", \"allow this exact scheme://host:port on this machine or a private network without asking (--yes never does)\")\n .option(\"-y, --yes\", \"answer yes to confirmations and take the defaults (never to a private-network allow)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n ${NPX} connections add notion\n ${NPX} connections add google-workspace --account you@example.com # turn on its Google APIs, then allow access\n ${NPX} connections add t3code --url http://100.101.102.103:3773 # one per T3 server; have a T3 pairing code ready\n ${NPX} connections add https://mcp.example.com/mcp --access read\n ${NPX} connections add http://127.0.0.1:8787/mcp # asks before allowing a server on this machine`,\n )\n .action(async (target: string, o: import(\"./manage.ts\").AddFlags & { data?: string }) => {\n const { addConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => addConnection(target, o, deps));\n });\n\n dataOption(connections.command(\"list\").description(\"list connections with their status and access\")).action(async (o: { data?: string }) => {\n const { listConnections } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => listConnections(deps));\n });\n\n dataOption(connections.command(\"reconnect\").description(\"sign in again (OAuth) or replace the key (header)\").argument(\"<name>\", \"the connection's name\"))\n .option(\"--paste\", \"paste the address the browser lands on (automatic over SSH)\")\n .option(\"--header <name>\", \"header connections: the header's name (default: asks, Authorization)\")\n .action(async (slug: string, o: { data?: string; paste?: boolean; header?: string }) => {\n const { reconnectConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => reconnectConnection(slug, o, deps));\n });\n\n dataOption(connections.command(\"disable\").description(\"turn a connection off at once (the kill switch); turn it back on in the console\").argument(\"<name>\", \"the connection's name\"))\n .option(\"-y, --yes\", \"don't ask\")\n .action(async (slug: string, o: { data?: string; yes?: boolean }) => {\n const { disableConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => disableConnection(slug, deps));\n });\n\n dataOption(\n connections\n .command(\"rename\")\n .description(\"change a connection's short name (agents see its tools as <name>__<tool>) or its display name\")\n .argument(\"<name>\", \"the connection's current short name (or its id)\"),\n )\n .option(\"--slug <new>\", \"the new short name: 1-24 lowercase letters, digits and dashes (calls by the old tool names stop working)\")\n .option(\"--name <display-name>\", \"a new display name\")\n .option(\"-y, --yes\", \"don't ask\")\n .action(async (target: string, o: { data?: string; yes?: boolean; slug?: string; name?: string }) => {\n const { renameConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => renameConnection(target, o, deps));\n });\n\n dataOption(connections.command(\"remove\").description(\"remove a connection and delete its credentials\").argument(\"<name>\", \"the connection's name\"))\n .option(\"-y, --yes\", \"don't ask\")\n .action(async (slug: string, o: { data?: string; yes?: boolean }) => {\n const { removeConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => removeConnection(slug, deps));\n });\n\n dataOption(\n program\n .command(\"import\", { hidden: !CONNECTIONS_VISIBLE })\n .description(\"move an agent tool's MCP servers into xaq: one connection each, credentials moved into xaq\")\n .summary(\"import MCP servers from Hermes, Claude Code, Cursor or Codex\")\n .helpGroup(GROUP)\n .requiredOption(\"--from <client>\", \"hermes, claude-code, cursor or codex\"),\n )\n .option(\"--dry-run\", \"print exactly what would be created and changed, and change nothing\")\n .option(\"--access <level>\", \"for every imported connection: full, ask (the default) or read\")\n .option(\"--agent <name>\", 'an agent that gets them (repeatable; default: all agents; \"all\")', collect)\n .option(\"--profile <name>\", \"the agent profile setup-mcp uses for the single xaq entry (default \\\"default\\\")\")\n .option(\"--allow-private <origin>\", \"allow this exact scheme://host:port on this machine or a private network without asking (repeatable; --yes never does)\", collect)\n .option(\"-y, --yes\", \"answer yes to the confirmations (scripts); never to a private-network allow or a project's .mcp.json servers\")\n .addHelpText(\n \"after\",\n `\nReads: hermes ~/.hermes/config.yaml mcp_servers (+ ~/.hermes/.env) · claude-code ~/.claude.json and ./.mcp.json ·\ncursor ~/.cursor/mcp.json · codex ~/.codex/config.toml. Static headers move into xaq (encrypted); OAuth\nservers are created needing Connect (their tokens stay in the client); local (stdio) servers aren't supported yet\nand stay where they are. Servers on this machine or a private network are created only after you confirm the exact\nhost:port. Then it offers setup-mcp --tool <client>, which replaces the entries that now work through xaq\nwith the single xaq entry, after a timestamped backup. The entry keeps the name the profile already uses (\"xaq\", or\n\"${LEGACY_PRODUCT}\" for a profile set up before the rename), so Hermes routes and cron jobs confined to it keep working.\n\nExamples:\n ${NPX} import --from hermes --dry-run\n ${NPX} import --from hermes`,\n )\n .action(async (o: import(\"./import.ts\").ImportFlags & { data?: string }) => {\n const { runImport } = await import(\"./import.ts\");\n const self = await selfOrigins(dataDirOf(o));\n if (o.dryRun) {\n // Read-only: the admin channel (when the daemon runs) only lists existing connections.\n const { TerminalPrompter } = await import(\"./prompt.ts\");\n const { openAdminChannel } = await import(\"./admin.ts\");\n const { ConnectionsApi } = await import(\"./api.ts\");\n let channel: import(\"./admin.ts\").AdminChannel | null = null;\n try {\n process.exitCode = await runImport(o, {\n prompter: new TerminalPrompter(!!o.yes),\n openApi: () => new ConnectionsApi((channel = openAdminChannel({ dataDir: dataDirOf(o) }))),\n selfOrigins: self,\n });\n } finally {\n (channel as import(\"./admin.ts\").AdminChannel | null)?.close();\n }\n return;\n }\n process.exitCode = await withApi(o, (deps) => runImport(o, { prompter: deps.prompter, openApi: () => deps.api, selfOrigins: self }));\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"commands-BKr8Ejx0.js","names":[],"sources":["../server/connections-cli/commands.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { NPX } from \"../listen/version.ts\";\nimport { LEGACY_PRODUCT } from \"../brand.ts\";\nimport { resolveDataDir } from \"../config.ts\";\n\n/**\n * `connections …` and `import --from …`: run on the daemon's machine, talking to its admin API through the\n * one-time local admin session (admin.ts). Listed in --help since the console (#65) shipped; while the daemon's\n * `brokerUpstreams` setting is off they say so (CONNECTIONS_VISIBLE).\n */\nexport const CONNECTIONS_VISIBLE = true;\nconst GROUP = \"MCP connections (on xaq's machine):\";\n\nconst collect = (value: string, previous: string[] | undefined) => [...(previous ?? []), value];\n// --data, else XAQ_DATA (AGENTINBOX_DATA), else ~/.xaq or an existing pre-rename ~/.agentinbox (config.ts; rename-xaq: keep).\nconst dataDirOf = (o: { data?: string }) => resolveDataDir(o.data, { quiet: true });\nconst dataOption = (cmd: Command) => cmd.option(\"-d, --data <dir>\", `xaq's data directory (default ~/.xaq, or an existing ~/.${LEGACY_PRODUCT}; env XAQ_DATA)`);\n\nasync function withApi<T>(o: { data?: string; yes?: boolean }, run: (deps: { api: import(\"./api.ts\").ConnectionsApi; prompter: import(\"./prompt.ts\").Prompter }) => Promise<T>): Promise<T> {\n const { CLEANUP_SIGNALS, openAdminChannel } = await import(\"./admin.ts\");\n const { ConnectionsApi } = await import(\"./api.ts\");\n const { TerminalPrompter } = await import(\"./prompt.ts\");\n const channel = openAdminChannel({ dataDir: dataDirOf(o) });\n const handlers = CLEANUP_SIGNALS.map((sig) => {\n const h = () => {\n channel.close();\n process.exit(sig === \"SIGINT\" ? 130 : 128 + (sig === \"SIGTERM\" ? 15 : 1));\n };\n process.once(sig, h);\n return [sig, h] as const;\n });\n try {\n return await run({ api: new ConnectionsApi(channel), prompter: new TerminalPrompter(!!o.yes) });\n } finally {\n for (const [sig, h] of handlers) process.removeListener(sig, h);\n channel.close();\n }\n}\n\n/** This xaq's own MCP origins, so `import` never imports its own entry. */\nasync function selfOrigins(dataDir: string): Promise<string[]> {\n const { runningInstance } = await import(\"../instance.ts\");\n const { daemonOrigin } = await import(\"./admin.ts\");\n const running = runningInstance(dataDir);\n if (!running) return [];\n return [daemonOrigin(running), `http://localhost:${running.port}`, `http://127.0.0.1:${running.port}`, `http://[::1]:${running.port}`];\n}\n\nexport function registerConnectionsCommands(program: Command): void {\n const connections = program\n .command(\"connections\", { hidden: !CONNECTIONS_VISIBLE })\n .description(\"the MCP servers xaq connects agents to (Notion, T3 Code, any MCP URL, installed extensions); run on xaq's machine\")\n .summary(\"add, list, reconnect or remove connected MCP servers\")\n .helpGroup(GROUP);\n\n dataOption(\n connections\n .command(\"add\")\n .description(\"connect an installed extension (install it first: `ext add notion`) or any MCP server URL, interactively\")\n .argument(\"<integration-or-url>\", \"an installed extension (`ext add notion|t3code|whoop|brightspace` first), or an MCP server URL such as https://mcp.example.com/mcp\"),\n )\n .option(\"--url <address>\", \"t3code: your T3 Code server's address, e.g. http://100.101.102.103:3773 (asked when omitted)\")\n .option(\"--slug <name>\", \"its short name: agents see its tools as <name>__<tool>\")\n .option(\"--name <name>\", \"its display name (unique; default: the server's host, or the integration's name)\")\n .option(\"--access <level>\", \"full, ask (ask before risky actions; the default) or read\")\n .option(\"--agent <name>\", 'an agent that gets it (repeatable; default: all agents; \"all\")', collect)\n .option(\"--header <name>\", \"header for a server that wants a static key (default Authorization)\")\n .option(\"--account <email>\", \"a Google extension (google-workspace): the connected Google account it works as (asked when omitted)\")\n .option(\"--paste\", \"paste the address the browser lands on after signing in, instead of waiting for the redirect (automatic over SSH)\")\n .option(\"--allow-private <origin>\", \"allow this exact scheme://host:port on this machine or a private network without asking (--yes never does)\")\n .option(\"-y, --yes\", \"answer yes to confirmations and take the defaults (never to a private-network allow)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n ${NPX} connections add notion\n ${NPX} connections add google-workspace --account you@example.com # turn on its Google APIs, then allow access\n ${NPX} connections add t3code --url http://100.101.102.103:3773 # one per T3 server; have a T3 pairing code ready\n ${NPX} connections add https://mcp.example.com/mcp --access read\n ${NPX} connections add http://127.0.0.1:8787/mcp # asks before allowing a server on this machine`,\n )\n .action(async (target: string, o: import(\"./manage.ts\").AddFlags & { data?: string }) => {\n const { addConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => addConnection(target, o, deps));\n });\n\n dataOption(connections.command(\"list\").description(\"list connections with their status and access\")).action(async (o: { data?: string }) => {\n const { listConnections } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => listConnections(deps));\n });\n\n dataOption(connections.command(\"reconnect\").description(\"sign in again (OAuth) or replace the key (header)\").argument(\"<name>\", \"the connection's name\"))\n .option(\"--paste\", \"paste the address the browser lands on (automatic over SSH)\")\n .option(\"--header <name>\", \"header connections: the header's name (default: asks, Authorization)\")\n .action(async (slug: string, o: { data?: string; paste?: boolean; header?: string }) => {\n const { reconnectConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => reconnectConnection(slug, o, deps));\n });\n\n dataOption(connections.command(\"disable\").description(\"turn a connection off at once (the kill switch); turn it back on in the console\").argument(\"<name>\", \"the connection's name\"))\n .option(\"-y, --yes\", \"don't ask\")\n .action(async (slug: string, o: { data?: string; yes?: boolean }) => {\n const { disableConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => disableConnection(slug, deps));\n });\n\n dataOption(\n connections\n .command(\"rename\")\n .description(\"change a connection's short name (agents see its tools as <name>__<tool>) or its display name\")\n .argument(\"<name>\", \"the connection's current short name (or its id)\"),\n )\n .option(\"--slug <new>\", \"the new short name: 1-24 lowercase letters, digits and dashes (calls by the old tool names stop working)\")\n .option(\"--name <display-name>\", \"a new display name\")\n .option(\"-y, --yes\", \"don't ask\")\n .action(async (target: string, o: { data?: string; yes?: boolean; slug?: string; name?: string }) => {\n const { renameConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => renameConnection(target, o, deps));\n });\n\n dataOption(connections.command(\"remove\").description(\"remove a connection and delete its credentials\").argument(\"<name>\", \"the connection's name\"))\n .option(\"-y, --yes\", \"don't ask\")\n .action(async (slug: string, o: { data?: string; yes?: boolean }) => {\n const { removeConnection } = await import(\"./manage.ts\");\n process.exitCode = await withApi(o, (deps) => removeConnection(slug, deps));\n });\n\n dataOption(\n program\n .command(\"import\", { hidden: !CONNECTIONS_VISIBLE })\n .description(\"move an agent tool's MCP servers into xaq: one connection each, credentials moved into xaq\")\n .summary(\"import MCP servers from Hermes, Claude Code, Cursor or Codex\")\n .helpGroup(GROUP)\n .requiredOption(\"--from <client>\", \"hermes, claude-code, cursor or codex\"),\n )\n .option(\"--dry-run\", \"print exactly what would be created and changed, and change nothing\")\n .option(\"--access <level>\", \"for every imported connection: full, ask (the default) or read\")\n .option(\"--agent <name>\", 'an agent that gets them (repeatable; default: all agents; \"all\")', collect)\n .option(\"--profile <name>\", \"the agent profile setup-mcp uses for the single xaq entry (default \\\"default\\\")\")\n .option(\"--allow-private <origin>\", \"allow this exact scheme://host:port on this machine or a private network without asking (repeatable; --yes never does)\", collect)\n .option(\"-y, --yes\", \"answer yes to the confirmations (scripts); never to a private-network allow or a project's .mcp.json servers\")\n .addHelpText(\n \"after\",\n `\nReads: hermes ~/.hermes/config.yaml mcp_servers (+ ~/.hermes/.env) · claude-code ~/.claude.json and ./.mcp.json ·\ncursor ~/.cursor/mcp.json · codex ~/.codex/config.toml. Static headers move into xaq (encrypted); OAuth\nservers are created needing Connect (their tokens stay in the client); local (stdio) servers aren't supported yet\nand stay where they are. Servers on this machine or a private network are created only after you confirm the exact\nhost:port. Then it offers setup-mcp --tool <client>, which replaces the entries that now work through xaq\nwith the single xaq entry, after a timestamped backup. The entry keeps the name the profile already uses (\"xaq\", or\n\"${LEGACY_PRODUCT}\" for a profile set up before the rename), so Hermes routes and cron jobs confined to it keep working.\n\nExamples:\n ${NPX} import --from hermes --dry-run\n ${NPX} import --from hermes`,\n )\n .action(async (o: import(\"./import.ts\").ImportFlags & { data?: string }) => {\n const { runImport } = await import(\"./import.ts\");\n const self = await selfOrigins(dataDirOf(o));\n if (o.dryRun) {\n // Read-only: the admin channel (when the daemon runs) only lists existing connections.\n const { TerminalPrompter } = await import(\"./prompt.ts\");\n const { openAdminChannel } = await import(\"./admin.ts\");\n const { ConnectionsApi } = await import(\"./api.ts\");\n let channel: import(\"./admin.ts\").AdminChannel | null = null;\n try {\n process.exitCode = await runImport(o, {\n prompter: new TerminalPrompter(!!o.yes),\n openApi: () => new ConnectionsApi((channel = openAdminChannel({ dataDir: dataDirOf(o) }))),\n selfOrigins: self,\n });\n } finally {\n (channel as import(\"./admin.ts\").AdminChannel | null)?.close();\n }\n return;\n }\n process.exitCode = await withApi(o, (deps) => runImport(o, { prompter: deps.prompter, openApi: () => deps.api, selfOrigins: self }));\n });\n}\n"],"mappings":"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"}