xaq-cli 0.0.0 → 0.1.0-nightly.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -0
  3. package/dist/admin-5gThRwgj.js +162 -0
  4. package/dist/admin-5gThRwgj.js.map +1 -0
  5. package/dist/admin-Btrm8mCd.js +218 -0
  6. package/dist/admin-Btrm8mCd.js.map +1 -0
  7. package/dist/admin-CWofnT_Q.js +2 -0
  8. package/dist/api-BFpElwqK.js +89 -0
  9. package/dist/api-BFpElwqK.js.map +1 -0
  10. package/dist/audit-BB7jK9Z5.js +2 -0
  11. package/dist/audit-BVYknW2i.js +79 -0
  12. package/dist/audit-BVYknW2i.js.map +1 -0
  13. package/dist/auth-CXmBdMqw.js +2 -0
  14. package/dist/auth-D-GmwNv-.js +550 -0
  15. package/dist/auth-D-GmwNv-.js.map +1 -0
  16. package/dist/brand--ZB8jTn1.js +32 -0
  17. package/dist/brand--ZB8jTn1.js.map +1 -0
  18. package/dist/bus-Cz0flS37.js +12 -0
  19. package/dist/bus-Cz0flS37.js.map +1 -0
  20. package/dist/bus-OKIGut72.js +2 -0
  21. package/dist/cli.js +234 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/commands-BNVLjYXA.js +167 -0
  24. package/dist/commands-BNVLjYXA.js.map +1 -0
  25. package/dist/commands-CdA6-WE7.js +112 -0
  26. package/dist/commands-CdA6-WE7.js.map +1 -0
  27. package/dist/config-C9XmYZWO.js +94 -0
  28. package/dist/config-C9XmYZWO.js.map +1 -0
  29. package/dist/config-CNVi0v5t.js +2 -0
  30. package/dist/connect-TtJ9n0Rw.js +362 -0
  31. package/dist/connect-TtJ9n0Rw.js.map +1 -0
  32. package/dist/content-C1lKMxFS.js +1170 -0
  33. package/dist/content-C1lKMxFS.js.map +1 -0
  34. package/dist/content-worker.js +28 -0
  35. package/dist/content-worker.js.map +1 -0
  36. package/dist/crypto-fv2fj3S8.js +75 -0
  37. package/dist/crypto-fv2fj3S8.js.map +1 -0
  38. package/dist/db-BEUEUPyP.js +561 -0
  39. package/dist/db-BEUEUPyP.js.map +1 -0
  40. package/dist/db-Q5BQuwga.js +2 -0
  41. package/dist/errors-FbMS3QBo.js +39 -0
  42. package/dist/errors-FbMS3QBo.js.map +1 -0
  43. package/dist/filter-Ck6OMxvu.js +158 -0
  44. package/dist/filter-Ck6OMxvu.js.map +1 -0
  45. package/dist/hermes-CKyzt1mH.js +3 -0
  46. package/dist/hermes-DHnDTYJp.js +1023 -0
  47. package/dist/hermes-DHnDTYJp.js.map +1 -0
  48. package/dist/import-DsN5NZT3.js +910 -0
  49. package/dist/import-DsN5NZT3.js.map +1 -0
  50. package/dist/instance-CwWbFbJ8.js +2 -0
  51. package/dist/instance-Dj9TpJB2.js +195 -0
  52. package/dist/instance-Dj9TpJB2.js.map +1 -0
  53. package/dist/listen-B9iO7HgQ.js +1568 -0
  54. package/dist/listen-B9iO7HgQ.js.map +1 -0
  55. package/dist/listen-CXVKG9XD.js +2 -0
  56. package/dist/manage-Bo6COB4p.js +477 -0
  57. package/dist/manage-Bo6COB4p.js.map +1 -0
  58. package/dist/manage-DoXqvjnU.js +2 -0
  59. package/dist/mcpheader-B8c5YO1B.js +2 -0
  60. package/dist/mcpheader-C9H4vudu.js +185 -0
  61. package/dist/mcpheader-C9H4vudu.js.map +1 -0
  62. package/dist/mcpsetup-BnHudwpq.js +2 -0
  63. package/dist/mcpsetup-DXXo2qjf.js +1053 -0
  64. package/dist/mcpsetup-DXXo2qjf.js.map +1 -0
  65. package/dist/node-check-CjTk6VNL.js +24 -0
  66. package/dist/node-check-CjTk6VNL.js.map +1 -0
  67. package/dist/paths-d-C2kdjo.js +2 -0
  68. package/dist/paths-yzOKD6ow.js +46 -0
  69. package/dist/paths-yzOKD6ow.js.map +1 -0
  70. package/dist/profile-CcMZ4hn7.js +2 -0
  71. package/dist/profile-NmMKAczz.js +222 -0
  72. package/dist/profile-NmMKAczz.js.map +1 -0
  73. package/dist/prompt-CKMQx_MJ.js +114 -0
  74. package/dist/prompt-CKMQx_MJ.js.map +1 -0
  75. package/dist/recipes-C7TIDlRj.js +3 -0
  76. package/dist/recipes-DG_-doGq.js +314 -0
  77. package/dist/recipes-DG_-doGq.js.map +1 -0
  78. package/dist/send-Dk-t8ia-.js +108 -0
  79. package/dist/send-Dk-t8ia-.js.map +1 -0
  80. package/dist/server-CDqDp1q3.js +20640 -0
  81. package/dist/server-CDqDp1q3.js.map +1 -0
  82. package/dist/service-BVn3soZZ.js +766 -0
  83. package/dist/service-BVn3soZZ.js.map +1 -0
  84. package/dist/service-BaWGPmSd.js +2 -0
  85. package/dist/service-C7jfo-Ex.js +457 -0
  86. package/dist/service-C7jfo-Ex.js.map +1 -0
  87. package/dist/service-DxDyKDQ-.js +2 -0
  88. package/dist/settings-B5qSHxRM.js +134 -0
  89. package/dist/settings-B5qSHxRM.js.map +1 -0
  90. package/dist/settings-DQvZaMN1.js +2 -0
  91. package/dist/setup-token-CwuSzfLK.js +48 -0
  92. package/dist/setup-token-CwuSzfLK.js.map +1 -0
  93. package/dist/skill/SKILL.md +445 -0
  94. package/dist/skill-1UQj3qgW.js +69 -0
  95. package/dist/skill-1UQj3qgW.js.map +1 -0
  96. package/dist/skill-pelq18JQ.js +2 -0
  97. package/dist/ssrf-BlVpGZ7C.js +181 -0
  98. package/dist/ssrf-BlVpGZ7C.js.map +1 -0
  99. package/dist/types-BhJDbSzE.js +135 -0
  100. package/dist/types-BhJDbSzE.js.map +1 -0
  101. package/dist/ui-B8Sd4Y7Y.js +81 -0
  102. package/dist/ui-B8Sd4Y7Y.js.map +1 -0
  103. package/dist/urls-Dp8pBGMU.js +2 -0
  104. package/dist/urls-U_LfYV61.js +27 -0
  105. package/dist/urls-U_LfYV61.js.map +1 -0
  106. package/dist/version-BxH7OuWD.js +20 -0
  107. package/dist/version-BxH7OuWD.js.map +1 -0
  108. package/dist/web/assets/_agentId-DonOCOlC.js +1 -0
  109. package/dist/web/assets/_app-B7t5lEia.js +1 -0
  110. package/dist/web/assets/_app-DMTGqYpM.js +65 -0
  111. package/dist/web/assets/_connectionId-DR5vFXOg.js +1 -0
  112. package/dist/web/assets/_webhookId-LfUlsULp.js +1 -0
  113. package/dist/web/assets/account-status-CEszs13C.js +1 -0
  114. package/dist/web/assets/accounts-5m7aiXuZ.js +1 -0
  115. package/dist/web/assets/accounts-list-YfJzThZa.js +1 -0
  116. package/dist/web/assets/activity-DOIe7SAg.js +1 -0
  117. package/dist/web/assets/add-connection-C8JR-13R.js +1 -0
  118. package/dist/web/assets/agent-create-form-CPxnPYH4.js +1 -0
  119. package/dist/web/assets/agents-B2Qj5KxT.js +1 -0
  120. package/dist/web/assets/approvals-BGaVaoFy.js +1 -0
  121. package/dist/web/assets/approve._id-BLrQnzPM.js +1 -0
  122. package/dist/web/assets/arrow-left-DZVAXoKj.js +1 -0
  123. package/dist/web/assets/arrow-right-C2zcqRr2.js +1 -0
  124. package/dist/web/assets/attention-gO9Nw5uW.js +1 -0
  125. package/dist/web/assets/audit-BPXXre8S.js +1 -0
  126. package/dist/web/assets/audit-bits-CGyIprzK.js +1 -0
  127. package/dist/web/assets/bell-ring-ig3zn1iS.js +1 -0
  128. package/dist/web/assets/bot-Zk76q_39.js +1 -0
  129. package/dist/web/assets/calendar-notice-DsCfq3VJ.js +1 -0
  130. package/dist/web/assets/calendar-plus-Cycfkk0y.js +1 -0
  131. package/dist/web/assets/calendar-setup-Pn61Wj1n.js +2 -0
  132. package/dist/web/assets/card-GSO5o-Ug.js +1 -0
  133. package/dist/web/assets/check-check-Ds1bPIGv.js +1 -0
  134. package/dist/web/assets/checkbox-B937U-Fd.js +1 -0
  135. package/dist/web/assets/chevron-right-Cqh4mDk1.js +1 -0
  136. package/dist/web/assets/chips-input-2xWDofmE.js +1 -0
  137. package/dist/web/assets/choice-cards-CgAIqBGX.js +1 -0
  138. package/dist/web/assets/circle-x-DcU-0zVh.js +1 -0
  139. package/dist/web/assets/command-khhto70y.js +1 -0
  140. package/dist/web/assets/common-BPZV8TFb.js +1 -0
  141. package/dist/web/assets/connect-agent-guide-CJdw31p2.js +1 -0
  142. package/dist/web/assets/connect-host-lr2c3xWh.js +6 -0
  143. package/dist/web/assets/connection-row-DYx_5o0c.js +1 -0
  144. package/dist/web/assets/connections-C4NOFb5R.js +1 -0
  145. package/dist/web/assets/data-table-kW1pkRB5.js +1 -0
  146. package/dist/web/assets/empty-DzTDioBP.js +1 -0
  147. package/dist/web/assets/events-C9zJnPKK.js +1 -0
  148. package/dist/web/assets/eye-B9gT1QSq.js +1 -0
  149. package/dist/web/assets/eye-off-Diktqz_g.js +1 -0
  150. package/dist/web/assets/field-C6ejurju.js +1 -0
  151. package/dist/web/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  152. package/dist/web/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  153. package/dist/web/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  154. package/dist/web/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  155. package/dist/web/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
  156. package/dist/web/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
  157. package/dist/web/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
  158. package/dist/web/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
  159. package/dist/web/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
  160. package/dist/web/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
  161. package/dist/web/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  162. package/dist/web/assets/get-started-C38bq1gZ.js +2 -0
  163. package/dist/web/assets/hidden-chars-Dr9TxfvF.js +1 -0
  164. package/dist/web/assets/index-DGzo3kGh.js +11 -0
  165. package/dist/web/assets/index-zKOCQLGX.css +2 -0
  166. package/dist/web/assets/input-CWwJgozn.js +1 -0
  167. package/dist/web/assets/input-group-HG8OXcJ4.js +1 -0
  168. package/dist/web/assets/label-multi-select-sH8mllw8.js +1 -0
  169. package/dist/web/assets/labels-B5UqVwFo.js +1 -0
  170. package/dist/web/assets/laptop-BxJ4Nbj7.js +1 -0
  171. package/dist/web/assets/last-call-D-O5O94z.js +1 -0
  172. package/dist/web/assets/listener-handled-HNCuVrQ7.js +1 -0
  173. package/dist/web/assets/login-DaeKclcf.js +1 -0
  174. package/dist/web/assets/mail-C5fm2pTC.js +1 -0
  175. package/dist/web/assets/mcp-call-UoOTPFyh.js +1 -0
  176. package/dist/web/assets/mcp-call-card-Cr-OEDX2.js +3 -0
  177. package/dist/web/assets/message-square-quote-se8Bf3RP.js +1 -0
  178. package/dist/web/assets/mutations-CLPqJ6cj.js +1 -0
  179. package/dist/web/assets/network-igNw0VVx.js +1 -0
  180. package/dist/web/assets/pairing-XjuaVr2u.js +1 -0
  181. package/dist/web/assets/pairing-notifier-KPzOEZSO.js +1 -0
  182. package/dist/web/assets/paperclip-znS4iTrg.js +1 -0
  183. package/dist/web/assets/password-input-DV3aqcNf.js +1 -0
  184. package/dist/web/assets/pause-o-dK3khK.js +1 -0
  185. package/dist/web/assets/pencil-DkPFAhEq.js +1 -0
  186. package/dist/web/assets/play-DvCHND93.js +1 -0
  187. package/dist/web/assets/plug-CXAniEiR.js +1 -0
  188. package/dist/web/assets/plug-zap-BwR-l5wb.js +1 -0
  189. package/dist/web/assets/plus-B_TUslu3.js +1 -0
  190. package/dist/web/assets/preload-helper-Cc_aKyUb.js +1 -0
  191. package/dist/web/assets/public-url-rF2Xjyel.js +1 -0
  192. package/dist/web/assets/queries-Cv3nXx0U.js +42 -0
  193. package/dist/web/assets/refresh-cw-Ch5FNrby.js +1 -0
  194. package/dist/web/assets/revealed-keys-C_9NtJPY.js +1 -0
  195. package/dist/web/assets/rolldown-runtime-XKyaHtl9.js +1 -0
  196. package/dist/web/assets/rotate-ccw-B-mzPDk0.js +1 -0
  197. package/dist/web/assets/search-CTVKGomS.js +1 -0
  198. package/dist/web/assets/select-Bb806bpq.js +1 -0
  199. package/dist/web/assets/send-DuMVuYs1.js +1 -0
  200. package/dist/web/assets/settings-BWauhfFf.js +1 -0
  201. package/dist/web/assets/setup-B7bNKQOp.js +1 -0
  202. package/dist/web/assets/sheet-CYPwpUsH.js +1 -0
  203. package/dist/web/assets/shield-alert-CSYB-ThV.js +1 -0
  204. package/dist/web/assets/shield-check-BulpsYqK.js +1 -0
  205. package/dist/web/assets/sparkles-CUTiob4K.js +1 -0
  206. package/dist/web/assets/stamp-BNXUGNa3.js +1 -0
  207. package/dist/web/assets/step-url-51aMNak-.js +1 -0
  208. package/dist/web/assets/stream-Du7fY5_Y.js +1 -0
  209. package/dist/web/assets/tag-I5_-1jFL.js +1 -0
  210. package/dist/web/assets/terminal-BvxDFTJc.js +1 -0
  211. package/dist/web/assets/test-email-button-DYi7V_6X.js +1 -0
  212. package/dist/web/assets/toggle-group-Bdo1gmQ1.js +1 -0
  213. package/dist/web/assets/trash-Ci0aICEl.js +1 -0
  214. package/dist/web/assets/use-delivery-speed-BBh7W2q6.js +1 -0
  215. package/dist/web/assets/use-label-names-BXicesnP.js +1 -0
  216. package/dist/web/assets/use-sign-out-CPrY_oVO.js +1 -0
  217. package/dist/web/assets/useInfiniteQuery-DJLIM8yJ.js +1 -0
  218. package/dist/web/assets/useQuery-MrTwwNy5.js +1 -0
  219. package/dist/web/assets/useRouterState-D4OBK8l5.js +1 -0
  220. package/dist/web/assets/webhook-DjeeZiNC.js +1 -0
  221. package/dist/web/assets/webhook-bits-jw-y2D3u.js +1 -0
  222. package/dist/web/assets/webhook-sheet-B8h0skDe.js +34 -0
  223. package/dist/web/assets/webhooks-Cfsdpoyd.js +1 -0
  224. package/dist/web/assets/x-MF2TZ9aG.js +1 -0
  225. package/dist/web/favicon.svg +1 -0
  226. package/dist/web/index.html +27 -0
  227. package/package.json +98 -1
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+ import { n as nodeVersionError, t as MIN_NODE } from "./node-check-CjTk6VNL.js";
3
+ import { f as writePrivateFile, n as loadProfile, o as profileBrand } from "./profile-NmMKAczz.js";
4
+ import { c as profilePath, n as configDir, p as validProfileName } from "./paths-yzOKD6ow.js";
5
+ import { existsSync, realpathSync, statSync } from "node:fs";
6
+ import { dirname, join } from "node:path";
7
+ import { spawnSync } from "node:child_process";
8
+ //#region server/listen/mcpheader.ts
9
+ /**
10
+ * Keeps the API key out of argv and out of agent config files: Claude Code's `headersHelper` runs a
11
+ * command at connection time and uses the JSON it prints as request headers. The helper is a tiny
12
+ * dependency-free script next to the profiles (stable, unlike the npx cache) that reads the key from
13
+ * the 0600 profile and prints `{"Authorization":"Bearer …"}` to Claude Code's pipe, never a terminal.
14
+ */
15
+ const helperScriptPath = () => join(configDir(), "bin", "mcp-header.mjs");
16
+ /** The MCP config the Claude Code recipe loads with --strict-mcp-config (no key inside). */
17
+ const claudeMcpConfigPath = (profile) => join(configDir(), "mcp", `${validProfileName(profile)}.claude.json`);
18
+ /** POSIX single-quoting for the shell Claude Code runs the helper in. */
19
+ const sq = (s) => `'${s.replace(/'/g, `'"'"'`)}'`;
20
+ function helperScript(profilesDir) {
21
+ return `#!/usr/bin/env node
22
+ // xaq MCP header helper (written by \`xaq connect\` / \`setup-mcp\`). Prints the
23
+ // Authorization header for one xaq profile as JSON for Claude Code's headersHelper.
24
+ import { readFileSync } from "node:fs";
25
+ import { join } from "node:path";
26
+ const name = process.argv[2] || "default";
27
+ if (!/^[a-z0-9][a-z0-9_-]{0,39}$/.test(name)) { console.error("invalid profile name"); process.exit(2); }
28
+ if (process.stdout.isTTY) { console.error("This prints a secret header; it is meant to be piped to an MCP client."); process.exit(2); }
29
+ const profile = JSON.parse(readFileSync(join(${JSON.stringify(profilesDir)}, name + ".json"), "utf8"));
30
+ process.stdout.write(JSON.stringify({ Authorization: "Bearer " + profile.apiKey }));
31
+ `;
32
+ }
33
+ /** Node installs whose path names one version, so upgrading or removing that version breaks anything that recorded it. */
34
+ const VERSIONED_NODE = /\/\.?fnm\/node-versions\/|\/\.?nvm\/versions\/node\/|\/\.volta\/tools\/image\/node\/|\/\.asdf\/installs\/nodejs\/|\/mise\/installs\/node\/|\/n\/versions\/node\/|\/Cellar\/node(@\d+)?\//;
35
+ /** A node binary that runs and is new enough for the helper (ESM with node: imports). */
36
+ function worksAsNode(path) {
37
+ if (!existsSync(path)) return false;
38
+ const r = spawnSync(path, ["--version"], {
39
+ encoding: "utf8",
40
+ stdio: [
41
+ "ignore",
42
+ "pipe",
43
+ "ignore"
44
+ ],
45
+ timeout: 5e3
46
+ });
47
+ const major = /^v(\d+)\./.exec(r.stdout ?? "")?.[1];
48
+ return r.status === 0 && major !== void 0 && Number(major) >= 18;
49
+ }
50
+ /**
51
+ * The node to record for Claude Code's header helper. A version manager's node (fnm, nvm, Volta, asdf,
52
+ * mise, n, a Homebrew Cellar keg) disappears on upgrade, so prefer a path that stays put: the same
53
+ * Homebrew keg's opt/ link (then the prefix's bin/node), fnm's default alias, or a system node, but only
54
+ * when it exists and runs.
55
+ * Version-manager shims that pick a version per directory (asdf, mise, Volta) aren't used: Claude Code
56
+ * runs the helper in whatever project it's in. Otherwise the current node is kept (and reported).
57
+ */
58
+ function helperNode(execPath = process.execPath, works = worksAsNode) {
59
+ if (!VERSIONED_NODE.test(execPath)) return {
60
+ path: execPath,
61
+ versioned: false
62
+ };
63
+ const candidates = [];
64
+ const cellar = /^(.*)\/Cellar\/(node(?:@\d+)?)\//.exec(execPath);
65
+ if (cellar) candidates.push(join(cellar[1], "opt", cellar[2], "bin", "node"), join(cellar[1], "bin", "node"));
66
+ const fnm = /^(.*\/\.?fnm)\/node-versions\//.exec(execPath);
67
+ if (fnm) candidates.push(join(fnm[1], "aliases", "default", "bin", "node"));
68
+ candidates.push("/opt/homebrew/bin/node", "/usr/local/bin/node", "/usr/bin/node");
69
+ const stable = candidates.find((c) => c !== execPath && !VERSIONED_NODE.test(c) && works(c));
70
+ return stable ? {
71
+ path: stable,
72
+ versioned: false
73
+ } : {
74
+ path: execPath,
75
+ versioned: true
76
+ };
77
+ }
78
+ /** `node --version` of a binary ("22.20.0"), or null when it doesn't run. */
79
+ function nodeVersionOf(path) {
80
+ if (!existsSync(path)) return null;
81
+ const r = spawnSync(path, ["--version"], {
82
+ encoding: "utf8",
83
+ stdio: [
84
+ "ignore",
85
+ "pipe",
86
+ "ignore"
87
+ ],
88
+ timeout: 5e3
89
+ });
90
+ const v = /^v(\d+\.\d+\.\d+)/.exec(r.stdout ?? "")?.[1];
91
+ return r.status === 0 && v ? v : null;
92
+ }
93
+ /**
94
+ * A node binary the service may run: the real file, and every directory above both the path as given and
95
+ * the real file, are owned by root or by this user and not writable by group or others (a sticky
96
+ * directory such as /tmp excepted). Otherwise someone else could replace what the service runs at every login.
97
+ */
98
+ function trustedNodeFile(path, uid = process.getuid?.() ?? 0) {
99
+ const owned = (st) => st.uid === 0 || st.uid === uid;
100
+ const dirsOk = (p) => {
101
+ for (let d = dirname(p);; d = dirname(d)) {
102
+ const st = statSync(d);
103
+ if (!owned(st) || (st.mode & 18) !== 0 && (st.mode & 512) === 0) return false;
104
+ if (d === dirname(d)) return true;
105
+ }
106
+ };
107
+ try {
108
+ const real = realpathSync(path);
109
+ const st = statSync(real);
110
+ return owned(st) && (st.mode & 18) === 0 && dirsOk(path) && dirsOk(real);
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+ /**
116
+ * The node the listener service runs on: the same stable-path preference as the header helper (a path
117
+ * that survives fnm/nvm/Homebrew upgrades), but only a candidate that is trusted (trustedNodeFile) and new
118
+ * enough for xaq (MIN_NODE); else this shell's node, reported as version-specific.
119
+ */
120
+ function serviceNode(execPath = process.execPath, versionOf = nodeVersionOf, current = process.versions.node, trusted = trustedNodeFile) {
121
+ const versions = /* @__PURE__ */ new Map();
122
+ const okVersion = (p) => {
123
+ if (!trusted(p)) return false;
124
+ if (!versions.has(p)) versions.set(p, versionOf(p));
125
+ const v = versions.get(p);
126
+ return !!v && nodeVersionError(v) === null;
127
+ };
128
+ const choice = helperNode(execPath, okVersion);
129
+ if (choice.path !== execPath) return {
130
+ ...choice,
131
+ version: versions.get(choice.path),
132
+ why: `a stable path that survives fnm/nvm upgrades (this shell's is ${execPath}, v${current})`
133
+ };
134
+ return {
135
+ ...choice,
136
+ version: current,
137
+ why: choice.versioned ? `this shell's node; its path belongs to one Node version (no stable node ${MIN_NODE}+ found in the usual places), so re-run install after upgrading or removing it` : "this shell's node"
138
+ };
139
+ }
140
+ let chosenNode;
141
+ /** helperNode() for this process, computed once (it may run a candidate's --version). */
142
+ const helperNodeChoice = () => chosenNode ??= helperNode();
143
+ /** The shell command Claude Code runs as headersHelper (nothing is written). */
144
+ const headerHelperCommand = (profile) => `${sq(helperNodeChoice().path)} ${sq(helperScriptPath())} ${validProfileName(profile)}`;
145
+ /** The note setup-mcp prints about the recorded node (like `listen service install`'s Node.js line). */
146
+ function helperNodeNote(profile, rerun) {
147
+ const { path, versioned } = helperNodeChoice();
148
+ const v = path === process.execPath ? ` (v${process.versions.node})` : "";
149
+ return versioned ? `Node.js: Claude Code runs the header helper with ${path}${v}. That path belongs to one Node version: if you upgrade or remove it, run \`${rerun}\` again.` : `Node.js: Claude Code runs the header helper with ${path}${v}; if you remove it, run \`${rerun}\` again.`;
150
+ }
151
+ /** Writes (or refreshes) the helper script, 0700. Returns the shell command for headersHelper. */
152
+ function installHeaderHelper(profile) {
153
+ const command = headerHelperCommand(profile);
154
+ writePrivateFile(helperScriptPath(), helperScript(join(configDir(), "profiles")));
155
+ return command;
156
+ }
157
+ /** Claude Code MCP server entry: URL plus the helper, no secret. `install: false` (dry runs) doesn't write the helper. */
158
+ function claudeServerEntry(url, profile, opts = {}) {
159
+ return {
160
+ type: "http",
161
+ url,
162
+ headersHelper: opts.install === false ? headerHelperCommand(profile) : installHeaderHelper(profile)
163
+ };
164
+ }
165
+ /** Writes the per-profile MCP config the Claude Code listener recipe uses. Returns its path. */
166
+ function writeClaudeMcpConfig(profile, url) {
167
+ const path = claudeMcpConfigPath(profile);
168
+ writePrivateFile(path, JSON.stringify({ mcpServers: { [profileBrand(profile)]: claudeServerEntry(url, profile) } }, null, 2) + "\n");
169
+ return path;
170
+ }
171
+ /** `xaq mcp-header`: the header JSON for MCP clients that run a helper. Refuses to print to a terminal. */
172
+ function printMcpHeader(profile) {
173
+ const name = validProfileName(profile);
174
+ if (process.stdout.isTTY) {
175
+ process.stderr.write(`This prints the agent's secret Authorization header; pipe it into the tool that needs it (profile file: ${profilePath(name)}).\n`);
176
+ return 2;
177
+ }
178
+ const p = loadProfile(name);
179
+ process.stdout.write(JSON.stringify({ Authorization: `Bearer ${p.apiKey}` }));
180
+ return 0;
181
+ }
182
+ //#endregion
183
+ export { helperNodeChoice as a, helperScriptPath as c, printMcpHeader as d, serviceNode as f, helperNode as i, installHeaderHelper as l, writeClaudeMcpConfig as m, claudeServerEntry as n, helperNodeNote as o, trustedNodeFile as p, headerHelperCommand as r, helperScript as s, claudeMcpConfigPath as t, nodeVersionOf as u };
184
+
185
+ //# sourceMappingURL=mcpheader-C9H4vudu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpheader-C9H4vudu.js","names":[],"sources":["../server/listen/mcpheader.ts"],"sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { existsSync, realpathSync, statSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { MIN_NODE, nodeVersionError } from \"../node-check.ts\";\nimport { writePrivateFile } from \"./fsutil.ts\";\nimport { profileBrand } from \"./names.ts\";\nimport { configDir, profilePath, validProfileName } from \"./paths.ts\";\nimport { loadProfile } from \"./profile.ts\";\n\n/**\n * Keeps the API key out of argv and out of agent config files: Claude Code's `headersHelper` runs a\n * command at connection time and uses the JSON it prints as request headers. The helper is a tiny\n * dependency-free script next to the profiles (stable, unlike the npx cache) that reads the key from\n * the 0600 profile and prints `{\"Authorization\":\"Bearer …\"}` to Claude Code's pipe, never a terminal.\n */\n\nexport const helperScriptPath = () => join(configDir(), \"bin\", \"mcp-header.mjs\");\n/** The MCP config the Claude Code recipe loads with --strict-mcp-config (no key inside). */\nexport const claudeMcpConfigPath = (profile: string) => join(configDir(), \"mcp\", `${validProfileName(profile)}.claude.json`);\n\n/** POSIX single-quoting for the shell Claude Code runs the helper in. */\nconst sq = (s: string) => `'${s.replace(/'/g, `'\"'\"'`)}'`;\n\nexport function helperScript(profilesDir: string): string {\n return `#!/usr/bin/env node\n// xaq MCP header helper (written by \\`xaq connect\\` / \\`setup-mcp\\`). Prints the\n// Authorization header for one xaq profile as JSON for Claude Code's headersHelper.\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nconst name = process.argv[2] || \"default\";\nif (!/^[a-z0-9][a-z0-9_-]{0,39}$/.test(name)) { console.error(\"invalid profile name\"); process.exit(2); }\nif (process.stdout.isTTY) { console.error(\"This prints a secret header; it is meant to be piped to an MCP client.\"); process.exit(2); }\nconst profile = JSON.parse(readFileSync(join(${JSON.stringify(profilesDir)}, name + \".json\"), \"utf8\"));\nprocess.stdout.write(JSON.stringify({ Authorization: \"Bearer \" + profile.apiKey }));\n`;\n}\n\n/** Node installs whose path names one version, so upgrading or removing that version breaks anything that recorded it. */\nconst VERSIONED_NODE = /\\/\\.?fnm\\/node-versions\\/|\\/\\.?nvm\\/versions\\/node\\/|\\/\\.volta\\/tools\\/image\\/node\\/|\\/\\.asdf\\/installs\\/nodejs\\/|\\/mise\\/installs\\/node\\/|\\/n\\/versions\\/node\\/|\\/Cellar\\/node(@\\d+)?\\//;\n\nexport interface NodeChoice {\n /** The node binary recorded in the header helper command. */\n path: string;\n /** `path` is version-specific: replacing or removing that Node breaks the helper. */\n versioned: boolean;\n}\n\n/** A node binary that runs and is new enough for the helper (ESM with node: imports). */\nfunction worksAsNode(path: string): boolean {\n if (!existsSync(path)) return false;\n const r = spawnSync(path, [\"--version\"], { encoding: \"utf8\", stdio: [\"ignore\", \"pipe\", \"ignore\"], timeout: 5000 });\n const major = /^v(\\d+)\\./.exec(r.stdout ?? \"\")?.[1];\n return r.status === 0 && major !== undefined && Number(major) >= 18;\n}\n\n/**\n * The node to record for Claude Code's header helper. A version manager's node (fnm, nvm, Volta, asdf,\n * mise, n, a Homebrew Cellar keg) disappears on upgrade, so prefer a path that stays put: the same\n * Homebrew keg's opt/ link (then the prefix's bin/node), fnm's default alias, or a system node, but only\n * when it exists and runs.\n * Version-manager shims that pick a version per directory (asdf, mise, Volta) aren't used: Claude Code\n * runs the helper in whatever project it's in. Otherwise the current node is kept (and reported).\n */\nexport function helperNode(execPath = process.execPath, works: (path: string) => boolean = worksAsNode): NodeChoice {\n if (!VERSIONED_NODE.test(execPath)) return { path: execPath, versioned: false };\n const candidates: string[] = [];\n // Homebrew: <prefix>/opt/node@22 (or opt/node) follows the same formula across upgrades; bin/node may be another one.\n const cellar = /^(.*)\\/Cellar\\/(node(?:@\\d+)?)\\//.exec(execPath);\n if (cellar) candidates.push(join(cellar[1]!, \"opt\", cellar[2]!, \"bin\", \"node\"), join(cellar[1]!, \"bin\", \"node\"));\n // fnm: ~/.local/share/fnm (or the older ~/.fnm)/node-versions/… → <fnm dir>/aliases/default.\n const fnm = /^(.*\\/\\.?fnm)\\/node-versions\\//.exec(execPath);\n if (fnm) candidates.push(join(fnm[1]!, \"aliases\", \"default\", \"bin\", \"node\"));\n candidates.push(\"/opt/homebrew/bin/node\", \"/usr/local/bin/node\", \"/usr/bin/node\");\n const stable = candidates.find((c) => c !== execPath && !VERSIONED_NODE.test(c) && works(c));\n return stable ? { path: stable, versioned: false } : { path: execPath, versioned: true };\n}\n\n/** `node --version` of a binary (\"22.20.0\"), or null when it doesn't run. */\nexport function nodeVersionOf(path: string): string | null {\n if (!existsSync(path)) return null;\n const r = spawnSync(path, [\"--version\"], { encoding: \"utf8\", stdio: [\"ignore\", \"pipe\", \"ignore\"], timeout: 5000 });\n const v = /^v(\\d+\\.\\d+\\.\\d+)/.exec(r.stdout ?? \"\")?.[1];\n return r.status === 0 && v ? v : null;\n}\n\n/**\n * A node binary the service may run: the real file, and every directory above both the path as given and\n * the real file, are owned by root or by this user and not writable by group or others (a sticky\n * directory such as /tmp excepted). Otherwise someone else could replace what the service runs at every login.\n */\nexport function trustedNodeFile(path: string, uid = process.getuid?.() ?? 0): boolean {\n const owned = (st: { uid: number }) => st.uid === 0 || st.uid === uid;\n const dirsOk = (p: string) => {\n for (let d = dirname(p); ; d = dirname(d)) {\n const st = statSync(d);\n if (!owned(st) || ((st.mode & 0o022) !== 0 && (st.mode & 0o1000) === 0)) return false;\n if (d === dirname(d)) return true;\n }\n };\n try {\n const real = realpathSync(path);\n const st = statSync(real);\n return owned(st) && (st.mode & 0o022) === 0 && dirsOk(path) && dirsOk(real);\n } catch {\n return false;\n }\n}\n\nexport interface ServiceNodeChoice extends NodeChoice {\n version: string;\n /** Why this node, in words (printed by `listen service install`). */\n why: string;\n}\n\n/**\n * The node the listener service runs on: the same stable-path preference as the header helper (a path\n * that survives fnm/nvm/Homebrew upgrades), but only a candidate that is trusted (trustedNodeFile) and new\n * enough for xaq (MIN_NODE); else this shell's node, reported as version-specific.\n */\nexport function serviceNode(\n execPath = process.execPath,\n versionOf: (path: string) => string | null = nodeVersionOf,\n current = process.versions.node,\n trusted: (path: string) => boolean = trustedNodeFile,\n): ServiceNodeChoice {\n const versions = new Map<string, string | null>();\n const okVersion = (p: string) => {\n if (!trusted(p)) return false;\n if (!versions.has(p)) versions.set(p, versionOf(p));\n const v = versions.get(p);\n return !!v && nodeVersionError(v) === null;\n };\n const choice = helperNode(execPath, okVersion);\n if (choice.path !== execPath) {\n return { ...choice, version: versions.get(choice.path)!, why: `a stable path that survives fnm/nvm upgrades (this shell's is ${execPath}, v${current})` };\n }\n return {\n ...choice,\n version: current,\n why: choice.versioned\n ? `this shell's node; its path belongs to one Node version (no stable node ${MIN_NODE}+ found in the usual places), so re-run install after upgrading or removing it`\n : \"this shell's node\",\n };\n}\n\nlet chosenNode: NodeChoice | undefined;\n/** helperNode() for this process, computed once (it may run a candidate's --version). */\nexport const helperNodeChoice = (): NodeChoice => (chosenNode ??= helperNode());\n\n/** The shell command Claude Code runs as headersHelper (nothing is written). */\nexport const headerHelperCommand = (profile: string) => `${sq(helperNodeChoice().path)} ${sq(helperScriptPath())} ${validProfileName(profile)}`;\n\n/** The note setup-mcp prints about the recorded node (like `listen service install`'s Node.js line). */\nexport function helperNodeNote(profile: string, rerun: string): string {\n const { path, versioned } = helperNodeChoice();\n const v = path === process.execPath ? ` (v${process.versions.node})` : \"\";\n return versioned\n ? `Node.js: Claude Code runs the header helper with ${path}${v}. That path belongs to one Node version: if you upgrade or remove it, run \\`${rerun}\\` again.`\n : `Node.js: Claude Code runs the header helper with ${path}${v}; if you remove it, run \\`${rerun}\\` again.`;\n}\n\n/** Writes (or refreshes) the helper script, 0700. Returns the shell command for headersHelper. */\nexport function installHeaderHelper(profile: string): string {\n const command = headerHelperCommand(profile);\n writePrivateFile(helperScriptPath(), helperScript(join(configDir(), \"profiles\")));\n // writePrivateFile leaves 0600; the script itself is run through node, so it needn't be executable.\n return command;\n}\n\n/** Claude Code MCP server entry: URL plus the helper, no secret. `install: false` (dry runs) doesn't write the helper. */\nexport function claudeServerEntry(url: string, profile: string, opts: { install?: boolean } = {}): { type: \"http\"; url: string; headersHelper: string } {\n return { type: \"http\", url, headersHelper: opts.install === false ? headerHelperCommand(profile) : installHeaderHelper(profile) };\n}\n\n/** Writes the per-profile MCP config the Claude Code listener recipe uses. Returns its path. */\nexport function writeClaudeMcpConfig(profile: string, url: string): string {\n const path = claudeMcpConfigPath(profile);\n // The recipe allows exactly `mcp__<brand>`, so the server is always named that in this file: xaq, or\n // agentinbox for a profile from before the rename, whose saved recipe allows `mcp__agentinbox`.\n writePrivateFile(path, JSON.stringify({ mcpServers: { [profileBrand(profile)]: claudeServerEntry(url, profile) } }, null, 2) + \"\\n\");\n return path;\n}\n\n/** `xaq mcp-header`: the header JSON for MCP clients that run a helper. Refuses to print to a terminal. */\nexport function printMcpHeader(profile: string): number {\n const name = validProfileName(profile);\n if (process.stdout.isTTY) {\n process.stderr.write(`This prints the agent's secret Authorization header; pipe it into the tool that needs it (profile file: ${profilePath(name)}).\\n`);\n return 2;\n }\n const p = loadProfile(name);\n process.stdout.write(JSON.stringify({ Authorization: `Bearer ${p.apiKey}` }));\n return 0;\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export { c as mcpTarget, u as setupMcp } from "./mcpsetup-DXXo2qjf.js";