xaq-cli 0.1.0-nightly.80 → 0.1.0-nightly.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/dist/{cli-Bfiv6zge.js → cli-CWUY8Vua.js} +2 -2
- package/dist/{cli-Bfiv6zge.js.map → cli-CWUY8Vua.js.map} +1 -1
- package/dist/cli.js +4 -4
- package/dist/{commands-CqNK71Z1.js → commands-CIiohOpI.js} +3 -3
- package/dist/{commands-CqNK71Z1.js.map → commands-CIiohOpI.js.map} +1 -1
- package/dist/{commands-tVCaKX2m.js → commands-CU46puIx.js} +10 -10
- package/dist/commands-CU46puIx.js.map +1 -0
- package/dist/{connect-Bc-_XGu6.js → connect-DH58vE7-.js} +2 -2
- package/dist/{connect-Bc-_XGu6.js.map → connect-DH58vE7-.js.map} +1 -1
- package/dist/{import-BpXEZv-g.js → import-spafY6Qe.js} +2 -2
- package/dist/{import-BpXEZv-g.js.map → import-spafY6Qe.js.map} +1 -1
- package/dist/{manage-B0GMd74N.js → manage-DGvJajD1.js} +1 -1
- package/dist/{manage-ZWS4TtDB.js → manage-z7PyU7z-.js} +15 -4
- package/dist/manage-z7PyU7z-.js.map +1 -0
- package/dist/registry-D_br7nQw.js +144 -0
- package/dist/registry-D_br7nQw.js.map +1 -0
- package/dist/{server-C8SwDPDp.js → server-DvFqIeG0.js} +10951 -10429
- package/dist/server-DvFqIeG0.js.map +1 -0
- package/dist/{sources-DO6MmQHi.js → sources-BUYFggE7.js} +3 -140
- package/dist/sources-BUYFggE7.js.map +1 -0
- package/dist/user-server-huynScXf.js.map +1 -1
- package/dist/web/assets/_agentId-Cclm55rp.js +1 -0
- package/dist/web/assets/{_app-_X4pIA9e.js → _app-C8v_gOs8.js} +1 -1
- package/dist/web/assets/{_app-BTcv7j6b.js → _app-C9LLrkjn.js} +2 -2
- package/dist/web/assets/{_connectionId-zMUYMV2-.js → _connectionId-BXi1tTsR.js} +1 -1
- package/dist/web/assets/{_webhookId-BzZqtVDC.js → _webhookId-D3gJSy5z.js} +1 -1
- package/dist/web/assets/{account-status-BLKaQQ2q.js → account-status-CVkC77cb.js} +1 -1
- package/dist/web/assets/{accounts-B2_8bFfM.js → accounts-5GVANQyp.js} +1 -1
- package/dist/web/assets/{accounts-list-B5p_Twni.js → accounts-list-YkG5aDdn.js} +1 -1
- package/dist/web/assets/add-connection-DcRUKdZQ.js +1 -0
- package/dist/web/assets/{agent-create-form-FxADP7ru.js → agent-create-form-C7zOmWen.js} +1 -1
- package/dist/web/assets/{agents-B2q_Aqxa.js → agents-CfN0SyLm.js} +1 -1
- package/dist/web/assets/{approvals-BnYPYunq.js → approvals-CWDr1Fwb.js} +1 -1
- package/dist/web/assets/{approve._id-CV2d_77B.js → approve._id-C5LFUNCd.js} +1 -1
- package/dist/web/assets/{attention-Dgl57eLP.js → attention-DfFZhrVh.js} +1 -1
- package/dist/web/assets/{audit-CztVJuz2.js → audit-BhhL-83a.js} +1 -1
- package/dist/web/assets/{audit-bits-Bnl59N8_.js → audit-bits-CFFHbqtb.js} +1 -1
- package/dist/web/assets/{calendar-notice-3ccrTjvg.js → calendar-notice-rqJncWTP.js} +1 -1
- package/dist/web/assets/{calendar-setup-b8L3oH02.js → calendar-setup-CLjwnoSP.js} +1 -1
- package/dist/web/assets/{chips-input-DGr5xdms.js → chips-input-B3DL5x5i.js} +1 -1
- package/dist/web/assets/{choice-cards-Bxbo73Th.js → choice-cards-BMRYLjtc.js} +1 -1
- package/dist/web/assets/{command-C9--j5qk.js → command-BH3-PHv4.js} +1 -1
- package/dist/web/assets/{common-DIYGNz_F.js → common-FcgAjAhR.js} +1 -1
- package/dist/web/assets/{connect-agent-guide-mjIv-bxM.js → connect-agent-guide-NZqPL6I7.js} +1 -1
- package/dist/web/assets/{connect-host-D4RyfiWZ.js → connect-host-BovYZJQH.js} +1 -1
- package/dist/web/assets/{connection-row-C9btdnxA.js → connection-row-Btio0SUT.js} +1 -1
- package/dist/web/assets/{connections-CLZHg7Ku.js → connections-C70RUeCt.js} +1 -1
- package/dist/web/assets/{data-table-CXk1mAQJ.js → data-table-Bs05imQG.js} +1 -1
- package/dist/web/assets/{events-DYKK455p.js → events-Ca2tTzYA.js} +1 -1
- package/dist/web/assets/extension-logic-DmMadhaV.js +1 -0
- package/dist/web/assets/extensions-BvApDq2l.js +1 -0
- package/dist/web/assets/get-started-BigQ1bNy.js +2 -0
- package/dist/web/assets/{index-BG2SDaTP.js → index-70mnmdJT.js} +2 -2
- package/dist/web/assets/{label-multi-select-WIvlufaS.js → label-multi-select-C8Q55TdF.js} +1 -1
- package/dist/web/assets/{labels-u5yJA-FE.js → labels-Q24L6gX1.js} +1 -1
- package/dist/web/assets/{last-call-C7aKME0q.js → last-call-KMn3wnR0.js} +1 -1
- package/dist/web/assets/{login-CaxOZUzr.js → login-D0MUFzN7.js} +1 -1
- package/dist/web/assets/{mcp-call-card-BUwytoHc.js → mcp-call-card--wZaM4e-.js} +1 -1
- package/dist/web/assets/{mutations-CMxxk8sI.js → mutations-erUGmbuW.js} +1 -1
- package/dist/web/assets/{pairing-DyNn3-jh.js → pairing-KmMQzX-D.js} +1 -1
- package/dist/web/assets/{public-url-RdgsU78L.js → public-url-Czx21EJK.js} +1 -1
- package/dist/web/assets/{select-Cv5fucW7.js → select-C8fcN_ma.js} +1 -1
- package/dist/web/assets/{settings-C0oQCtgf.js → settings-DIvD7iTK.js} +1 -1
- package/dist/web/assets/{setup-DZS5AilY.js → setup-pPg0nw4H.js} +1 -1
- package/dist/web/assets/{sheet-PewQsdBv.js → sheet-B3X1F8zP.js} +1 -1
- package/dist/web/assets/{step-url-DSs6pSXM.js → step-url-BHaD3t1u.js} +1 -1
- package/dist/web/assets/{test-email-button-7-VR9Xio.js → test-email-button-BoFNdnCC.js} +1 -1
- package/dist/web/assets/{toggle-group-C5V56DZG.js → toggle-group-DyXUsgty.js} +1 -1
- package/dist/web/assets/{use-delivery-speed-C_zTJz0L.js → use-delivery-speed-DDvrorbz.js} +1 -1
- package/dist/web/assets/{webhook-bits-DvEpXGJm.js → webhook-bits-CTVkfles.js} +1 -1
- package/dist/web/assets/{webhook-sheet-BIguf2bW.js → webhook-sheet-1g8F9GOk.js} +1 -1
- package/dist/web/assets/{webhooks-CLF820_e.js → webhooks-FVJobKvC.js} +1 -1
- package/dist/web/assets/{x-DM3jpoy5.js → x-G8iFD-iO.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/dist/commands-tVCaKX2m.js.map +0 -1
- package/dist/manage-ZWS4TtDB.js.map +0 -1
- package/dist/server-C8SwDPDp.js.map +0 -1
- package/dist/sources-DO6MmQHi.js.map +0 -1
- package/dist/web/assets/_agentId-GeoEyMgJ.js +0 -1
- package/dist/web/assets/add-connection-CkZgTiFB.js +0 -1
- package/dist/web/assets/extensions-Di3FeHuQ.js +0 -1
- package/dist/web/assets/get-started-CyJb68Vl.js +0 -2
package/README.md
CHANGED
|
@@ -12,13 +12,15 @@ server, Gmail and Google Calendar) and gives each agent a single MCP endpoint wi
|
|
|
12
12
|
npx xaq-cli
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Open the link it prints and pick what to connect first: Notion,
|
|
16
|
-
|
|
17
|
-
Only Gmail and Calendar need a Google Cloud project; everything else
|
|
18
|
-
first agent. Requires Node.js 22.13 or newer
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
Open the link it prints and pick what to connect first: Notion, another MCP server, or Gmail and Calendar.
|
|
16
|
+
Pre-made connections (Notion, T3 Code, WHOOP, Brightspace) are extensions: the console installs the one you pick
|
|
17
|
+
from the official registry, then connects it. Only Gmail and Calendar need a Google Cloud project; everything else
|
|
18
|
+
is a few clicks. The console then connects your first agent. Requires Node.js 22.13 or newer (code extensions such
|
|
19
|
+
as WHOOP need 22.23.2, 24.18.1 or 26.5.1 or newer on those lines).
|
|
20
|
+
|
|
21
|
+
From the terminal on the same machine: install an extension first, `npx xaq-cli ext add notion` (or `t3code`,
|
|
22
|
+
`whoop`, `brightspace`), then `npx xaq-cli connections add notion` (`t3code --url http://<your T3 server>:3773`, or
|
|
23
|
+
any MCP server URL),
|
|
22
24
|
and `npx xaq-cli import --from hermes` (also `claude-code`, `cursor`, `codex`) to move an agent's existing MCP
|
|
23
25
|
servers behind the broker. Details: [Connections](docs/reference.md#connections-mcp-broker).
|
|
24
26
|
|
|
@@ -4,7 +4,7 @@ import { s as resolveDataDir } from "./config-cEBzNniL.js";
|
|
|
4
4
|
import { t as AdminApiError } from "./admin-vJum87dw.js";
|
|
5
5
|
import { t as NPX } from "./version-BxH7OuWD.js";
|
|
6
6
|
import { i as safeText } from "./ui-B8Sd4Y7Y.js";
|
|
7
|
-
import { o as parseSource } from "./sources-
|
|
7
|
+
import { o as parseSource } from "./sources-BUYFggE7.js";
|
|
8
8
|
import pc from "picocolors";
|
|
9
9
|
//#region server/extensions/cli.ts
|
|
10
10
|
const enc = encodeURIComponent;
|
|
@@ -193,4 +193,4 @@ Examples:
|
|
|
193
193
|
//#endregion
|
|
194
194
|
export { registerExtensionCommands };
|
|
195
195
|
|
|
196
|
-
//# sourceMappingURL=cli-
|
|
196
|
+
//# sourceMappingURL=cli-CWUY8Vua.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-Bfiv6zge.js","names":[],"sources":["../server/extensions/cli.ts"],"sourcesContent":["// `xaq ext add | list | update | remove`: run on xaq's machine, through the daemon's /api/extensions over the local\n// admin channel (server/connections-cli/admin.ts), so the daemon's own checks (and B2's usedBy) apply.\n\nimport type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport type { ExtensionErrorBody, ExtensionResolveResult, ExtensionUpdateResult, ExtensionView } from \"../../shared/extensions.ts\";\nimport { LEGACY_PRODUCT } from \"../brand.ts\";\nimport { resolveDataDir } from \"../config.ts\";\nimport { AdminApiError, type AdminChannel } from \"../connections-cli/admin.ts\";\nimport type { Prompter } from \"../connections-cli/prompt.ts\";\nimport { safeText } from \"../listen/ui.ts\";\nimport { NPX } from \"../listen/version.ts\";\nimport { parseSource } from \"./sources.ts\";\n\nconst enc = encodeURIComponent;\n\n/** The admin extensions API as the CLI uses it. */\nexport class ExtensionsApi {\n constructor(readonly channel: Pick<AdminChannel, \"request\">) {}\n list(): Promise<ExtensionView[]> {\n return this.channel.request(\"GET\", \"/api/extensions\");\n }\n resolve(source: string): Promise<ExtensionResolveResult> {\n return this.channel.request(\"POST\", \"/api/extensions/resolve\", { source });\n }\n install(source: string, confirmThirdParty: boolean, expectIntegrity: string): Promise<ExtensionView> {\n return this.channel.request(\"POST\", \"/api/extensions\", { source, confirmThirdParty, expectIntegrity });\n }\n update(name: string, body: { confirm: boolean; expectIntegrity?: string }): Promise<ExtensionUpdateResult> {\n return this.channel.request(\"POST\", `/api/extensions/${enc(name)}/update`, body);\n }\n remove(name: string, force: boolean): Promise<void> {\n return this.channel.request(\"DELETE\", `/api/extensions/${enc(name)}${force ? \"?force=true\" : \"\"}`);\n }\n}\n\nexport interface ExtDeps {\n api: ExtensionsApi;\n prompter: Prompter;\n /** Where a relative directory is resolved (default: this process's cwd). */\n cwd?: string;\n}\n\nconst shortCommit = (c: string | null) => (c ? c.slice(0, 12) : \"(directory)\");\nconst origin = (e: Pick<ExtensionView, \"official\">) => (e.official ? pc.green(\"official\") : pc.yellow(\"third-party\"));\n\nfunction describe(p: Prompter, e: ExtensionView): void {\n p.print(`${pc.bold(safeText(e.displayName, 60))} ${pc.dim(`(${e.name})`)} ${safeText(e.version, 40)}, kind ${e.kind}, ${origin(e)}`);\n p.print(` source ${safeText(e.source, 200)}`);\n p.print(` commit ${shortCommit(e.commit)}`);\n p.print(` integrity ${e.integrity}`);\n if (e.kind === \"code\") p.print(` network ${e.network.length ? e.network.map((h) => safeText(h, 100)).join(\", \") : \"none declared\"}`);\n}\n\nfunction printWarnings(p: Prompter, warnings: string[]): void {\n if (!warnings.length) return;\n p.print(\"\");\n for (const w of warnings) p.print(pc.yellow(`! ${safeText(w, 600)}`));\n p.print(\"\");\n}\n\n/** An API error body (a 409 that carries usedBy / warnings), or null. */\nconst errorBody = (err: unknown): ExtensionErrorBody | null => (err instanceof AdminApiError ? ((err.body as ExtensionErrorBody | null) ?? null) : null);\n\nexport async function addExtension(input: string, deps: ExtDeps): Promise<number> {\n const { api, prompter: p } = deps;\n // A directory is resolved here, against this terminal's cwd (and ~), not the daemon's: it gets the absolute path.\n const spec = parseSource(input, { cwd: deps.cwd ?? process.cwd() });\n const source = spec.type === \"local\" ? spec.path : input.trim();\n p.print(`Fetching ${pc.cyan(safeText(source, 200))}…`);\n const { candidate, warnings, installed } = await api.resolve(source);\n describe(p, candidate);\n if (installed) {\n if (installed.integrity === candidate.integrity) {\n p.print(`${pc.green(\"✔\")} ${candidate.name} ${installed.version} is already installed.`);\n return 0;\n }\n p.print(pc.yellow(`${candidate.name} is already installed (${installed.version}, ${shortCommit(installed.commit)}). To change it: ${NPX} ext update ${candidate.name}`));\n return 1;\n }\n if (!candidate.official) {\n printWarnings(p, warnings);\n if (!(await p.confirm(`Install the third-party extension ${candidate.name}?`, false))) {\n p.print(\"Nothing was installed.\");\n return 0;\n }\n }\n const ext = await api.install(source, !candidate.official, candidate.integrity);\n p.print(`${pc.green(\"✔\")} Installed ${ext.name} ${ext.version}${ext.commit ? ` (${shortCommit(ext.commit)})` : \"\"}.`);\n return 0;\n}\n\nexport async function listExtensions(deps: ExtDeps): Promise<number> {\n const { api, prompter: p } = deps;\n const all = await api.list();\n if (!all.length) {\n p.print(`No extensions installed. Add one: ${NPX} ext add <name|github-url|git-url|./dir>`);\n return 0;\n }\n const w = Math.max(4, ...all.map((e) => e.name.length));\n const v = Math.max(7, ...all.map((e) => safeText(e.version, 20).length));\n p.print(pc.dim(`${\"NAME\".padEnd(w)} ${\"VERSION\".padEnd(v)} ${\"COMMIT\".padEnd(12)} ${\"ORIGIN\".padEnd(11)} ${\"USED BY\".padEnd(16)} SOURCE`));\n for (const e of all) {\n const used = e.usedBy.length ? safeText(e.usedBy.join(\", \"), 40) : \"-\";\n p.print(\n `${e.name.padEnd(w)} ${safeText(e.version, 20).padEnd(v)} ${shortCommit(e.commit).padEnd(12)} ${(e.official ? \"official\" : \"third-party\").padEnd(11)} ${used.padEnd(16)} ${safeText(e.source, 120)}`,\n );\n }\n return 0;\n}\n\nexport async function updateExtension(name: string, deps: ExtDeps): Promise<number> {\n const { api, prompter: p } = deps;\n p.print(`Checking ${pc.cyan(name)} for an update…`);\n const preview = await api.update(name, { confirm: false });\n if (!preview.update) {\n p.print(`${pc.green(\"✔\")} ${name} is up to date.`);\n return 0;\n }\n const { from, to, warnings } = preview.update;\n const row = (label: string, a: string, b: string) => p.print(` ${label.padEnd(10)} ${a} → ${a === b ? pc.dim(b) : pc.bold(b)}`);\n p.print(`Update ${pc.bold(name)}:`);\n row(\"version\", safeText(from.version, 40), safeText(to.version, 40));\n row(\"commit\", shortCommit(from.commit), shortCommit(to.commit));\n row(\"integrity\", from.integrity, to.integrity);\n if (from.kind !== to.kind) row(\"kind\", from.kind, to.kind);\n const hosts = (e: ExtensionView) => (e.network.length ? e.network.map((h) => safeText(h, 100)).join(\", \") : \"none\");\n if (to.kind === \"code\" && hosts(from) !== hosts(to)) row(\"network\", hosts(from), hosts(to));\n printWarnings(p, warnings);\n if (from.usedBy.length) p.print(pc.dim(`Used by ${from.usedBy.join(\", \")}: they switch to the new version.`));\n if (!(await p.confirm(`Install ${name} ${safeText(to.version, 40)}?`, false))) {\n p.print(\"Nothing was changed.\");\n return 0;\n }\n const done = await api.update(name, { confirm: true, expectIntegrity: to.integrity });\n if (!done.update) {\n p.print(`${pc.green(\"✔\")} ${name} is up to date.`);\n return 0;\n }\n p.print(`${pc.green(\"✔\")} Updated ${name} to ${safeText(done.update.to.version, 40)}${done.update.to.commit ? ` (${shortCommit(done.update.to.commit)})` : \"\"}.`);\n return 0;\n}\n\nexport async function removeExtension(name: string, flags: { force?: boolean }, deps: ExtDeps): Promise<number> {\n const { api, prompter: p } = deps;\n const ext = (await api.list()).find((e) => e.name === name);\n if (!ext) throw new Error(`${name} isn't installed.`);\n if (ext.usedBy.length && !flags.force) {\n p.print(pc.yellow(`${name} is used by ${ext.usedBy.join(\", \")}.`));\n p.print(`Remove those connections first (${NPX} connections remove <name>), or pass --force, which disables them (their credentials stay until you remove them).`);\n return 1;\n }\n const what = ext.usedBy.length ? ` and disable ${ext.usedBy.join(\", \")}` : \"\";\n if (!(await p.confirm(`Remove the extension ${name}${what}?`, false))) return 0;\n try {\n await api.remove(name, !!flags.force);\n } catch (err) {\n const body = errorBody(err);\n if (body?.error.code === \"in_use\") {\n p.print(pc.yellow(`${name} is used by ${(body.usedBy ?? []).join(\", \")}. Pass --force to disable them and remove it.`));\n return 1;\n }\n throw err;\n }\n p.print(`${pc.green(\"✔\")} Removed ${name}.`);\n return 0;\n}\n\nconst GROUP = \"MCP connections (on xaq's machine):\";\n\nexport function registerExtensionCommands(program: Command): void {\n const dataOption = (cmd: Command) => cmd.option(\"-d, --data <dir>\", `xaq's data directory (default ~/.xaq, or an existing ~/.${LEGACY_PRODUCT}; env XAQ_DATA)`);\n const withApi = async (o: { data?: string; yes?: boolean }, run: (deps: ExtDeps) => Promise<number>) => {\n const { CLEANUP_SIGNALS, openAdminChannel } = await import(\"../connections-cli/admin.ts\");\n const { TerminalPrompter } = await import(\"../connections-cli/prompt.ts\");\n const channel = openAdminChannel({ dataDir: resolveDataDir(o.data, { quiet: true }) });\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 process.exitCode = await run({ api: new ExtensionsApi(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 const ext = program\n .command(\"ext\")\n .description(\"extensions: the integrations xaq can connect to (Notion, WHOOP, T3 Code, …), from the official registry or elsewhere\")\n .summary(\"add, list, update or remove extensions\")\n .helpGroup(GROUP);\n\n dataOption(\n ext\n .command(\"add\")\n .description(\"install an extension: a registry name, a GitHub URL, another git URL (#ref, #ref:path), or a ./directory\")\n .argument(\"<name|url|path>\", \"e.g. notion, https://github.com/you/repo/tree/main/ext, ./my-extension\"),\n )\n .option(\"-y, --yes\", \"install a third-party extension without asking (the warning is still printed)\")\n .addHelpText(\n \"after\",\n `\nAnything that isn't the official registry (wynn-dev/xaq-extensions) is third-party: you see its kind, its declared\nnetwork hosts and its source first, and confirm. A code extension runs on this machine with network access.\n\nExamples:\n ${NPX} ext add notion\n ${NPX} ext add https://github.com/you/xaq-ext/tree/main/extensions/thing\n ${NPX} ext add https://git.example.com/you/ext.git#v1.2.0\n ${NPX} ext add ./my-extension`,\n )\n .action((source: string, o: { data?: string; yes?: boolean }) => withApi(o, (deps) => addExtension(source, deps)));\n\n dataOption(ext.command(\"list\").description(\"list installed extensions: version, commit, official or third-party, and the connections using each\")).action((o: { data?: string }) =>\n withApi(o, (deps) => listExtensions(deps)),\n );\n\n dataOption(ext.command(\"update\").description(\"show what an update changes (version, commit, integrity) and install it on confirmation\").argument(\"<name>\", \"the extension's name\"))\n .option(\"-y, --yes\", \"install the update without asking\")\n .action((name: string, o: { data?: string; yes?: boolean }) => withApi(o, (deps) => updateExtension(name, deps)));\n\n dataOption(ext.command(\"remove\").description(\"remove an extension (refused while connections use it, unless --force)\").argument(\"<name>\", \"the extension's name\"))\n .option(\"--force\", \"also when connections use it: they're disabled (credentials stay until you remove them)\")\n .option(\"-y, --yes\", \"don't ask\")\n .action((name: string, o: { data?: string; yes?: boolean; force?: boolean }) => withApi(o, (deps) => removeExtension(name, o, deps)));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli-CWUY8Vua.js","names":[],"sources":["../server/extensions/cli.ts"],"sourcesContent":["// `xaq ext add | list | update | remove`: run on xaq's machine, through the daemon's /api/extensions over the local\n// admin channel (server/connections-cli/admin.ts), so the daemon's own checks (and B2's usedBy) apply.\n\nimport type { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport type { ExtensionErrorBody, ExtensionResolveResult, ExtensionUpdateResult, ExtensionView } from \"../../shared/extensions.ts\";\nimport { LEGACY_PRODUCT } from \"../brand.ts\";\nimport { resolveDataDir } from \"../config.ts\";\nimport { AdminApiError, type AdminChannel } from \"../connections-cli/admin.ts\";\nimport type { Prompter } from \"../connections-cli/prompt.ts\";\nimport { safeText } from \"../listen/ui.ts\";\nimport { NPX } from \"../listen/version.ts\";\nimport { parseSource } from \"./sources.ts\";\n\nconst enc = encodeURIComponent;\n\n/** The admin extensions API as the CLI uses it. */\nexport class ExtensionsApi {\n constructor(readonly channel: Pick<AdminChannel, \"request\">) {}\n list(): Promise<ExtensionView[]> {\n return this.channel.request(\"GET\", \"/api/extensions\");\n }\n resolve(source: string): Promise<ExtensionResolveResult> {\n return this.channel.request(\"POST\", \"/api/extensions/resolve\", { source });\n }\n install(source: string, confirmThirdParty: boolean, expectIntegrity: string): Promise<ExtensionView> {\n return this.channel.request(\"POST\", \"/api/extensions\", { source, confirmThirdParty, expectIntegrity });\n }\n update(name: string, body: { confirm: boolean; expectIntegrity?: string }): Promise<ExtensionUpdateResult> {\n return this.channel.request(\"POST\", `/api/extensions/${enc(name)}/update`, body);\n }\n remove(name: string, force: boolean): Promise<void> {\n return this.channel.request(\"DELETE\", `/api/extensions/${enc(name)}${force ? \"?force=true\" : \"\"}`);\n }\n}\n\nexport interface ExtDeps {\n api: ExtensionsApi;\n prompter: Prompter;\n /** Where a relative directory is resolved (default: this process's cwd). */\n cwd?: string;\n}\n\nconst shortCommit = (c: string | null) => (c ? c.slice(0, 12) : \"(directory)\");\nconst origin = (e: Pick<ExtensionView, \"official\">) => (e.official ? pc.green(\"official\") : pc.yellow(\"third-party\"));\n\nfunction describe(p: Prompter, e: ExtensionView): void {\n p.print(`${pc.bold(safeText(e.displayName, 60))} ${pc.dim(`(${e.name})`)} ${safeText(e.version, 40)}, kind ${e.kind}, ${origin(e)}`);\n p.print(` source ${safeText(e.source, 200)}`);\n p.print(` commit ${shortCommit(e.commit)}`);\n p.print(` integrity ${e.integrity}`);\n if (e.kind === \"code\") p.print(` network ${e.network.length ? e.network.map((h) => safeText(h, 100)).join(\", \") : \"none declared\"}`);\n}\n\nfunction printWarnings(p: Prompter, warnings: string[]): void {\n if (!warnings.length) return;\n p.print(\"\");\n for (const w of warnings) p.print(pc.yellow(`! ${safeText(w, 600)}`));\n p.print(\"\");\n}\n\n/** An API error body (a 409 that carries usedBy / warnings), or null. */\nconst errorBody = (err: unknown): ExtensionErrorBody | null => (err instanceof AdminApiError ? ((err.body as ExtensionErrorBody | null) ?? null) : null);\n\nexport async function addExtension(input: string, deps: ExtDeps): Promise<number> {\n const { api, prompter: p } = deps;\n // A directory is resolved here, against this terminal's cwd (and ~), not the daemon's: it gets the absolute path.\n const spec = parseSource(input, { cwd: deps.cwd ?? process.cwd() });\n const source = spec.type === \"local\" ? spec.path : input.trim();\n p.print(`Fetching ${pc.cyan(safeText(source, 200))}…`);\n const { candidate, warnings, installed } = await api.resolve(source);\n describe(p, candidate);\n if (installed) {\n if (installed.integrity === candidate.integrity) {\n p.print(`${pc.green(\"✔\")} ${candidate.name} ${installed.version} is already installed.`);\n return 0;\n }\n p.print(pc.yellow(`${candidate.name} is already installed (${installed.version}, ${shortCommit(installed.commit)}). To change it: ${NPX} ext update ${candidate.name}`));\n return 1;\n }\n if (!candidate.official) {\n printWarnings(p, warnings);\n if (!(await p.confirm(`Install the third-party extension ${candidate.name}?`, false))) {\n p.print(\"Nothing was installed.\");\n return 0;\n }\n }\n const ext = await api.install(source, !candidate.official, candidate.integrity);\n p.print(`${pc.green(\"✔\")} Installed ${ext.name} ${ext.version}${ext.commit ? ` (${shortCommit(ext.commit)})` : \"\"}.`);\n return 0;\n}\n\nexport async function listExtensions(deps: ExtDeps): Promise<number> {\n const { api, prompter: p } = deps;\n const all = await api.list();\n if (!all.length) {\n p.print(`No extensions installed. Add one: ${NPX} ext add <name|github-url|git-url|./dir>`);\n return 0;\n }\n const w = Math.max(4, ...all.map((e) => e.name.length));\n const v = Math.max(7, ...all.map((e) => safeText(e.version, 20).length));\n p.print(pc.dim(`${\"NAME\".padEnd(w)} ${\"VERSION\".padEnd(v)} ${\"COMMIT\".padEnd(12)} ${\"ORIGIN\".padEnd(11)} ${\"USED BY\".padEnd(16)} SOURCE`));\n for (const e of all) {\n const used = e.usedBy.length ? safeText(e.usedBy.join(\", \"), 40) : \"-\";\n p.print(\n `${e.name.padEnd(w)} ${safeText(e.version, 20).padEnd(v)} ${shortCommit(e.commit).padEnd(12)} ${(e.official ? \"official\" : \"third-party\").padEnd(11)} ${used.padEnd(16)} ${safeText(e.source, 120)}`,\n );\n }\n return 0;\n}\n\nexport async function updateExtension(name: string, deps: ExtDeps): Promise<number> {\n const { api, prompter: p } = deps;\n p.print(`Checking ${pc.cyan(name)} for an update…`);\n const preview = await api.update(name, { confirm: false });\n if (!preview.update) {\n p.print(`${pc.green(\"✔\")} ${name} is up to date.`);\n return 0;\n }\n const { from, to, warnings } = preview.update;\n const row = (label: string, a: string, b: string) => p.print(` ${label.padEnd(10)} ${a} → ${a === b ? pc.dim(b) : pc.bold(b)}`);\n p.print(`Update ${pc.bold(name)}:`);\n row(\"version\", safeText(from.version, 40), safeText(to.version, 40));\n row(\"commit\", shortCommit(from.commit), shortCommit(to.commit));\n row(\"integrity\", from.integrity, to.integrity);\n if (from.kind !== to.kind) row(\"kind\", from.kind, to.kind);\n const hosts = (e: ExtensionView) => (e.network.length ? e.network.map((h) => safeText(h, 100)).join(\", \") : \"none\");\n if (to.kind === \"code\" && hosts(from) !== hosts(to)) row(\"network\", hosts(from), hosts(to));\n printWarnings(p, warnings);\n if (from.usedBy.length) p.print(pc.dim(`Used by ${from.usedBy.join(\", \")}: they switch to the new version.`));\n if (!(await p.confirm(`Install ${name} ${safeText(to.version, 40)}?`, false))) {\n p.print(\"Nothing was changed.\");\n return 0;\n }\n const done = await api.update(name, { confirm: true, expectIntegrity: to.integrity });\n if (!done.update) {\n p.print(`${pc.green(\"✔\")} ${name} is up to date.`);\n return 0;\n }\n p.print(`${pc.green(\"✔\")} Updated ${name} to ${safeText(done.update.to.version, 40)}${done.update.to.commit ? ` (${shortCommit(done.update.to.commit)})` : \"\"}.`);\n return 0;\n}\n\nexport async function removeExtension(name: string, flags: { force?: boolean }, deps: ExtDeps): Promise<number> {\n const { api, prompter: p } = deps;\n const ext = (await api.list()).find((e) => e.name === name);\n if (!ext) throw new Error(`${name} isn't installed.`);\n if (ext.usedBy.length && !flags.force) {\n p.print(pc.yellow(`${name} is used by ${ext.usedBy.join(\", \")}.`));\n p.print(`Remove those connections first (${NPX} connections remove <name>), or pass --force, which disables them (their credentials stay until you remove them).`);\n return 1;\n }\n const what = ext.usedBy.length ? ` and disable ${ext.usedBy.join(\", \")}` : \"\";\n if (!(await p.confirm(`Remove the extension ${name}${what}?`, false))) return 0;\n try {\n await api.remove(name, !!flags.force);\n } catch (err) {\n const body = errorBody(err);\n if (body?.error.code === \"in_use\") {\n p.print(pc.yellow(`${name} is used by ${(body.usedBy ?? []).join(\", \")}. Pass --force to disable them and remove it.`));\n return 1;\n }\n throw err;\n }\n p.print(`${pc.green(\"✔\")} Removed ${name}.`);\n return 0;\n}\n\nconst GROUP = \"MCP connections (on xaq's machine):\";\n\nexport function registerExtensionCommands(program: Command): void {\n const dataOption = (cmd: Command) => cmd.option(\"-d, --data <dir>\", `xaq's data directory (default ~/.xaq, or an existing ~/.${LEGACY_PRODUCT}; env XAQ_DATA)`);\n const withApi = async (o: { data?: string; yes?: boolean }, run: (deps: ExtDeps) => Promise<number>) => {\n const { CLEANUP_SIGNALS, openAdminChannel } = await import(\"../connections-cli/admin.ts\");\n const { TerminalPrompter } = await import(\"../connections-cli/prompt.ts\");\n const channel = openAdminChannel({ dataDir: resolveDataDir(o.data, { quiet: true }) });\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 process.exitCode = await run({ api: new ExtensionsApi(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 const ext = program\n .command(\"ext\")\n .description(\"extensions: the integrations xaq can connect to (Notion, WHOOP, T3 Code, …), from the official registry or elsewhere\")\n .summary(\"add, list, update or remove extensions\")\n .helpGroup(GROUP);\n\n dataOption(\n ext\n .command(\"add\")\n .description(\"install an extension: a registry name, a GitHub URL, another git URL (#ref, #ref:path), or a ./directory\")\n .argument(\"<name|url|path>\", \"e.g. notion, https://github.com/you/repo/tree/main/ext, ./my-extension\"),\n )\n .option(\"-y, --yes\", \"install a third-party extension without asking (the warning is still printed)\")\n .addHelpText(\n \"after\",\n `\nAnything that isn't the official registry (wynn-dev/xaq-extensions) is third-party: you see its kind, its declared\nnetwork hosts and its source first, and confirm. A code extension runs on this machine with network access.\n\nExamples:\n ${NPX} ext add notion\n ${NPX} ext add https://github.com/you/xaq-ext/tree/main/extensions/thing\n ${NPX} ext add https://git.example.com/you/ext.git#v1.2.0\n ${NPX} ext add ./my-extension`,\n )\n .action((source: string, o: { data?: string; yes?: boolean }) => withApi(o, (deps) => addExtension(source, deps)));\n\n dataOption(ext.command(\"list\").description(\"list installed extensions: version, commit, official or third-party, and the connections using each\")).action((o: { data?: string }) =>\n withApi(o, (deps) => listExtensions(deps)),\n );\n\n dataOption(ext.command(\"update\").description(\"show what an update changes (version, commit, integrity) and install it on confirmation\").argument(\"<name>\", \"the extension's name\"))\n .option(\"-y, --yes\", \"install the update without asking\")\n .action((name: string, o: { data?: string; yes?: boolean }) => withApi(o, (deps) => updateExtension(name, deps)));\n\n dataOption(ext.command(\"remove\").description(\"remove an extension (refused while connections use it, unless --force)\").argument(\"<name>\", \"the extension's name\"))\n .option(\"--force\", \"also when connections use it: they're disabled (credentials stay until you remove them)\")\n .option(\"-y, --yes\", \"don't ask\")\n .action((name: string, o: { data?: string; yes?: boolean; force?: boolean }) => withApi(o, (deps) => removeExtension(name, o, deps)));\n}\n"],"mappings":";;;;;;;;;AAcA,MAAM,MAAM;;AAGZ,IAAa,gBAAb,MAA2B;CACJ;CAArB,YAAY,SAAiD;EAAxC,KAAA,UAAA;CAAyC;CAC9D,OAAiC;EAC/B,OAAO,KAAK,QAAQ,QAAQ,OAAO,iBAAiB;CACtD;CACA,QAAQ,QAAiD;EACvD,OAAO,KAAK,QAAQ,QAAQ,QAAQ,2BAA2B,EAAE,OAAO,CAAC;CAC3E;CACA,QAAQ,QAAgB,mBAA4B,iBAAiD;EACnG,OAAO,KAAK,QAAQ,QAAQ,QAAQ,mBAAmB;GAAE;GAAQ;GAAmB;EAAgB,CAAC;CACvG;CACA,OAAO,MAAc,MAAsF;EACzG,OAAO,KAAK,QAAQ,QAAQ,QAAQ,mBAAmB,IAAI,IAAI,EAAE,UAAU,IAAI;CACjF;CACA,OAAO,MAAc,OAA+B;EAClD,OAAO,KAAK,QAAQ,QAAQ,UAAU,mBAAmB,IAAI,IAAI,IAAI,QAAQ,gBAAgB,IAAI;CACnG;AACF;AASA,MAAM,eAAe,MAAsB,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI;AAChE,MAAM,UAAU,MAAwC,EAAE,WAAW,GAAG,MAAM,UAAU,IAAI,GAAG,OAAO,aAAa;AAEnH,SAAS,SAAS,GAAa,GAAwB;CACrD,EAAE,MAAM,GAAG,GAAG,KAAK,SAAS,EAAE,aAAa,EAAE,CAAC,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE,KAAK,EAAE,EAAE,GAAG,SAAS,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,KAAK,IAAI,OAAO,CAAC,GAAG;CACnI,EAAE,MAAM,gBAAgB,SAAS,EAAE,QAAQ,GAAG,GAAG;CACjD,EAAE,MAAM,gBAAgB,YAAY,EAAE,MAAM,GAAG;CAC/C,EAAE,MAAM,gBAAgB,EAAE,WAAW;CACrC,IAAI,EAAE,SAAS,QAAQ,EAAE,MAAM,gBAAgB,EAAE,QAAQ,SAAS,EAAE,QAAQ,KAAK,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,iBAAiB;AACzI;AAEA,SAAS,cAAc,GAAa,UAA0B;CAC5D,IAAI,CAAC,SAAS,QAAQ;CACtB,EAAE,MAAM,EAAE;CACV,KAAK,MAAM,KAAK,UAAU,EAAE,MAAM,GAAG,OAAO,KAAK,SAAS,GAAG,GAAG,GAAG,CAAC;CACpE,EAAE,MAAM,EAAE;AACZ;;AAGA,MAAM,aAAa,QAA6C,eAAe,gBAAkB,IAAI,QAAsC,OAAQ;AAEnJ,eAAsB,aAAa,OAAe,MAAgC;CAChF,MAAM,EAAE,KAAK,UAAU,MAAM;CAE7B,MAAM,OAAO,YAAY,OAAO,EAAE,KAAK,KAAK,OAAO,QAAQ,IAAI,EAAE,CAAC;CAClE,MAAM,SAAS,KAAK,SAAS,UAAU,KAAK,OAAO,MAAM,KAAK;CAC9D,EAAE,MAAM,YAAY,GAAG,KAAK,SAAS,QAAQ,GAAG,CAAC,EAAE,EAAE;CACrD,MAAM,EAAE,WAAW,UAAU,cAAc,MAAM,IAAI,QAAQ,MAAM;CACnE,SAAS,GAAG,SAAS;CACrB,IAAI,WAAW;EACb,IAAI,UAAU,cAAc,UAAU,WAAW;GAC/C,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,EAAE,GAAG,UAAU,KAAK,GAAG,UAAU,QAAQ,uBAAuB;GACvF,OAAO;EACT;EACA,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,KAAK,yBAAyB,UAAU,QAAQ,IAAI,YAAY,UAAU,MAAM,EAAE,mBAAmB,IAAI,cAAc,UAAU,MAAM,CAAC;EACvK,OAAO;CACT;CACA,IAAI,CAAC,UAAU,UAAU;EACvB,cAAc,GAAG,QAAQ;EACzB,IAAI,CAAE,MAAM,EAAE,QAAQ,qCAAqC,UAAU,KAAK,IAAI,KAAK,GAAI;GACrF,EAAE,MAAM,wBAAwB;GAChC,OAAO;EACT;CACF;CACA,MAAM,MAAM,MAAM,IAAI,QAAQ,QAAQ,CAAC,UAAU,UAAU,UAAU,SAAS;CAC9E,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,EAAE,aAAa,IAAI,KAAK,GAAG,IAAI,UAAU,IAAI,SAAS,KAAK,YAAY,IAAI,MAAM,EAAE,KAAK,GAAG,EAAE;CACpH,OAAO;AACT;AAEA,eAAsB,eAAe,MAAgC;CACnE,MAAM,EAAE,KAAK,UAAU,MAAM;CAC7B,MAAM,MAAM,MAAM,IAAI,KAAK;CAC3B,IAAI,CAAC,IAAI,QAAQ;EACf,EAAE,MAAM,qCAAqC,IAAI,yCAAyC;EAC1F,OAAO;CACT;CACA,MAAM,IAAI,KAAK,IAAI,GAAG,GAAG,IAAI,KAAK,MAAM,EAAE,KAAK,MAAM,CAAC;CACtD,MAAM,IAAI,KAAK,IAAI,GAAG,GAAG,IAAI,KAAK,MAAM,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;CACvE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,OAAO,CAAC,EAAE,IAAI,UAAU,OAAO,CAAC,EAAE,IAAI,SAAS,OAAO,EAAE,EAAE,IAAI,SAAS,OAAO,EAAE,EAAE,IAAI,UAAU,OAAO,EAAE,EAAE,SAAS,CAAC;CAC9I,KAAK,MAAM,KAAK,KAAK;EACnB,MAAM,OAAO,EAAE,OAAO,SAAS,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,EAAE,IAAI;EACnE,EAAE,MACA,GAAG,EAAE,KAAK,OAAO,CAAC,EAAE,IAAI,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,YAAY,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,aAAa,cAAA,CAAe,OAAO,EAAE,EAAE,IAAI,KAAK,OAAO,EAAE,EAAE,IAAI,SAAS,EAAE,QAAQ,GAAG,GACxM;CACF;CACA,OAAO;AACT;AAEA,eAAsB,gBAAgB,MAAc,MAAgC;CAClF,MAAM,EAAE,KAAK,UAAU,MAAM;CAC7B,EAAE,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE,gBAAgB;CAClD,MAAM,UAAU,MAAM,IAAI,OAAO,MAAM,EAAE,SAAS,MAAM,CAAC;CACzD,IAAI,CAAC,QAAQ,QAAQ;EACnB,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,EAAE,GAAG,KAAK,gBAAgB;EACjD,OAAO;CACT;CACA,MAAM,EAAE,MAAM,IAAI,aAAa,QAAQ;CACvC,MAAM,OAAO,OAAe,GAAW,MAAc,EAAE,MAAM,KAAK,MAAM,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG;CACjI,EAAE,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE,EAAE;CAClC,IAAI,WAAW,SAAS,KAAK,SAAS,EAAE,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;CACnE,IAAI,UAAU,YAAY,KAAK,MAAM,GAAG,YAAY,GAAG,MAAM,CAAC;CAC9D,IAAI,aAAa,KAAK,WAAW,GAAG,SAAS;CAC7C,IAAI,KAAK,SAAS,GAAG,MAAM,IAAI,QAAQ,KAAK,MAAM,GAAG,IAAI;CACzD,MAAM,SAAS,MAAsB,EAAE,QAAQ,SAAS,EAAE,QAAQ,KAAK,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI;CAC5G,IAAI,GAAG,SAAS,UAAU,MAAM,IAAI,MAAM,MAAM,EAAE,GAAG,IAAI,WAAW,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;CAC1F,cAAc,GAAG,QAAQ;CACzB,IAAI,KAAK,OAAO,QAAQ,EAAE,MAAM,GAAG,IAAI,WAAW,KAAK,OAAO,KAAK,IAAI,EAAE,kCAAkC,CAAC;CAC5G,IAAI,CAAE,MAAM,EAAE,QAAQ,WAAW,KAAK,GAAG,SAAS,GAAG,SAAS,EAAE,EAAE,IAAI,KAAK,GAAI;EAC7E,EAAE,MAAM,sBAAsB;EAC9B,OAAO;CACT;CACA,MAAM,OAAO,MAAM,IAAI,OAAO,MAAM;EAAE,SAAS;EAAM,iBAAiB,GAAG;CAAU,CAAC;CACpF,IAAI,CAAC,KAAK,QAAQ;EAChB,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,EAAE,GAAG,KAAK,gBAAgB;EACjD,OAAO;CACT;CACA,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,EAAE,WAAW,KAAK,MAAM,SAAS,KAAK,OAAO,GAAG,SAAS,EAAE,IAAI,KAAK,OAAO,GAAG,SAAS,KAAK,YAAY,KAAK,OAAO,GAAG,MAAM,EAAE,KAAK,GAAG,EAAE;CAChK,OAAO;AACT;AAEA,eAAsB,gBAAgB,MAAc,OAA4B,MAAgC;CAC9G,MAAM,EAAE,KAAK,UAAU,MAAM;CAC7B,MAAM,OAAO,MAAM,IAAI,KAAK,EAAA,CAAG,MAAM,MAAM,EAAE,SAAS,IAAI;CAC1D,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,GAAG,KAAK,kBAAkB;CACpD,IAAI,IAAI,OAAO,UAAU,CAAC,MAAM,OAAO;EACrC,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,cAAc,IAAI,OAAO,KAAK,IAAI,EAAE,EAAE,CAAC;EACjE,EAAE,MAAM,mCAAmC,IAAI,kHAAkH;EACjK,OAAO;CACT;CACA,MAAM,OAAO,IAAI,OAAO,SAAS,gBAAgB,IAAI,OAAO,KAAK,IAAI,MAAM;CAC3E,IAAI,CAAE,MAAM,EAAE,QAAQ,wBAAwB,OAAO,KAAK,IAAI,KAAK,GAAI,OAAO;CAC9E,IAAI;EACF,MAAM,IAAI,OAAO,MAAM,CAAC,CAAC,MAAM,KAAK;CACtC,SAAS,KAAK;EACZ,MAAM,OAAO,UAAU,GAAG;EAC1B,IAAI,MAAM,MAAM,SAAS,UAAU;GACjC,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,eAAe,KAAK,UAAU,CAAC,EAAA,CAAG,KAAK,IAAI,EAAE,8CAA8C,CAAC;GACtH,OAAO;EACT;EACA,MAAM;CACR;CACA,EAAE,MAAM,GAAG,GAAG,MAAM,GAAG,EAAE,WAAW,KAAK,EAAE;CAC3C,OAAO;AACT;AAEA,MAAM,QAAQ;AAEd,SAAgB,0BAA0B,SAAwB;CAChE,MAAM,cAAc,QAAiB,IAAI,OAAO,oBAAoB,2DAA2D,eAAe,gBAAgB;CAC9J,MAAM,UAAU,OAAO,GAAqC,QAA4C;EACtG,MAAM,EAAE,iBAAiB,qBAAqB,MAAM,OAAO;EAC3D,MAAM,EAAE,qBAAqB,MAAM,OAAO;EAC1C,MAAM,UAAU,iBAAiB,EAAE,SAAS,eAAe,EAAE,MAAM,EAAE,OAAO,KAAK,CAAC,EAAE,CAAC;EACrF,MAAM,WAAW,gBAAgB,KAAK,QAAQ;GAC5C,MAAM,UAAU;IACd,QAAQ,MAAM;IACd,QAAQ,KAAK,QAAQ,WAAW,MAAM,OAAO,QAAQ,YAAY,KAAK,EAAE;GAC1E;GACA,QAAQ,KAAK,KAAK,CAAC;GACnB,OAAO,CAAC,KAAK,CAAC;EAChB,CAAC;EACD,IAAI;GACF,QAAQ,WAAW,MAAM,IAAI;IAAE,KAAK,IAAI,cAAc,OAAO;IAAG,UAAU,IAAI,iBAAiB,CAAC,CAAC,EAAE,GAAG;GAAE,CAAC;EAC3G,UAAU;GACR,KAAK,MAAM,CAAC,KAAK,MAAM,UAAU,QAAQ,eAAe,KAAK,CAAC;GAC9D,QAAQ,MAAM;EAChB;CACF;CAEA,MAAM,MAAM,QACT,QAAQ,KAAK,CAAC,CACd,YAAY,sHAAsH,CAAC,CACnI,QAAQ,wCAAwC,CAAC,CACjD,UAAU,KAAK;CAElB,WACE,IACG,QAAQ,KAAK,CAAC,CACd,YAAY,0GAA0G,CAAC,CACvH,SAAS,mBAAmB,wEAAwE,CACzG,CAAC,CACE,OAAO,aAAa,+EAA+E,CAAC,CACpG,YACC,SACA;;;;;IAKF,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI,wBACJ,CAAC,CACA,QAAQ,QAAgB,MAAwC,QAAQ,IAAI,SAAS,aAAa,QAAQ,IAAI,CAAC,CAAC;CAEnH,WAAW,IAAI,QAAQ,MAAM,CAAC,CAAC,YAAY,qGAAqG,CAAC,CAAC,CAAC,QAAQ,MACzJ,QAAQ,IAAI,SAAS,eAAe,IAAI,CAAC,CAC3C;CAEA,WAAW,IAAI,QAAQ,QAAQ,CAAC,CAAC,YAAY,yFAAyF,CAAC,CAAC,SAAS,UAAU,sBAAsB,CAAC,CAAC,CAChL,OAAO,aAAa,mCAAmC,CAAC,CACxD,QAAQ,MAAc,MAAwC,QAAQ,IAAI,SAAS,gBAAgB,MAAM,IAAI,CAAC,CAAC;CAElH,WAAW,IAAI,QAAQ,QAAQ,CAAC,CAAC,YAAY,wEAAwE,CAAC,CAAC,SAAS,UAAU,sBAAsB,CAAC,CAAC,CAC/J,OAAO,WAAW,yFAAyF,CAAC,CAC5G,OAAO,aAAa,WAAW,CAAC,CAChC,QAAQ,MAAc,MAAyD,QAAQ,IAAI,SAAS,gBAAgB,MAAM,GAAG,IAAI,CAAC,CAAC;AACxI"}
|
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-
|
|
62
|
+
const { runForeground } = await import("./server-DvFqIeG0.js");
|
|
63
63
|
await runForeground({
|
|
64
64
|
...configInput(o),
|
|
65
65
|
dev: !!o.dev,
|
|
@@ -138,11 +138,11 @@ program.command("reset-password").description("forgot the console password? Remo
|
|
|
138
138
|
db.close();
|
|
139
139
|
}
|
|
140
140
|
});
|
|
141
|
-
const { registerListenCommands } = await import("./commands-
|
|
141
|
+
const { registerListenCommands } = await import("./commands-CIiohOpI.js");
|
|
142
142
|
registerListenCommands(program);
|
|
143
|
-
const { registerConnectionsCommands } = await import("./commands-
|
|
143
|
+
const { registerConnectionsCommands } = await import("./commands-CU46puIx.js");
|
|
144
144
|
registerConnectionsCommands(program);
|
|
145
|
-
const { registerExtensionCommands } = await import("./cli-
|
|
145
|
+
const { registerExtensionCommands } = await import("./cli-CWUY8Vua.js");
|
|
146
146
|
registerExtensionCommands(program);
|
|
147
147
|
const AGENT_SUMMARIES = {
|
|
148
148
|
connect: "pair an agent; you approve it in the console",
|
|
@@ -83,11 +83,11 @@ Exit codes: 0 approved, 2 denied, 3 expired, 4 already consumed, 130 cancelled,
|
|
|
83
83
|
|
|
84
84
|
Example:
|
|
85
85
|
${NPX} connect https://mail.example.com --tool claude-code --setup-mcp`).action(async (url, flags) => {
|
|
86
|
-
const { runConnect } = await import("./connect-
|
|
86
|
+
const { runConnect } = await import("./connect-DH58vE7-.js");
|
|
87
87
|
process.exit(await runConnect(url, flags, { handleSignals: true }));
|
|
88
88
|
});
|
|
89
89
|
profileOption(program.command("setup-mcp").description("register the xaq MCP server in your agent's tool, without showing the key")).option("--tool <tool>", `${TOOLS.filter((t) => t !== "other").join(", ")} (default: the tool given to connect)`).option("--dry-run", "print the exact commands and file changes, and change nothing").addHelpText("after", mcpSetupHelp()).action(async (flags) => {
|
|
90
|
-
const { parseTool, printMcpResult } = await import("./connect-
|
|
90
|
+
const { parseTool, printMcpResult } = await import("./connect-DH58vE7-.js");
|
|
91
91
|
const { loadProfile } = await import("./profile-BpGWft1B.js");
|
|
92
92
|
const { setupMcp, mcpTarget } = await import("./mcpsetup-D7QlLvCo.js");
|
|
93
93
|
const { profilePath } = await import("./paths-Bk9CoSYL.js");
|
|
@@ -164,4 +164,4 @@ Example:
|
|
|
164
164
|
//#endregion
|
|
165
165
|
export { registerListenCommands };
|
|
166
166
|
|
|
167
|
-
//# sourceMappingURL=commands-
|
|
167
|
+
//# sourceMappingURL=commands-CIiohOpI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands-CqNK71Z1.js","names":[],"sources":["../server/listen/commands.ts"],"sourcesContent":["import { type Command, InvalidArgumentError } from \"commander\";\nimport { LEGACY_PRODUCT } from \"../brand.ts\";\nimport { EVENT_TYPES } from \"../../shared/types.ts\";\nimport type { ConnectFlags } from \"./connect.ts\";\nimport type { HermesFlags } from \"./hermes.ts\";\nimport type { ListenFlags } from \"./options.ts\";\nimport { DEFAULT_PROFILE } from \"./paths.ts\";\nimport { RECIPE_NAMES, recipesHelp, TOOLS } from \"./recipes.ts\";\nimport { NPX } from \"./version.ts\";\n\n/** `xaq connect`, `xaq setup-mcp` and `xaq listen …`, all lazily loaded. */\n\n/**\n * Options of a `listen` subcommand plus any its ancestors parsed: `listen` declares the same flags\n * (--profile, --exec…), and commander lets the parent claim them wherever they appear.\n */\nconst all = <T>(cmd: Command): T => cmd.optsWithGlobals() as T;\n\nconst collect = (value: string, previous: string[] | undefined) => [...(previous ?? []), value];\n\nconst int = (name: string) => (value: string) => {\n if (!/^\\d+$/.test(value)) throw new InvalidArgumentError(`${name} must be a whole number.`);\n return Number(value);\n};\n\nconst profileOption = (cmd: Command) => cmd.option(\"--profile <name>\", `profile to use (default \"${DEFAULT_PROFILE}\")`);\n\nfunction listenFlags(cmd: Command): Command {\n return profileOption(cmd)\n .option(\"--exec <command>\", \"run this command for each event (via /bin/sh; the event arrives on stdin as JSON, never in the command)\")\n .option(\"--recipe <name>\", `use a built-in target: ${RECIPE_NAMES.join(\", \")} (hermes forwards to your Hermes gateway; see it with --print-recipe)`)\n .option(\"--forward <url>\", \"POST each event to this localhost URL, signed per Standard Webhooks\")\n .option(\"--types <list>\", `comma-separated event types, or \"all\" (default: message.received, new mail only; also ${EVENT_TYPES.filter((t) => t !== \"message.received\").join(\", \")}; calendar.* need calendar.read)`)\n .option(\"--from <glob>\", 'only senders (calendar: organizers) matching this glob, e.g. \"*@stripe.com\" (repeatable)', collect)\n .option(\"--to <glob>\", \"only when a to/cc address (calendar: an attendee) matches (repeatable)\", collect)\n .option(\"--label <id>\", \"only messages with this Gmail label id, e.g. INBOX or Label_123 (repeatable)\", collect)\n .option(\"--subject <regex>\", \"only subjects (calendar: event titles) matching this case-insensitive regular expression\")\n .option(\"--not-from <glob>\", 'skip senders matching this glob, e.g. \"*@github.com\" (repeatable; --not-from \"\" --save clears saved exclusions)', collect)\n .option(\"--not-label <id>\", \"skip messages with this Gmail label id, e.g. CATEGORY_UPDATES (repeatable)\", collect)\n .option(\"--all-categories\", \"don't skip Gmail's Promotions, Social and Forums tabs (skipped by default)\")\n .option(\"--include-category <name>\", \"take one category back from the default skip: promotions, social or forums (repeatable)\", collect)\n .option(\"--default-categories\", \"back to the default: skip Promotions, Social and Forums (undoes a saved --all-categories / --include-category)\")\n .option(\"--batch <duration>\", `collect events this long (e.g. 60s, 2m) and run --exec once for all of them (up to 20); 0 turns it off`)\n .option(\"--include-body\", \"include the cleaned message body (calendar: the event description) in each event\")\n .option(\"--no-include-body\", \"don't include bodies (overrides a saved setting)\")\n .option(\"--concurrency <n>\", \"events handled at once (default 2)\", int(\"--concurrency\"))\n .option(\"--timeout <seconds>\", \"per-event time limit; the whole process group is killed after it (default 300)\", int(\"--timeout\"))\n .option(\"--max-attempts <n>\", \"attempts before an event goes to dead letters (default 5)\", int(\"--max-attempts\"))\n .option(\"--consumer <name>\", \"server-side cursor name (default <hostname>-<profile>)\")\n .option(\"--cwd <dir>\", \"directory --exec commands run in (default: a private dir in the state dir; must be yours and not group/world-writable)\")\n .option(\"--insecure\", \"allow plain http to a non-loopback, non-Tailscale daemon (loud warning)\")\n .option(\"--save\", \"save these settings to the profile\");\n}\n\n/** `listen hermes --help`. */\nfunction hermesHelp(): string {\n return `\n--recipe hermes forwards each event to your running Hermes gateway (http://127.0.0.1:8644/webhooks/xaq; for\nanother profile the route is xaq-<profile>; a profile set up before the rename keeps its ${LEGACY_PRODUCT}[-<profile>] route,\ntoolset and server name). Hermes verifies the Standard Webhooks signature with the\nlistener's secret, runs the triage, and delivers the result where this route says. Mail that isn't important gets\na [SILENT] reply, which Hermes doesn't deliver.\n\nA Hermes webhook run normally gets web tools (web_search, web_extract, vision_analyze, clarify) and every MCP\nserver enabled in Hermes: with email as the trigger, an attacker could make it read your mail and send it out.\n--run therefore also limits the route to the xaq MCP server (\"toolsets\": [\"mcp-xaq\"] in\nwebhook_subscriptions.json, which \\`hermes webhook subscribe\\` can't set). That limit only holds when xaq is an\nenabled MCP server in Hermes' config.yaml (else Hermes adds every MCP server), so this refuses until\n\\`${NPX} setup-mcp --tool hermes\\` has added it. --run creates the route disabled with the real secret under Hermes'\nlock (python3), runs \\`hermes webhook subscribe\\` without --secret (hermes keeps the secret and the disabled state),\nthen sets the toolsets and enables it. The secret is never in a command line, the route never runs unconfined, and\nany failure removes it again. Re-run it after any \\`hermes webhook subscribe\\` for this route (that resets the\ntoolsets). The Hermes home follows HERMES_HOME or Hermes' sticky active_profile.\n\nWithout --run it prints both steps for you to do by hand; the toolsets edit is required.\n\n--cron-job hands the email to that job's own tools, so it is accepted only when the job's enabled_toolsets is\nexactly [\"xaq\"] (the bare server name; \"mcp-xaq\" doesn't narrow MCP servers for cron jobs).\n\nNeeds python3, the gateway's webhook platform (hermes gateway setup, or WEBHOOK_ENABLED=true in ~/.hermes/.env) and\na running gateway. Check it: curl http://127.0.0.1:8644/health\n\nExamples:\n ${NPX} listen hermes --deliver telegram --run\n ${NPX} listen hermes --cron-job email-watch --run # only for a job limited to [\"xaq\"]\n ${NPX} listen service install --recipe hermes`;\n}\n\n/** `setup-mcp --help`: exactly what it changes, per tool. */\nfunction mcpSetupHelp(): string {\n return `\nWhat it changes (the server is named \"xaq\", or \"xaq-<profile>\" for --profile; a profile set up before the\nrename keeps the \"${LEGACY_PRODUCT}[-<profile>]\" name it already has in your tools):\n claude-code runs \\`claude mcp remove xaq --scope user\\` then\n \\`claude mcp add-json --scope user xaq '{\"type\":\"http\",\"url\":\"<daemon>/mcp\",\"headersHelper\":\"…\"}'\\`.\n The header helper (~/.config/xaq/bin/mcp-header.mjs) reads the key from your profile, so\n the key is in neither the command line nor ~/.claude.json. Backs up ~/.claude.json first\n ($CLAUDE_CONFIG_DIR/.claude.json if set).\n codex adds or replaces [mcp_servers.xaq] in ~/.codex/config.toml ($CODEX_HOME), with the key in\n http_headers; the file becomes 0600.\n cursor adds or replaces mcpServers.xaq in ~/.cursor/mcp.json, with the key in headers; 0600.\n hermes adds or replaces mcp_servers.xaq in ~/.hermes/config.yaml ($HERMES_HOME) and puts the key in\n ~/.hermes/.env as XAQ_API_KEY; both 0600.\nEvery file is backed up first as <file>.xaq-backup-<timestamp> (0600; backups of files holding the key hold it\ntoo). It also refreshes ~/.config/xaq/mcp/<profile>.claude.json (no key), which the listen recipe uses.\n\nCheck it afterwards: claude mcp list · codex mcp list · agent mcp list (Cursor) · hermes mcp test xaq\n\nExample:\n ${NPX} setup-mcp --tool claude-code --dry-run`;\n}\n\nexport function registerListenCommands(program: Command): void {\n program\n .command(\"connect\")\n .description(\"pair this machine's agent with a xaq daemon (approve the code in the console)\")\n .argument(\"<daemon-url>\", \"the xaq daemon, e.g. https://mail.example.com or http://100.101.102.103:8425\")\n .option(\"--name <name>\", 'how the agent appears in the console (default \"<Tool> on <hostname>\")')\n .option(\"--tool <tool>\", `the agent's tool: ${TOOLS.join(\", \")}; tailors the next steps`)\n .option(\"--account <email>\", \"mailbox to request access to (repeatable; the approver decides)\", collect)\n .option(\"--capabilities <list>\", \"capabilities to request, e.g. read,draft or read,calendar.read (the approver decides)\")\n .option(\"--reason <text>\", \"why the agent needs access (shown to the approver)\")\n .option(\"--setup-mcp\", \"also register the MCP server in the chosen tool (the key is never shown; `setup-mcp --help` lists exactly what changes)\")\n .option(\"--profile <name>\", `profile to save the key in (default \"${DEFAULT_PROFILE}\")`)\n .option(\"--consumer <name>\", \"listener cursor name (default <hostname>-<profile>)\")\n .option(\"--log <file>\", \"also write the output to this file (created 0600; for running connect in the background)\")\n .option(\"--insecure\", \"allow plain http to a non-loopback, non-Tailscale daemon (loud warning)\")\n .option(\"--force\", \"re-pair an existing profile (keeps its listener settings)\")\n .addHelpText(\n \"after\",\n `\nExit codes: 0 approved, 2 denied, 3 expired, 4 already consumed, 130 cancelled, 1 error.\n\nExample:\n ${NPX} connect https://mail.example.com --tool claude-code --setup-mcp`,\n )\n .action(async (url: string, flags: ConnectFlags) => {\n const { runConnect } = await import(\"./connect.ts\");\n process.exit(await runConnect(url, flags, { handleSignals: true }));\n });\n\n profileOption(program.command(\"setup-mcp\").description(\"register the xaq MCP server in your agent's tool, without showing the key\"))\n .option(\"--tool <tool>\", `${TOOLS.filter((t) => t !== \"other\").join(\", \")} (default: the tool given to connect)`)\n .option(\"--dry-run\", \"print the exact commands and file changes, and change nothing\")\n .addHelpText(\"after\", mcpSetupHelp())\n .action(async (flags: { tool?: string; profile?: string; dryRun?: boolean }) => {\n const { parseTool, printMcpResult } = await import(\"./connect.ts\");\n const { loadProfile } = await import(\"./profile.ts\");\n const { setupMcp, mcpTarget } = await import(\"./mcpsetup.ts\");\n const { profilePath } = await import(\"./paths.ts\");\n const name = flags.profile ?? DEFAULT_PROFILE;\n const profile = loadProfile(name);\n const tool = flags.tool ? parseTool(flags.tool) : (profile.tool ?? \"other\");\n if (tool === \"other\") throw new Error(`Which tool? Pass --tool ${TOOLS.filter((t) => t !== \"other\").join(\"|\")}.`);\n const { claudeMcpConfigPath, writeClaudeMcpConfig } = await import(\"./mcpheader.ts\");\n const r = setupMcp(tool, mcpTarget(name, profile), profilePath(name), { dryRun: flags.dryRun });\n if (flags.dryRun) r.changes = [...(r.changes ?? []), `refresh ${claudeMcpConfigPath(name)} (keyless MCP config the Claude Code listen recipe loads)`];\n else writeClaudeMcpConfig(name, `${profile.url}/mcp`);\n printMcpResult(r);\n if (!r.ok) process.exitCode = 1;\n });\n\n profileOption(\n program.command(\"mcp-header\").description(\"print the agent's Authorization header as JSON for an MCP client's header helper (refuses to print to a terminal)\"),\n ).action(async (flags: { profile?: string }) => {\n const { printMcpHeader } = await import(\"./mcpheader.ts\");\n process.exitCode = printMcpHeader(flags.profile ?? DEFAULT_PROFILE);\n });\n\n const listen = listenFlags(\n program\n .command(\"listen\")\n .description(\"wake a local agent on new mail: hold an outbound stream to the daemon and run a command or POST to localhost per event\"),\n )\n .option(\"--dry-run\", \"print matching events without running anything (uses a throwaway <consumer>-dry-run cursor)\")\n .option(\"--from-start\", \"a NEW consumer starts at the oldest stored event (no effect once it exists: use --backfill)\")\n .option(\"--backfill\", \"run the mail from before this listener started through --exec/--forward once, oldest first, then exit; safe while the listener runs (own cursor)\")\n .option(\"--until <seq>\", \"with --backfill: replay up to this event number instead of where the listener started\", int(\"--until\"))\n .option(\"--print-recipe <name>\", `print what --recipe <name> runs (hermes: its URL), for ${RECIPE_NAMES.join(\", \")} (with this machine's paths), and exit`)\n .addHelpText(\"after\", recipesHelp())\n .action(async (flags: ListenFlags & { printRecipe?: string }) => {\n if (flags.printRecipe !== undefined) {\n const { parseRecipeTool, recipe } = await import(\"./recipes.ts\");\n const name = flags.printRecipe.trim().toLowerCase();\n const r = recipe(name === \"other\" ? \"other\" : parseRecipeTool(name), flags.profile ?? DEFAULT_PROFILE);\n // Exec recipes print the bare command (to edit and pass back with --exec); hermes its forward URL.\n process.stdout.write(`${r.exec ?? r.forward}\\n`);\n return;\n }\n const { runListener } = await import(\"./listen.ts\");\n process.exit(await runListener({ flags, handleSignals: true }));\n });\n\n profileOption(listen.command(\"status\").description(\"show the listener's connection, cursor, recent events and dead letters\")).action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string }>(cmd);\n const { printStatus } = await import(\"./admin.ts\");\n await printStatus(flags.profile ?? DEFAULT_PROFILE);\n });\n\n profileOption(listen.command(\"secret\").description(\"print the forward-mode signing secret (whsec_…) for your local receiver\"))\n .option(\"--rotate\", \"generate a new secret (restart the listener afterwards)\")\n .action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string; rotate?: boolean }>(cmd);\n const { printSecret } = await import(\"./admin.ts\");\n printSecret(flags.profile ?? DEFAULT_PROFILE, flags);\n });\n\n profileOption(\n listen\n .command(\"hermes\")\n .description(\"create the Hermes gateway webhook route that --recipe hermes forwards to, limited to the xaq tools\"),\n )\n .option(\"--deliver <target>\", \"where Hermes sends its triage: telegram, discord, slack… (a platform connected to your gateway), or log\")\n .option(\"--deliver-chat-id <id>\", \"with --deliver: a specific chat instead of the platform's home channel\")\n .option(\"--cron-job <job>\", \"instead of --deliver: fire this existing Hermes cron job (id or name; `hermes cron list`); its prompt, tools and delivery apply, so its enabled_toolsets must be exactly [\\\"xaq\\\"]\")\n .option(\"--script <file>\", \"a Hermes filter script under ~/.hermes/scripts (runs before the agent; can drop events at no LLM cost)\")\n .option(\"--run\", \"set the route up now: run hermes, then set the real secret and limit the route to the xaq tools (recommended)\")\n .addHelpText(\"after\", hermesHelp())\n .action(async (_o: unknown, cmd: Command) => {\n const flags = all<HermesFlags>(cmd);\n const { hermesSubscribe } = await import(\"./hermes.ts\");\n process.exitCode = await hermesSubscribe(flags.profile ?? DEFAULT_PROFILE, flags);\n });\n\n listenFlags(listen.command(\"dead\").description(\"list events that failed every attempt; --replay runs them again\"))\n .option(\"--replay\", \"run dead events again (successes are removed)\")\n .option(\"--id <eventId>\", \"only this event (with --replay or --clear)\")\n .option(\"--clear\", \"delete dead events without running them\")\n .option(\"--json\", \"print raw JSON lines\")\n .action(async (_o: unknown, cmd: Command) => {\n const flags = all<ListenFlags & { replay?: boolean; id?: string; clear?: boolean; json?: boolean }>(cmd);\n const admin = await import(\"./admin.ts\");\n const profile = flags.profile ?? DEFAULT_PROFILE;\n if (flags.clear) admin.clearDead(profile, flags.id);\n else if (flags.replay) {\n if ((await admin.replayDead(flags)) > 0) process.exitCode = 1;\n } else admin.printDead(profile, flags);\n });\n\n const service = listen.command(\"service\").description(\"run the listener in the background (systemd user service / launchd agent, one per profile)\");\n listenFlags(service.command(\"install\").description(\"install and start the listener service; flags are saved to the profile. Re-run to update\")).action(\n async (_o: unknown, cmd: Command) => {\n const flags = all<ListenFlags>(cmd);\n const { installListenService } = await import(\"./service.ts\");\n await installListenService(flags);\n },\n );\n profileOption(service.command(\"uninstall\").description(\"stop and remove the listener service (keeps the profile)\")).action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string }>(cmd);\n const { uninstallListenService } = await import(\"./service.ts\");\n uninstallListenService(flags.profile ?? DEFAULT_PROFILE);\n });\n profileOption(service.command(\"status\").description(\"show the service manager's status for the listener\")).action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string }>(cmd);\n const { listenServiceStatus } = await import(\"./service.ts\");\n listenServiceStatus(flags.profile ?? DEFAULT_PROFILE);\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"commands-CIiohOpI.js","names":[],"sources":["../server/listen/commands.ts"],"sourcesContent":["import { type Command, InvalidArgumentError } from \"commander\";\nimport { LEGACY_PRODUCT } from \"../brand.ts\";\nimport { EVENT_TYPES } from \"../../shared/types.ts\";\nimport type { ConnectFlags } from \"./connect.ts\";\nimport type { HermesFlags } from \"./hermes.ts\";\nimport type { ListenFlags } from \"./options.ts\";\nimport { DEFAULT_PROFILE } from \"./paths.ts\";\nimport { RECIPE_NAMES, recipesHelp, TOOLS } from \"./recipes.ts\";\nimport { NPX } from \"./version.ts\";\n\n/** `xaq connect`, `xaq setup-mcp` and `xaq listen …`, all lazily loaded. */\n\n/**\n * Options of a `listen` subcommand plus any its ancestors parsed: `listen` declares the same flags\n * (--profile, --exec…), and commander lets the parent claim them wherever they appear.\n */\nconst all = <T>(cmd: Command): T => cmd.optsWithGlobals() as T;\n\nconst collect = (value: string, previous: string[] | undefined) => [...(previous ?? []), value];\n\nconst int = (name: string) => (value: string) => {\n if (!/^\\d+$/.test(value)) throw new InvalidArgumentError(`${name} must be a whole number.`);\n return Number(value);\n};\n\nconst profileOption = (cmd: Command) => cmd.option(\"--profile <name>\", `profile to use (default \"${DEFAULT_PROFILE}\")`);\n\nfunction listenFlags(cmd: Command): Command {\n return profileOption(cmd)\n .option(\"--exec <command>\", \"run this command for each event (via /bin/sh; the event arrives on stdin as JSON, never in the command)\")\n .option(\"--recipe <name>\", `use a built-in target: ${RECIPE_NAMES.join(\", \")} (hermes forwards to your Hermes gateway; see it with --print-recipe)`)\n .option(\"--forward <url>\", \"POST each event to this localhost URL, signed per Standard Webhooks\")\n .option(\"--types <list>\", `comma-separated event types, or \"all\" (default: message.received, new mail only; also ${EVENT_TYPES.filter((t) => t !== \"message.received\").join(\", \")}; calendar.* need calendar.read)`)\n .option(\"--from <glob>\", 'only senders (calendar: organizers) matching this glob, e.g. \"*@stripe.com\" (repeatable)', collect)\n .option(\"--to <glob>\", \"only when a to/cc address (calendar: an attendee) matches (repeatable)\", collect)\n .option(\"--label <id>\", \"only messages with this Gmail label id, e.g. INBOX or Label_123 (repeatable)\", collect)\n .option(\"--subject <regex>\", \"only subjects (calendar: event titles) matching this case-insensitive regular expression\")\n .option(\"--not-from <glob>\", 'skip senders matching this glob, e.g. \"*@github.com\" (repeatable; --not-from \"\" --save clears saved exclusions)', collect)\n .option(\"--not-label <id>\", \"skip messages with this Gmail label id, e.g. CATEGORY_UPDATES (repeatable)\", collect)\n .option(\"--all-categories\", \"don't skip Gmail's Promotions, Social and Forums tabs (skipped by default)\")\n .option(\"--include-category <name>\", \"take one category back from the default skip: promotions, social or forums (repeatable)\", collect)\n .option(\"--default-categories\", \"back to the default: skip Promotions, Social and Forums (undoes a saved --all-categories / --include-category)\")\n .option(\"--batch <duration>\", `collect events this long (e.g. 60s, 2m) and run --exec once for all of them (up to 20); 0 turns it off`)\n .option(\"--include-body\", \"include the cleaned message body (calendar: the event description) in each event\")\n .option(\"--no-include-body\", \"don't include bodies (overrides a saved setting)\")\n .option(\"--concurrency <n>\", \"events handled at once (default 2)\", int(\"--concurrency\"))\n .option(\"--timeout <seconds>\", \"per-event time limit; the whole process group is killed after it (default 300)\", int(\"--timeout\"))\n .option(\"--max-attempts <n>\", \"attempts before an event goes to dead letters (default 5)\", int(\"--max-attempts\"))\n .option(\"--consumer <name>\", \"server-side cursor name (default <hostname>-<profile>)\")\n .option(\"--cwd <dir>\", \"directory --exec commands run in (default: a private dir in the state dir; must be yours and not group/world-writable)\")\n .option(\"--insecure\", \"allow plain http to a non-loopback, non-Tailscale daemon (loud warning)\")\n .option(\"--save\", \"save these settings to the profile\");\n}\n\n/** `listen hermes --help`. */\nfunction hermesHelp(): string {\n return `\n--recipe hermes forwards each event to your running Hermes gateway (http://127.0.0.1:8644/webhooks/xaq; for\nanother profile the route is xaq-<profile>; a profile set up before the rename keeps its ${LEGACY_PRODUCT}[-<profile>] route,\ntoolset and server name). Hermes verifies the Standard Webhooks signature with the\nlistener's secret, runs the triage, and delivers the result where this route says. Mail that isn't important gets\na [SILENT] reply, which Hermes doesn't deliver.\n\nA Hermes webhook run normally gets web tools (web_search, web_extract, vision_analyze, clarify) and every MCP\nserver enabled in Hermes: with email as the trigger, an attacker could make it read your mail and send it out.\n--run therefore also limits the route to the xaq MCP server (\"toolsets\": [\"mcp-xaq\"] in\nwebhook_subscriptions.json, which \\`hermes webhook subscribe\\` can't set). That limit only holds when xaq is an\nenabled MCP server in Hermes' config.yaml (else Hermes adds every MCP server), so this refuses until\n\\`${NPX} setup-mcp --tool hermes\\` has added it. --run creates the route disabled with the real secret under Hermes'\nlock (python3), runs \\`hermes webhook subscribe\\` without --secret (hermes keeps the secret and the disabled state),\nthen sets the toolsets and enables it. The secret is never in a command line, the route never runs unconfined, and\nany failure removes it again. Re-run it after any \\`hermes webhook subscribe\\` for this route (that resets the\ntoolsets). The Hermes home follows HERMES_HOME or Hermes' sticky active_profile.\n\nWithout --run it prints both steps for you to do by hand; the toolsets edit is required.\n\n--cron-job hands the email to that job's own tools, so it is accepted only when the job's enabled_toolsets is\nexactly [\"xaq\"] (the bare server name; \"mcp-xaq\" doesn't narrow MCP servers for cron jobs).\n\nNeeds python3, the gateway's webhook platform (hermes gateway setup, or WEBHOOK_ENABLED=true in ~/.hermes/.env) and\na running gateway. Check it: curl http://127.0.0.1:8644/health\n\nExamples:\n ${NPX} listen hermes --deliver telegram --run\n ${NPX} listen hermes --cron-job email-watch --run # only for a job limited to [\"xaq\"]\n ${NPX} listen service install --recipe hermes`;\n}\n\n/** `setup-mcp --help`: exactly what it changes, per tool. */\nfunction mcpSetupHelp(): string {\n return `\nWhat it changes (the server is named \"xaq\", or \"xaq-<profile>\" for --profile; a profile set up before the\nrename keeps the \"${LEGACY_PRODUCT}[-<profile>]\" name it already has in your tools):\n claude-code runs \\`claude mcp remove xaq --scope user\\` then\n \\`claude mcp add-json --scope user xaq '{\"type\":\"http\",\"url\":\"<daemon>/mcp\",\"headersHelper\":\"…\"}'\\`.\n The header helper (~/.config/xaq/bin/mcp-header.mjs) reads the key from your profile, so\n the key is in neither the command line nor ~/.claude.json. Backs up ~/.claude.json first\n ($CLAUDE_CONFIG_DIR/.claude.json if set).\n codex adds or replaces [mcp_servers.xaq] in ~/.codex/config.toml ($CODEX_HOME), with the key in\n http_headers; the file becomes 0600.\n cursor adds or replaces mcpServers.xaq in ~/.cursor/mcp.json, with the key in headers; 0600.\n hermes adds or replaces mcp_servers.xaq in ~/.hermes/config.yaml ($HERMES_HOME) and puts the key in\n ~/.hermes/.env as XAQ_API_KEY; both 0600.\nEvery file is backed up first as <file>.xaq-backup-<timestamp> (0600; backups of files holding the key hold it\ntoo). It also refreshes ~/.config/xaq/mcp/<profile>.claude.json (no key), which the listen recipe uses.\n\nCheck it afterwards: claude mcp list · codex mcp list · agent mcp list (Cursor) · hermes mcp test xaq\n\nExample:\n ${NPX} setup-mcp --tool claude-code --dry-run`;\n}\n\nexport function registerListenCommands(program: Command): void {\n program\n .command(\"connect\")\n .description(\"pair this machine's agent with a xaq daemon (approve the code in the console)\")\n .argument(\"<daemon-url>\", \"the xaq daemon, e.g. https://mail.example.com or http://100.101.102.103:8425\")\n .option(\"--name <name>\", 'how the agent appears in the console (default \"<Tool> on <hostname>\")')\n .option(\"--tool <tool>\", `the agent's tool: ${TOOLS.join(\", \")}; tailors the next steps`)\n .option(\"--account <email>\", \"mailbox to request access to (repeatable; the approver decides)\", collect)\n .option(\"--capabilities <list>\", \"capabilities to request, e.g. read,draft or read,calendar.read (the approver decides)\")\n .option(\"--reason <text>\", \"why the agent needs access (shown to the approver)\")\n .option(\"--setup-mcp\", \"also register the MCP server in the chosen tool (the key is never shown; `setup-mcp --help` lists exactly what changes)\")\n .option(\"--profile <name>\", `profile to save the key in (default \"${DEFAULT_PROFILE}\")`)\n .option(\"--consumer <name>\", \"listener cursor name (default <hostname>-<profile>)\")\n .option(\"--log <file>\", \"also write the output to this file (created 0600; for running connect in the background)\")\n .option(\"--insecure\", \"allow plain http to a non-loopback, non-Tailscale daemon (loud warning)\")\n .option(\"--force\", \"re-pair an existing profile (keeps its listener settings)\")\n .addHelpText(\n \"after\",\n `\nExit codes: 0 approved, 2 denied, 3 expired, 4 already consumed, 130 cancelled, 1 error.\n\nExample:\n ${NPX} connect https://mail.example.com --tool claude-code --setup-mcp`,\n )\n .action(async (url: string, flags: ConnectFlags) => {\n const { runConnect } = await import(\"./connect.ts\");\n process.exit(await runConnect(url, flags, { handleSignals: true }));\n });\n\n profileOption(program.command(\"setup-mcp\").description(\"register the xaq MCP server in your agent's tool, without showing the key\"))\n .option(\"--tool <tool>\", `${TOOLS.filter((t) => t !== \"other\").join(\", \")} (default: the tool given to connect)`)\n .option(\"--dry-run\", \"print the exact commands and file changes, and change nothing\")\n .addHelpText(\"after\", mcpSetupHelp())\n .action(async (flags: { tool?: string; profile?: string; dryRun?: boolean }) => {\n const { parseTool, printMcpResult } = await import(\"./connect.ts\");\n const { loadProfile } = await import(\"./profile.ts\");\n const { setupMcp, mcpTarget } = await import(\"./mcpsetup.ts\");\n const { profilePath } = await import(\"./paths.ts\");\n const name = flags.profile ?? DEFAULT_PROFILE;\n const profile = loadProfile(name);\n const tool = flags.tool ? parseTool(flags.tool) : (profile.tool ?? \"other\");\n if (tool === \"other\") throw new Error(`Which tool? Pass --tool ${TOOLS.filter((t) => t !== \"other\").join(\"|\")}.`);\n const { claudeMcpConfigPath, writeClaudeMcpConfig } = await import(\"./mcpheader.ts\");\n const r = setupMcp(tool, mcpTarget(name, profile), profilePath(name), { dryRun: flags.dryRun });\n if (flags.dryRun) r.changes = [...(r.changes ?? []), `refresh ${claudeMcpConfigPath(name)} (keyless MCP config the Claude Code listen recipe loads)`];\n else writeClaudeMcpConfig(name, `${profile.url}/mcp`);\n printMcpResult(r);\n if (!r.ok) process.exitCode = 1;\n });\n\n profileOption(\n program.command(\"mcp-header\").description(\"print the agent's Authorization header as JSON for an MCP client's header helper (refuses to print to a terminal)\"),\n ).action(async (flags: { profile?: string }) => {\n const { printMcpHeader } = await import(\"./mcpheader.ts\");\n process.exitCode = printMcpHeader(flags.profile ?? DEFAULT_PROFILE);\n });\n\n const listen = listenFlags(\n program\n .command(\"listen\")\n .description(\"wake a local agent on new mail: hold an outbound stream to the daemon and run a command or POST to localhost per event\"),\n )\n .option(\"--dry-run\", \"print matching events without running anything (uses a throwaway <consumer>-dry-run cursor)\")\n .option(\"--from-start\", \"a NEW consumer starts at the oldest stored event (no effect once it exists: use --backfill)\")\n .option(\"--backfill\", \"run the mail from before this listener started through --exec/--forward once, oldest first, then exit; safe while the listener runs (own cursor)\")\n .option(\"--until <seq>\", \"with --backfill: replay up to this event number instead of where the listener started\", int(\"--until\"))\n .option(\"--print-recipe <name>\", `print what --recipe <name> runs (hermes: its URL), for ${RECIPE_NAMES.join(\", \")} (with this machine's paths), and exit`)\n .addHelpText(\"after\", recipesHelp())\n .action(async (flags: ListenFlags & { printRecipe?: string }) => {\n if (flags.printRecipe !== undefined) {\n const { parseRecipeTool, recipe } = await import(\"./recipes.ts\");\n const name = flags.printRecipe.trim().toLowerCase();\n const r = recipe(name === \"other\" ? \"other\" : parseRecipeTool(name), flags.profile ?? DEFAULT_PROFILE);\n // Exec recipes print the bare command (to edit and pass back with --exec); hermes its forward URL.\n process.stdout.write(`${r.exec ?? r.forward}\\n`);\n return;\n }\n const { runListener } = await import(\"./listen.ts\");\n process.exit(await runListener({ flags, handleSignals: true }));\n });\n\n profileOption(listen.command(\"status\").description(\"show the listener's connection, cursor, recent events and dead letters\")).action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string }>(cmd);\n const { printStatus } = await import(\"./admin.ts\");\n await printStatus(flags.profile ?? DEFAULT_PROFILE);\n });\n\n profileOption(listen.command(\"secret\").description(\"print the forward-mode signing secret (whsec_…) for your local receiver\"))\n .option(\"--rotate\", \"generate a new secret (restart the listener afterwards)\")\n .action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string; rotate?: boolean }>(cmd);\n const { printSecret } = await import(\"./admin.ts\");\n printSecret(flags.profile ?? DEFAULT_PROFILE, flags);\n });\n\n profileOption(\n listen\n .command(\"hermes\")\n .description(\"create the Hermes gateway webhook route that --recipe hermes forwards to, limited to the xaq tools\"),\n )\n .option(\"--deliver <target>\", \"where Hermes sends its triage: telegram, discord, slack… (a platform connected to your gateway), or log\")\n .option(\"--deliver-chat-id <id>\", \"with --deliver: a specific chat instead of the platform's home channel\")\n .option(\"--cron-job <job>\", \"instead of --deliver: fire this existing Hermes cron job (id or name; `hermes cron list`); its prompt, tools and delivery apply, so its enabled_toolsets must be exactly [\\\"xaq\\\"]\")\n .option(\"--script <file>\", \"a Hermes filter script under ~/.hermes/scripts (runs before the agent; can drop events at no LLM cost)\")\n .option(\"--run\", \"set the route up now: run hermes, then set the real secret and limit the route to the xaq tools (recommended)\")\n .addHelpText(\"after\", hermesHelp())\n .action(async (_o: unknown, cmd: Command) => {\n const flags = all<HermesFlags>(cmd);\n const { hermesSubscribe } = await import(\"./hermes.ts\");\n process.exitCode = await hermesSubscribe(flags.profile ?? DEFAULT_PROFILE, flags);\n });\n\n listenFlags(listen.command(\"dead\").description(\"list events that failed every attempt; --replay runs them again\"))\n .option(\"--replay\", \"run dead events again (successes are removed)\")\n .option(\"--id <eventId>\", \"only this event (with --replay or --clear)\")\n .option(\"--clear\", \"delete dead events without running them\")\n .option(\"--json\", \"print raw JSON lines\")\n .action(async (_o: unknown, cmd: Command) => {\n const flags = all<ListenFlags & { replay?: boolean; id?: string; clear?: boolean; json?: boolean }>(cmd);\n const admin = await import(\"./admin.ts\");\n const profile = flags.profile ?? DEFAULT_PROFILE;\n if (flags.clear) admin.clearDead(profile, flags.id);\n else if (flags.replay) {\n if ((await admin.replayDead(flags)) > 0) process.exitCode = 1;\n } else admin.printDead(profile, flags);\n });\n\n const service = listen.command(\"service\").description(\"run the listener in the background (systemd user service / launchd agent, one per profile)\");\n listenFlags(service.command(\"install\").description(\"install and start the listener service; flags are saved to the profile. Re-run to update\")).action(\n async (_o: unknown, cmd: Command) => {\n const flags = all<ListenFlags>(cmd);\n const { installListenService } = await import(\"./service.ts\");\n await installListenService(flags);\n },\n );\n profileOption(service.command(\"uninstall\").description(\"stop and remove the listener service (keeps the profile)\")).action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string }>(cmd);\n const { uninstallListenService } = await import(\"./service.ts\");\n uninstallListenService(flags.profile ?? DEFAULT_PROFILE);\n });\n profileOption(service.command(\"status\").description(\"show the service manager's status for the listener\")).action(async (_o: unknown, cmd: Command) => {\n const flags = all<{ profile?: string }>(cmd);\n const { listenServiceStatus } = await import(\"./service.ts\");\n listenServiceStatus(flags.profile ?? DEFAULT_PROFILE);\n });\n}\n"],"mappings":"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"}
|
|
@@ -44,34 +44,34 @@ async function selfOrigins(dataDir) {
|
|
|
44
44
|
];
|
|
45
45
|
}
|
|
46
46
|
function registerConnectionsCommands(program) {
|
|
47
|
-
const connections = program.command("connections", { hidden: false }).description("the MCP servers xaq connects agents to (Notion,
|
|
48
|
-
dataOption(connections.command("add").description("connect an
|
|
47
|
+
const connections = program.command("connections", { hidden: false }).description("the MCP servers xaq connects agents to (Notion, T3 Code, any MCP URL, installed extensions); run on xaq's machine").summary("add, list, reconnect or remove connected MCP servers").helpGroup(GROUP);
|
|
48
|
+
dataOption(connections.command("add").description("connect an installed extension (install it first: `ext add notion`) or any MCP server URL, interactively").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")).option("--url <address>", "t3code: your T3 Code server's address, e.g. http://100.101.102.103:3773 (asked when omitted)").option("--slug <name>", "its short name: agents see its tools as <name>__<tool>").option("--name <name>", "its display name (unique; default: the server's host, or the integration's name)").option("--access <level>", "full, ask (ask before risky actions; the default) or read").option("--agent <name>", "an agent that gets it (repeatable; default: all agents; \"all\")", collect).option("--header <name>", "header for a server that wants a static key (default Authorization)").option("--paste", "paste the address the browser lands on after signing in, instead of waiting for the redirect (automatic over SSH)").option("--allow-private <origin>", "allow this exact scheme://host:port on this machine or a private network without asking (--yes never does)").option("-y, --yes", "answer yes to confirmations and take the defaults (never to a private-network allow)").addHelpText("after", `
|
|
49
49
|
Examples:
|
|
50
50
|
${NPX} connections add notion
|
|
51
51
|
${NPX} connections add t3code --url http://100.101.102.103:3773 # one per T3 server; have a T3 pairing code ready
|
|
52
52
|
${NPX} connections add https://mcp.example.com/mcp --access read
|
|
53
53
|
${NPX} connections add http://127.0.0.1:8787/mcp # asks before allowing a server on this machine`).action(async (target, o) => {
|
|
54
|
-
const { addConnection } = await import("./manage-
|
|
54
|
+
const { addConnection } = await import("./manage-DGvJajD1.js");
|
|
55
55
|
process.exitCode = await withApi(o, (deps) => addConnection(target, o, deps));
|
|
56
56
|
});
|
|
57
57
|
dataOption(connections.command("list").description("list connections with their status and access")).action(async (o) => {
|
|
58
|
-
const { listConnections } = await import("./manage-
|
|
58
|
+
const { listConnections } = await import("./manage-DGvJajD1.js");
|
|
59
59
|
process.exitCode = await withApi(o, (deps) => listConnections(deps));
|
|
60
60
|
});
|
|
61
61
|
dataOption(connections.command("reconnect").description("sign in again (OAuth) or replace the key (header)").argument("<name>", "the connection's name")).option("--paste", "paste the address the browser lands on (automatic over SSH)").option("--header <name>", "header connections: the header's name (default: asks, Authorization)").action(async (slug, o) => {
|
|
62
|
-
const { reconnectConnection } = await import("./manage-
|
|
62
|
+
const { reconnectConnection } = await import("./manage-DGvJajD1.js");
|
|
63
63
|
process.exitCode = await withApi(o, (deps) => reconnectConnection(slug, o, deps));
|
|
64
64
|
});
|
|
65
65
|
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")).option("-y, --yes", "don't ask").action(async (slug, o) => {
|
|
66
|
-
const { disableConnection } = await import("./manage-
|
|
66
|
+
const { disableConnection } = await import("./manage-DGvJajD1.js");
|
|
67
67
|
process.exitCode = await withApi(o, (deps) => disableConnection(slug, deps));
|
|
68
68
|
});
|
|
69
69
|
dataOption(connections.command("rename").description("change a connection's short name (agents see its tools as <name>__<tool>) or its display name").argument("<name>", "the connection's current short name (or its id)")).option("--slug <new>", "the new short name: 1-24 lowercase letters, digits and dashes (calls by the old tool names stop working)").option("--name <display-name>", "a new display name").option("-y, --yes", "don't ask").action(async (target, o) => {
|
|
70
|
-
const { renameConnection } = await import("./manage-
|
|
70
|
+
const { renameConnection } = await import("./manage-DGvJajD1.js");
|
|
71
71
|
process.exitCode = await withApi(o, (deps) => renameConnection(target, o, deps));
|
|
72
72
|
});
|
|
73
73
|
dataOption(connections.command("remove").description("remove a connection and delete its credentials").argument("<name>", "the connection's name")).option("-y, --yes", "don't ask").action(async (slug, o) => {
|
|
74
|
-
const { removeConnection } = await import("./manage-
|
|
74
|
+
const { removeConnection } = await import("./manage-DGvJajD1.js");
|
|
75
75
|
process.exitCode = await withApi(o, (deps) => removeConnection(slug, deps));
|
|
76
76
|
});
|
|
77
77
|
dataOption(program.command("import", { hidden: false }).description("move an agent tool's MCP servers into xaq: one connection each, credentials moved into xaq").summary("import MCP servers from Hermes, Claude Code, Cursor or Codex").helpGroup(GROUP).requiredOption("--from <client>", "hermes, claude-code, cursor or codex")).option("--dry-run", "print exactly what would be created and changed, and change nothing").option("--access <level>", "for every imported connection: full, ask (the default) or read").option("--agent <name>", "an agent that gets them (repeatable; default: all agents; \"all\")", collect).option("--profile <name>", "the agent profile setup-mcp uses for the single xaq entry (default \"default\")").option("--allow-private <origin>", "allow this exact scheme://host:port on this machine or a private network without asking (repeatable; --yes never does)", collect).option("-y, --yes", "answer yes to the confirmations (scripts); never to a private-network allow or a project's .mcp.json servers").addHelpText("after", `
|
|
@@ -86,7 +86,7 @@ with the single xaq entry, after a timestamped backup. The entry keeps the name
|
|
|
86
86
|
Examples:
|
|
87
87
|
${NPX} import --from hermes --dry-run
|
|
88
88
|
${NPX} import --from hermes`).action(async (o) => {
|
|
89
|
-
const { runImport } = await import("./import-
|
|
89
|
+
const { runImport } = await import("./import-spafY6Qe.js");
|
|
90
90
|
const self = await selfOrigins(dataDirOf(o));
|
|
91
91
|
if (o.dryRun) {
|
|
92
92
|
const { TerminalPrompter } = await import("./prompt-CKMQx_MJ.js");
|
|
@@ -114,4 +114,4 @@ Examples:
|
|
|
114
114
|
//#endregion
|
|
115
115
|
export { registerConnectionsCommands };
|
|
116
116
|
|
|
117
|
-
//# sourceMappingURL=commands-
|
|
117
|
+
//# sourceMappingURL=commands-CU46puIx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands-CU46puIx.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(\"--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 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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"}
|
|
@@ -338,7 +338,7 @@ function printNextSteps(profileName, profile, tool, mcp, o = {}) {
|
|
|
338
338
|
} else {
|
|
339
339
|
out(` ${n++}. Wake ${label} when one of its connections needs it. First try it in the foreground (Ctrl-C stops it; --save keeps the command in the profile):`);
|
|
340
340
|
out(` ${pc.cyan(`${NPX} listen${p} --save ${target} --types approval.requested,connection.auth_failed,connection.expiring`)}`);
|
|
341
|
-
out(pc.gray(` Add an integration's own events too
|
|
341
|
+
out(pc.gray(` Add an integration's own events too (<extension>.<event>, if it emits any).`));
|
|
342
342
|
}
|
|
343
343
|
out(pc.gray(` What the woken agent can use: ${r.confinement}.`));
|
|
344
344
|
out(pc.gray(` Where its output goes: ${r.output}`));
|
|
@@ -359,4 +359,4 @@ function printNextSteps(profileName, profile, tool, mcp, o = {}) {
|
|
|
359
359
|
//#endregion
|
|
360
360
|
export { parseTool, printMcpResult, runConnect };
|
|
361
361
|
|
|
362
|
-
//# sourceMappingURL=connect-
|
|
362
|
+
//# sourceMappingURL=connect-DH58vE7-.js.map
|