xaq-cli 0.0.0 → 0.1.0-nightly.72

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 @@
1
+ {"version":3,"file":"service-C7jfo-Ex.js","names":[],"sources":["../server/listen/service.ts"],"sourcesContent":["import { existsSync, mkdirSync, readdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { delimiter, dirname, join } from \"node:path\";\nimport pc from \"picocolors\";\nimport { envVar, LEGACY_PRODUCT, PRODUCT } from \"../brand.ts\";\nimport {\n assertSupported,\n bootstrapLaunchd,\n commandFailure,\n enableLinger,\n installedEntry,\n launchdTarget,\n LEGACY_PACKAGE,\n preflight,\n readText,\n removeOwnInstall,\n restoreUnit,\n sdQuote,\n serviceMainPid,\n type ServiceOps,\n stagePackage,\n stopAndWait,\n swapIn,\n systemctl,\n systemOps,\n type UnitId,\n unitPath,\n unitState,\n xmlEscape,\n} from \"../service.ts\";\nimport { ensurePrivateDir } from \"./fsutil.ts\";\nimport { EXIT } from \"./listen.ts\";\nimport { acquireFileLock } from \"./lock.ts\";\nimport { type ListenFlags, resolveListen } from \"./options.ts\";\nimport { serviceNode, type ServiceNodeChoice } from \"./mcpheader.ts\";\nimport { DEFAULT_PROFILE, dataDir, listenAppDir, logPath, profilePath, profileStateDir, validProfileName } from \"./paths.ts\";\nimport { gatewayWarning } from \"./hermes.ts\";\nimport { hermesChangeNote, isHermesRoute, RECIPE_NAMES } from \"./recipes.ts\";\nimport { loadProfile, saveProfile } from \"./profile.ts\";\nimport { pidAlive, readStatus } from \"./state.ts\";\nimport { checkTransport } from \"./transport.ts\";\nimport { NPX } from \"./version.ts\";\n\n/**\n * `xaq listen service install|uninstall|status`: one systemd user unit / launchd agent per\n * profile, running from a stable install (not the npx cache). The unit only says which profile to\n * run; settings and the key stay in the 0600 profile file. Installation reuses the daemon's\n * machinery (server/service.ts): systemd pre-check, the user manager's unit directory, staging into\n * app.new and swapping in, rollback when the new listener doesn't start.\n *\n * A listener installed before the rename (agentinbox-listen-<profile> / com.unlaboredlabs.agentinbox.listen.<profile>)\n * is replaced by `install` for its profile: stopped and waited for before the new one starts (one listener\n * per profile, never two), and put back exactly as it was if the new one fails. `status` and\n * `uninstall` find either name.\n */\n\nexport const unitName = (profile: string) => `${PRODUCT}-listen-${profile}`;\nexport const launchdLabel = (profile: string) => `sh.xaq.listen.${profile}`;\n/** The names before the rename. */\nexport const legacyUnitName = (profile: string) => `${LEGACY_PRODUCT}-listen-${profile}`;\nexport const legacyLaunchdLabel = (profile: string) => `com.unlaboredlabs.agentinbox.listen.${profile}`;\n\nexport const listenUnit = (profile: string): UnitId => ({ launchd: launchdLabel(profile), systemd: unitName(profile) });\nexport const legacyListenUnit = (profile: string): UnitId => ({ launchd: legacyLaunchdLabel(profile), systemd: legacyUnitName(profile) });\n\n/**\n * PATH for the service: this shell's PATH (so `claude`, `codex`… resolve as they do here) minus\n * transient entries npx, npm scripts and version-manager shells add, plus node's own directory.\n */\nexport function servicePath(raw = process.env.PATH ?? \"\", node = process.execPath): string {\n const transient = /\\/_npx\\/|node_modules\\/\\.bin|node-gyp-bin|fnm_multishells|\\/\\.pnpm\\//;\n // This shell's node first (global npm tools such as `claude` live next to it), then the service's own.\n const dirs = [dirname(process.execPath), dirname(node), ...raw.split(delimiter)].filter((d) => d && d.startsWith(\"/\") && !transient.test(d));\n if (!dirs.includes(\"/usr/bin\")) dirs.push(\"/usr/local/bin\", \"/usr/bin\", \"/bin\");\n return [...new Set(dirs)].join(delimiter);\n}\n\n/** Environment the service needs to behave like the shell `service install` ran in. Never contains the key. */\nexport function serviceEnvironment(node = process.execPath): Record<string, string> {\n const env: Record<string, string> = { XAQ_SERVICE: \"1\" };\n // PATH matters most: `claude`, `codex`, `hermes`… usually live in ~/.local/bin, nvm or Homebrew dirs\n // that a service manager's minimal PATH doesn't include.\n env.PATH = servicePath(undefined, node);\n for (const key of [\"XDG_CONFIG_HOME\", \"XDG_STATE_HOME\", \"XDG_DATA_HOME\", \"CLAUDE_CONFIG_DIR\", \"CODEX_HOME\", \"HERMES_HOME\", \"LANG\"]) {\n if (process.env[key]) env[key] = process.env[key]!;\n }\n const debug = envVar(\"DEBUG\");\n if (debug) env.XAQ_DEBUG = debug;\n return env;\n}\n\nexport function systemdListenUnit(profile: string, entry: string, cwd: string, system = false, node = process.execPath): string {\n const vars = Object.entries(serviceEnvironment(node))\n .map(([k, v]) => `Environment=${sdQuote(`${k}=${v}`)}`)\n .join(\"\\n\");\n return `[Unit]\nDescription=xaq listener (profile ${profile})${system ? \"\\nAfter=network-online.target\\nWants=network-online.target\" : \"\"}\nStartLimitIntervalSec=0\n\n[Service]\nExecStart=${sdQuote(node)} ${sdQuote(entry)} listen --profile ${profile}\nWorkingDirectory=${cwd.replace(/%/g, \"%%\")}\n${vars}\nRestart=on-failure\nRestartSec=10\nRestartSteps=6\nRestartMaxDelaySec=600\n# ${EXIT.revoked}: the key was revoked or the config is invalid. Restarting can't fix that.\nRestartPreventExitStatus=${EXIT.revoked}\nTimeoutStopSec=20\n\n[Install]\nWantedBy=${system ? \"multi-user.target\" : \"default.target\"}\n`;\n}\n\nexport function launchdListenPlist(profile: string, entry: string, cwd: string, node = process.execPath): string {\n const esc = xmlEscape;\n const vars = Object.entries(serviceEnvironment(node))\n .map(([k, v]) => ` <key>${esc(k)}</key><string>${esc(v)}</string>`)\n .join(\"\\n\");\n // The listener logs to the rotated listen.log and stays quiet on the console under launchd; only\n // crashes reach stderr, so this file stays small.\n const errLog = esc(join(profileStateDir(profile), \"service-stderr.log\"));\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key><string>${esc(launchdLabel(profile))}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${esc(node)}</string>\n <string>${esc(entry)}</string>\n <string>listen</string>\n <string>--profile</string>\n <string>${esc(profile)}</string>\n </array>\n <key>WorkingDirectory</key><string>${esc(cwd)}</string>\n <key>EnvironmentVariables</key>\n <dict>\n${vars}\n </dict>\n <key>RunAtLoad</key><true/>\n <key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>\n <key>ThrottleInterval</key><integer>10</integer>\n <key>StandardOutPath</key><string>/dev/null</string>\n <key>StandardErrorPath</key><string>${errLog}</string>\n</dict>\n</plist>\n`;\n}\n\nconst unitFile = (ops: ServiceOps, profile: string) => unitPath(ops, listenUnit(profile));\nconst label = (ops: Pick<ServiceOps, \"platform\">, id: UnitId) => (ops.platform === \"linux\" ? id.systemd : id.launchd);\n\n/** Listener profiles with a unit file under the new names, or (`legacy`) under the names from before the rename. */\nfunction profilesWithUnits(ops: ServiceOps, legacy: boolean): string[] {\n const dir = ops.unitDir();\n if (!existsSync(dir)) return [];\n const re =\n ops.platform === \"darwin\"\n ? legacy\n ? /^com\\.unlaboredlabs\\.agentinbox\\.listen\\.(.+)\\.plist$/\n : /^sh\\.xaq\\.listen\\.(.+)\\.plist$/\n : legacy\n ? /^agentinbox-listen-(.+)\\.service$/\n : /^xaq-listen-(.+)\\.service$/;\n return readdirSync(dir)\n .map((f) => re.exec(f)?.[1])\n .filter((p): p is string => !!p);\n}\n\n/** Installed listener profiles (from the unit directory), under either name. */\nfunction installedProfiles(ops: ServiceOps): string[] {\n return [...new Set([...profilesWithUnits(ops, false), ...profilesWithUnits(ops, true)])];\n}\n\n/** The profile's installed listener service: the new one, else one from before the rename; null when neither. */\nexport function installedListenUnit(profile: string, ops: ServiceOps = systemOps()): { id: UnitId; file: string; legacy: boolean } | null {\n if (ops.platform !== \"linux\" && ops.platform !== \"darwin\") return null;\n try {\n for (const [id, legacy] of [\n [listenUnit(profile), false],\n [legacyListenUnit(profile), true],\n ] as const) {\n const file = unitPath(ops, id);\n if (existsSync(file)) return { id, file, legacy };\n }\n } catch {\n // No unit directory to look in.\n }\n return null;\n}\n\nexport function isServiceInstalled(profile: string, ops: ServiceOps = systemOps()): boolean {\n return installedListenUnit(profile, ops) !== null;\n}\n\n/** The service's name as the platform knows it (for status lines), under whichever name it is installed. */\nexport const installedServiceLabel = (profile: string, ops: ServiceOps = systemOps()): string | null => {\n const u = installedListenUnit(profile, ops);\n return u ? label(ops, u.id) : null;\n};\n\nfunction listenerHints(ops: ServiceOps, profile: string, id: UnitId = listenUnit(profile)): string[] {\n if (ops.platform === \"darwin\") return [`launchctl print ${launchdTarget(ops)}/${id.launchd}`, `the log ${logPath(profile)}`];\n const scope = ops.root ? \"\" : \" --user\";\n return [`systemctl${scope} status ${id.systemd}`, `journalctl${scope} -u ${id.systemd} -e`, `the log ${logPath(profile)}`];\n}\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\n/**\n * The pid of a listener started after `since` for the profile (it writes status.json on start), once it\n * has stayed up for a moment; null if none did within the timeout, or it stopped again.\n */\nexport async function waitListenerStarted(profile: string, since: number, timeoutMs = 20_000): Promise<number | null> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const st = readStatus(profile);\n if (st && Date.parse(st.startedAt) >= since - 1000) {\n if (st.stoppedAt) return null;\n if (pidAlive(st.pid)) {\n // A listener that exits at once (bad settings, revoked key) must not count as started.\n await sleep(1000);\n const again = readStatus(profile);\n return again?.pid === st.pid && !again.stoppedAt && pidAlive(st.pid) ? st.pid : null;\n }\n }\n await sleep(250);\n }\n return null;\n}\n\nconst why = commandFailure;\n\n/** What the service manager says about the profile's listener (under `id`'s names): running (with its pid), or why not. */\nexport function managerState(ops: ServiceOps, profile: string, id: UnitId = listenUnit(profile)): { running: boolean; pid: number | null; detail: string } {\n const pid = serviceMainPid(ops, id);\n if (ops.platform === \"darwin\") {\n let text: string;\n try {\n text = ops.capture(\"launchctl\", [\"print\", `${launchdTarget(ops)}/${id.launchd}`]);\n } catch (err) {\n return { running: false, pid: null, detail: `launchctl print: ${why(err)}` };\n }\n const state = /^\\s*state = (\\S+)/m.exec(text)?.[1] ?? \"unknown\";\n return { running: state === \"running\" && pid !== null, pid, detail: `launchd state ${state}${pid ? `, pid ${pid}` : \"\"}` };\n }\n let active: string;\n try {\n active = ops.capture(\"systemctl\", [...(ops.root ? [] : [\"--user\"]), \"is-active\", id.systemd]).trim();\n } catch (err) {\n active = String((err as { stdout?: unknown })?.stdout ?? \"\").trim() || why(err);\n }\n return { running: active === \"active\" && pid !== null, pid, detail: `systemd ${active || \"unknown\"}${pid ? `, MainPID ${pid}` : \"\"}` };\n}\n\n/** (Re)starts the profile's unit with the file just written (launchd: see bootstrapLaunchd). */\nasync function startUnit(ops: ServiceOps, profile: string, file: string, pollMs = 250): Promise<void> {\n if (ops.platform === \"linux\") {\n systemctl(ops, \"daemon-reload\");\n systemctl(ops, \"enable\", unitName(profile));\n // restart, not start: a re-install must pick up the new install and settings.\n systemctl(ops, \"restart\", unitName(profile));\n return;\n }\n await bootstrapLaunchd(ops, launchdLabel(profile), file, { pollMs });\n}\n\n/** Stops and removes one unit (no waiting: for uninstall and for undoing a new unit that never ran). */\nfunction removeUnit(ops: ServiceOps, id: UnitId, file: string): void {\n if (ops.platform === \"linux\") {\n try {\n systemctl(ops, \"disable\", \"--now\", id.systemd);\n } catch {\n // Already stopped.\n }\n rmSync(file);\n systemctl(ops, \"daemon-reload\");\n } else {\n try {\n ops.exec(\"launchctl\", [\"bootout\", `${launchdTarget(ops)}/${id.launchd}`], { quiet: true });\n } catch {\n // Not loaded.\n }\n rmSync(file);\n }\n}\n\n/**\n * Listener units from before the rename start `<app>/node_modules/agentinbox-cli/dist/cli.js`. While some\n * still run from this shared install (other profiles not moved yet), it keeps that path working: a tiny\n * module there runs xaq-cli, so those listeners run the new version under their old names until\n * `listen service install --profile <name>` moves them too.\n */\nexport function writeLegacyEntry(app: string): void {\n const dir = join(app, \"node_modules\", LEGACY_PACKAGE);\n mkdirSync(join(dir, \"dist\"), { recursive: true });\n writeFileSync(join(dir, \"package.json\"), `${JSON.stringify({ name: LEGACY_PACKAGE, private: true, type: \"module\", description: \"Runs xaq-cli for listener services installed before the rename.\" }, null, 2)}\\n`);\n writeFileSync(join(dir, \"dist\", \"cli.js\"), `// Listener services installed as agentinbox still start this path: run xaq-cli.\\nimport \"../../xaq-cli/dist/cli.js\";\\n`);\n}\n\n/** Stages the listeners' install (no web console needed). */\nexport const stageListenerApp = (staging: string): string => stagePackage(staging, { where: dirname(staging), requireWeb: false });\n\nexport interface ListenServiceDeps {\n ops?: ServiceOps;\n /** Installs the package into the given staging dir (tests). */\n stage?: (staging: string) => string;\n /** Readiness check after (re)starting the unit: the new listener's pid (tests). */\n waitStarted?: (profile: string, since: number) => Promise<number | null>;\n /** The node the unit runs (tests). */\n node?: ServiceNodeChoice;\n /** launchd polling interval (tests). */\n pollMs?: number;\n /** Probes the Hermes gateway (tests). */\n gatewayCheck?: (url: string) => Promise<string | null>;\n}\n\nexport async function installListenService(flags: ListenFlags, deps: ListenServiceDeps = {}): Promise<void> {\n const ops = deps.ops ?? systemOps();\n assertSupported(ops);\n const profileName = validProfileName(flags.profile ?? DEFAULT_PROFILE);\n const profile = loadProfile(profileName);\n // Service settings live in the profile: save whatever was passed with this command.\n const { config, next } = resolveListen(profileName, profile, { ...flags, save: true });\n if (!config.exec && !config.forward) {\n throw new Error(`Nothing for the service to run. Pass --recipe <name> (${RECIPE_NAMES.join(\", \")}), --exec \"<command>\" and/or --forward <url> (they are saved to profile \"${profileName}\").`);\n }\n await checkTransport(next.url, { insecure: config.insecure });\n preflight(ops);\n const shared = dataDir();\n // A daemon started with --data pointing here would share (and lose) its app/ install with us.\n const daemonDb = [`${PRODUCT}.db`, `${LEGACY_PRODUCT}.db`].find((f) => existsSync(join(shared, f)));\n if (daemonDb) {\n throw new Error(`${shared} holds a xaq daemon's data (${daemonDb}), so the listener can't install there. Run the daemon with another --data directory, or set XDG_DATA_HOME for the listener.`);\n }\n\n const p = profileName === DEFAULT_PROFILE ? \"\" : ` --profile ${profileName}`;\n const node = deps.node ?? serviceNode();\n let runningPid = 0;\n let replacedLegacy = false;\n // Commands run in config.cwd (a private dir unless --cwd was given); the unit uses it too.\n const cwd = config.cwd;\n mkdirSync(profileStateDir(profileName), { recursive: true, mode: 0o700 });\n if (config.cwdIsDefault) ensurePrivateDir(cwd);\n\n // The same install path as the daemon (stage into app.new, swap into app), under a lock: all\n // profiles share this install, so two installs at once would trip over app.new / app.old.\n mkdirSync(shared, { recursive: true, mode: 0o700 });\n const releaseInstallLock = acquireFileLock(\n join(shared, \"install.lock\"),\n (holder) => new Error(`Another listener service install is running (pid ${holder.pid}, since ${holder.startedAt}). Try again when it has finished.`),\n );\n try {\n await installLocked();\n } finally {\n releaseInstallLock();\n }\n\n async function installLocked(): Promise<void> {\n const staging = (deps.stage ?? stageListenerApp)(join(shared, \"app.new\"));\n // Saved only once the new version is staged: a failed npm install changes nothing.\n saveProfile(profileName, next);\n const app = listenAppDir();\n const entry = installedEntry(app);\n const file = unitFile(ops, profileName);\n const previousUnit = readText(file);\n // This profile's listener from before the rename, if any: replaced, or put back on failure.\n const legacyId = legacyListenUnit(profileName);\n const legacyFile = unitPath(ops, legacyId);\n const legacyText = readText(legacyFile);\n const legacyState = legacyText !== null ? unitState(ops, legacyId) : null;\n let legacyStopped = false;\n // Other profiles' pre-rename units that run from this same install must keep a working entry point.\n const legacyEntry = join(app, \"node_modules\", LEGACY_PACKAGE);\n const othersOnLegacy = profilesWithUnits(ops, true).filter((o) => o !== profileName && (readText(unitPath(ops, legacyListenUnit(o))) ?? \"\").includes(legacyEntry));\n if (othersOnLegacy.length) writeLegacyEntry(staging);\n const since = Date.now();\n let swap: ReturnType<typeof swapIn> | null = null;\n try {\n swap = swapIn(staging, app);\n mkdirSync(ops.unitDir(), { recursive: true });\n if (ops.platform === \"linux\") writeFileSync(file, systemdListenUnit(profileName, entry, cwd, ops.root, node.path));\n else writeFileSync(file, launchdListenPlist(profileName, entry, cwd, node.path), { mode: 0o600 });\n if (legacyText !== null) {\n // One listener per profile: the old one is gone (launchd: unloaded) before the new one starts.\n legacyStopped = true;\n await stopAndWait(ops, legacyId, { pollMs: deps.pollMs });\n rmSync(legacyFile, { force: true });\n }\n await startUnit(ops, profileName, file, deps.pollMs);\n const pid = await (deps.waitStarted ?? waitListenerStarted)(profileName, since);\n if (!pid) throw new Error(\"the listener did not start\");\n // Only a listener the service manager itself runs counts: not an older job still loaded, nor a\n // foreground one (the profile lock keeps those apart, so a pid match means it is ours).\n const svc = managerState(ops, profileName);\n if (!svc.running) throw new Error(`the service manager doesn't report it running (${svc.detail})`);\n if (svc.pid !== pid) throw new Error(`the listener that started (pid ${pid}) isn't the service's process (${svc.detail})`);\n runningPid = pid;\n replacedLegacy = legacyText !== null;\n } catch (err) {\n // Best effort, but reported as it went: never claim a rollback that didn't happen.\n const failed: string[] = [];\n const step = (what: string, fn: () => void) => {\n try {\n fn();\n } catch (e) {\n failed.push(`${what}: ${why(e)}`);\n }\n };\n if (swap) step(\"restoring the previous install\", () => swap!.restore());\n // The settings this install saved go back too, so the restored listener runs as before.\n step(\"restoring the profile's settings\", () => saveProfile(profileName, profile));\n step(\"removing the staged install\", () => rmSync(staging, { recursive: true, force: true }));\n let outcome: string;\n if (previousUnit !== null) {\n step(\"restoring the previous unit file\", () => writeFileSync(file, previousUnit, { mode: ops.platform === \"darwin\" ? 0o600 : 0o644 }));\n const restarted = await startUnit(ops, profileName, file, deps.pollMs).then(\n () => null,\n (e: unknown) => why(e),\n );\n const svc = restarted ? null : managerState(ops, profileName);\n outcome = restarted\n ? `Put the previous install back, but restarting it failed (${restarted}), so no listener service is running now`\n : svc!.running\n ? `Put the previous install back; it is running again (${svc!.detail})`\n : `Put the previous install back and started it, but the service manager doesn't report it running (${svc!.detail})`;\n } else {\n // Before the old listener comes back, the new one must be gone (launchd tears it down asynchronously).\n if (legacyStopped) await stopAndWait(ops, listenUnit(profileName), { pollMs: deps.pollMs }).catch((e: unknown) => failed.push(`stopping the new service: ${why(e)}`));\n step(\"removing the new service\", () => {\n if (existsSync(file)) removeUnit(ops, listenUnit(profileName), file);\n });\n outcome = legacyText !== null ? \"Removed the new service again\" : \"Removed the new service again (no listener service is installed)\";\n }\n if (legacyText !== null && legacyStopped) {\n // The pre-rename listener comes back under its own name, running (and enabled) only if it was before.\n const restored = await restoreUnit(ops, legacyId, legacyFile, legacyText, legacyState!, deps.pollMs).then(\n () => null,\n (e: unknown) => why(e),\n );\n const svc = restored || !legacyState!.running ? null : managerState(ops, profileName, legacyId);\n outcome += restored\n ? `. Putting the ${LEGACY_PRODUCT} listener (${label(ops, legacyId)}) back failed (${restored})`\n : svc\n ? `. Put the ${LEGACY_PRODUCT} listener (${label(ops, legacyId)}) back${svc.running ? `; it is running again (${svc.detail})` : `, but the service manager doesn't report it running (${svc.detail})`}`\n : `. Put the ${LEGACY_PRODUCT} listener (${label(ops, legacyId)}) back, stopped as it was`;\n } else if (legacyText !== null) {\n outcome += `. The ${LEGACY_PRODUCT} listener (${label(ops, legacyId)}) was left as it was`;\n }\n if (failed.length) outcome += `. These rollback steps failed too: ${failed.join(\"; \")}`;\n const hints = listenerHints(ops, profileName, legacyText !== null && previousUnit === null ? legacyId : listenUnit(profileName))\n .map((h) => ` ${h}`)\n .join(\"\\n\");\n throw new Error(`Starting the listener service failed (${why(err)}). ${outcome}.\\n To find out why:\\n${hints}`);\n }\n swap.commit();\n enableLinger(ops);\n // The other profiles' listeners share the install: move them onto the new one (whichever name they run under).\n for (const other of profilesWithUnits(ops, false).filter((o) => o !== profileName)) restartOther(listenUnit(other));\n for (const other of othersOnLegacy) restartOther(legacyListenUnit(other));\n if (othersOnLegacy.length) {\n const list = othersOnLegacy.map((o) => `${o} (\\`${NPX} listen service install --profile ${o}\\`)`).join(\", \");\n console.log(`\\n ${pc.yellow(\"!\")} Still under their ${LEGACY_PRODUCT} service names (running this version): ${list}. Run those to move them to xaq too.`);\n }\n }\n\n function restartOther(id: UnitId): void {\n try {\n if (ops.platform === \"linux\") systemctl(ops, \"try-restart\", id.systemd);\n else ops.exec(\"launchctl\", [\"kickstart\", \"-k\", `${launchdTarget(ops)}/${id.launchd}`], { quiet: true });\n } catch {\n // Not running: nothing to restart.\n }\n }\n\n const kind = ops.platform === \"linux\" ? (ops.root ? \"systemd system service\" : \"systemd user service\") : \"launchd agent\";\n console.log(\n `\\n ${pc.green(\"✔\")} Installed the listener for profile \"${profileName}\" as a ${kind} (${label(ops, listenUnit(profileName))}); it is running as pid ${runningPid}.`,\n );\n if (replacedLegacy) console.log(` Replaced: the ${LEGACY_PRODUCT} listener service ${label(ops, legacyListenUnit(profileName))} (removed; the profile, its key and its cursor are unchanged)`);\n console.log(` Runs: ${config.exec ? `--exec ${config.exec}` : \"\"}${config.exec && config.forward ? \" and \" : \"\"}${config.forward ? `--forward ${config.forward.url}` : \"\"}`);\n console.log(` Directory: ${cwd}${config.cwdIsDefault ? \" (private; pass --cwd to run in a project)\" : \"\"}`);\n console.log(` Node.js: ${node.path} (v${node.version}): ${node.why}. If you remove it, run \\`${NPX} listen service install${p}\\` again.`);\n console.log(` Settings: ${profilePath(profileName)} (change them with \\`${NPX} listen${p} … --save\\`, then reinstall)`);\n console.log(` Log: ${logPath(profileName)}`);\n const change = hermesChangeNote(flags.recipe, config.exec);\n if (change) console.log(` Note: ${change}`);\n if (config.forward && isHermesRoute(config.forward.url)) {\n const w = await (deps.gatewayCheck ?? gatewayWarning)(config.forward.url);\n if (w) console.log(pc.yellow(` Warning: ${w}`));\n }\n console.log(` Status: ${NPX} listen status${p}`);\n if (ops.platform === \"linux\") console.log(` Follow: journalctl ${ops.root ? \"\" : \"--user \"}-u ${unitName(profileName)} -f`);\n console.log();\n}\n\nexport function uninstallListenService(profileName: string, quiet = false, deps: ListenServiceDeps = {}): void {\n const ops = deps.ops ?? systemOps();\n assertSupported(ops);\n const name = validProfileName(profileName);\n const units = [listenUnit(name), legacyListenUnit(name)].map((id) => ({ id, file: unitPath(ops, id) })).filter((u) => existsSync(u.file));\n if (!units.length) {\n if (!quiet) console.log(`No listener service is installed for profile \"${name}\".`);\n return;\n }\n for (const u of units) removeUnit(ops, u.id, u.file);\n // The last listener gone: remove the shared install too (only if it really is ours).\n if (!installedProfiles(ops).length) removeOwnInstall(dataDir());\n if (!quiet) console.log(`Removed the listener service for profile \"${name}\". The profile (and its key) was kept: ${profilePath(name)}`);\n}\n\nexport function listenServiceStatus(profileName: string, deps: ListenServiceDeps = {}): void {\n const ops = deps.ops ?? systemOps();\n assertSupported(ops);\n const name = validProfileName(profileName);\n const p = name === DEFAULT_PROFILE ? \"\" : ` --profile ${name}`;\n const installed = installedListenUnit(name, ops);\n if (!installed) {\n console.log(`No listener service is installed for profile \"${name}\". Install one with \\`${NPX} listen service install${p}\\`.`);\n process.exitCode = 1;\n return;\n }\n if (installed.legacy) {\n console.log(`This listener runs under its name from before the rename to xaq (${label(ops, installed.id)}). \\`${NPX} listen service install${p}\\` moves it to ${label(ops, listenUnit(name))}.\\n`);\n }\n try {\n if (ops.platform === \"linux\") systemctl(ops, \"status\", installed.id.systemd, \"--no-pager\");\n else ops.exec(\"launchctl\", [\"print\", `${launchdTarget(ops)}/${installed.id.launchd}`]);\n } catch {\n process.exitCode = 1;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export { p as installService, N as serviceInstallInput, F as serviceStatus, B as systemOps, H as uninstallService } from "./service-BVn3soZZ.js";
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+ import { r as json } from "./db-BEUEUPyP.js";
3
+ import { r as badRequest } from "./errors-FbMS3QBo.js";
4
+ //#region server/settings.ts
5
+ const USER_KEY = "settings";
6
+ var SettingsStore = class {
7
+ db;
8
+ bus;
9
+ config;
10
+ constructor(db, bus, config) {
11
+ this.db = db;
12
+ this.bus = bus;
13
+ this.config = config;
14
+ }
15
+ defaults() {
16
+ return {
17
+ publicUrl: defaultPublicUrl(this.config.host, this.config.port),
18
+ ingestMode: "poll",
19
+ pollIntervalSeconds: 30,
20
+ maxBodyChars: 2e4,
21
+ retentionDays: 30,
22
+ approvalTtlHours: 72,
23
+ webhookAllowlist: [
24
+ "localhost",
25
+ "127.0.0.0/8",
26
+ "::1"
27
+ ],
28
+ pairingEnabled: true,
29
+ brokerUpstreams: true,
30
+ calendarPollSeconds: 60
31
+ };
32
+ }
33
+ get() {
34
+ this.brokerOnOnce();
35
+ const row = this.db.get("SELECT value FROM settings WHERE key = ?", USER_KEY);
36
+ return {
37
+ ...this.defaults(),
38
+ ...json.parse(row?.value, {})
39
+ };
40
+ }
41
+ brokerChecked = false;
42
+ /**
43
+ * The broker shipped off (M1 PRs 1-7 wrote brokerUpstreams: false into saved settings on any save). When the
44
+ * console ships it turns on for everyone, once: a stored false becomes true, and the marker makes a later
45
+ * deliberate "off" (Settings → MCP broker) stick.
46
+ */
47
+ brokerOnOnce() {
48
+ if (this.brokerChecked) return;
49
+ this.brokerChecked = true;
50
+ if (this.getState("broker.defaultOnApplied")) return;
51
+ const row = this.db.get("SELECT value FROM settings WHERE key = ?", USER_KEY);
52
+ const stored = json.parse(row?.value, {});
53
+ this.db.tx(() => {
54
+ if (row && stored.brokerUpstreams === false) this.write(USER_KEY, {
55
+ ...stored,
56
+ brokerUpstreams: true
57
+ });
58
+ this.setState("broker.defaultOnApplied", (/* @__PURE__ */ new Date()).toISOString());
59
+ });
60
+ }
61
+ /** Validates, persists and broadcasts. Throws HttpError(400) on invalid input. */
62
+ update(patch) {
63
+ const next = validate({
64
+ ...this.get(),
65
+ ...stripUndefined(patch)
66
+ });
67
+ this.write(USER_KEY, next);
68
+ this.bus.emit("settings", next);
69
+ return next;
70
+ }
71
+ /** The OAuth redirect URI and MCP snippets are derived from this. Never has a trailing slash. */
72
+ publicUrl() {
73
+ return this.get().publicUrl;
74
+ }
75
+ getState(key) {
76
+ const row = this.db.get("SELECT value FROM settings WHERE key = ?", key);
77
+ return row ? json.parse(row.value, null) : null;
78
+ }
79
+ setState(key, value) {
80
+ this.write(key, value);
81
+ }
82
+ deleteState(key) {
83
+ this.db.run("DELETE FROM settings WHERE key = ?", key);
84
+ }
85
+ write(key, value) {
86
+ this.db.run("INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value", key, json.str(value));
87
+ }
88
+ };
89
+ const INGEST_MODES = ["pubsub", "poll"];
90
+ function validate(s) {
91
+ let url;
92
+ try {
93
+ url = new URL(s.publicUrl);
94
+ } catch {
95
+ throw badRequest("Public URL must be a full URL", "For example https://mail.example.com or http://localhost:8425");
96
+ }
97
+ if (url.protocol !== "http:" && url.protocol !== "https:") throw badRequest("Public URL must use http or https");
98
+ if (url.search || url.hash) throw badRequest("Public URL must not contain a query or fragment");
99
+ const int = (v, name, min, max) => {
100
+ if (!Number.isInteger(v) || v < min || v > max) throw badRequest(`${name} must be a whole number from ${min} to ${max}`);
101
+ return v;
102
+ };
103
+ if (!INGEST_MODES.includes(s.ingestMode)) throw badRequest("Ingest mode must be pubsub or poll");
104
+ const allowlist = Array.isArray(s.webhookAllowlist) ? s.webhookAllowlist.map((h) => String(h).trim()).filter(Boolean) : null;
105
+ if (!allowlist || allowlist.length > 100 || allowlist.some((h) => h.length > 253 || /\s/.test(h))) throw badRequest("Webhook allowlist must be a list of hostnames, IPs or CIDRs");
106
+ return {
107
+ publicUrl: url.origin + url.pathname.replace(/\/+$/, ""),
108
+ ingestMode: s.ingestMode,
109
+ pollIntervalSeconds: int(s.pollIntervalSeconds, "Poll interval", 5, 3600),
110
+ maxBodyChars: int(s.maxBodyChars, "Max body characters", 0, 1e6),
111
+ retentionDays: int(s.retentionDays, "Retention", 1, 3650),
112
+ approvalTtlHours: int(s.approvalTtlHours, "Approval expiry", 1, 720),
113
+ webhookAllowlist: [...new Set(allowlist)],
114
+ pairingEnabled: s.pairingEnabled !== false,
115
+ brokerUpstreams: s.brokerUpstreams !== false,
116
+ calendarPollSeconds: int(s.calendarPollSeconds, "Calendar poll interval", 15, 3600)
117
+ };
118
+ }
119
+ function stripUndefined(o) {
120
+ return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
121
+ }
122
+ /**
123
+ * localhost when bound to all interfaces or to 127.0.0.1/::1 (Google accepts http://localhost redirects);
124
+ * otherwise the specific address or name the operator chose with --host.
125
+ */
126
+ function defaultPublicUrl(host, port) {
127
+ const h = host.trim().toLowerCase();
128
+ if (!h || h === "0.0.0.0" || h === "::" || h === "localhost" || h === "::1" || h === "127.0.0.1") return `http://localhost:${port}`;
129
+ return `http://${h.includes(":") ? `[${h}]` : h}:${port}`;
130
+ }
131
+ //#endregion
132
+ export { defaultPublicUrl as n, SettingsStore as t };
133
+
134
+ //# sourceMappingURL=settings-B5qSHxRM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-B5qSHxRM.js","names":[],"sources":["../server/settings.ts"],"sourcesContent":["import type { GoogleAppType, GoogleClientCheck as ClientCheck, IngestMode, PubsubState, Settings } from \"../shared/types.ts\";\nimport type { Bus } from \"./bus.ts\";\nimport type { Config } from \"./config.ts\";\nimport { type Db, json } from \"./db/index.ts\";\nimport { badRequest } from \"./util/errors.ts\";\n\n/**\n * Internal key/value state kept in the `settings` table next to the user-facing Settings.\n * Owners: google.* and pubsub → server/google, admin.* → server/auth, calendar.* → server/calendar.\n */\nexport interface InternalState {\n \"google.client\": {\n clientId: string;\n /** AES-GCM ciphertext (ctx.crypto). */\n clientSecretEnc: string | null;\n projectId: string;\n /** null: imported from a client JSON without choosing the app type yet. */\n appType: GoogleAppType | null;\n /** redirect_uris listed in the last imported client JSON (absent after manual entry). */\n importedRedirectUris?: string[];\n /**\n * Redirect URI in effect when the client was last saved or imported: presumably the one registered\n * on it. A later public URL change makes it differ (SetupWarning redirect_uri_changed).\n */\n savedRedirectUri?: string;\n /** Redirect URI of the last successful account connection: proves it is registered on the client. */\n verifiedRedirectUri?: string | null;\n /** Last 4 characters of the secret, for display (GoogleClientView.secretHint). */\n secretHint?: string;\n /** Result of the last client check (server/google/check.ts) for this exact client ID + secret; dropped on save. */\n check?: { clientId: ClientCheck[\"clientId\"]; redirectUri: ClientCheck[\"redirectUri\"]; secret: ClientCheck[\"secret\"]; redirectUriTested: string; at: string };\n };\n /** Pub/Sub resources and health. `mode` is not stored here: it is Settings.ingestMode. */\n pubsub: Omit<PubsubState, \"mode\" | \"principalAccountId\" | \"principalEmail\" | \"pendingPrincipalAccountId\" | \"pendingPrincipalEmail\"> & {\n /** Account whose OAuth token pulls the subscription (it provisioned successfully; needs IAM on the project). */\n principalAccountId: string | null;\n /** Account chosen to provision with that hasn't succeeded yet (becomes principalAccountId on success). */\n pendingPrincipalAccountId?: string | null;\n };\n /**\n * Google Calendar for this install (CalendarSetupState). No row = enabled (fresh install); migration 7\n * writes {enabled:false} on installs that had accounts before the upgrade.\n */\n \"calendar.setup\": {\n enabled: boolean;\n /** When the operator hid the calendar_not_added notice. */\n dismissedAt?: string | null;\n /** Last observation of the Calendar API in the project (CalendarSetupState.api). */\n api?: {\n state: \"enabled\" | \"disabled\";\n at: string;\n error?: string | null;\n /** ErrorInfo metadata.activationUrl from Google's SERVICE_DISABLED answer (names the right project). */\n activationUrl?: string | null;\n };\n };\n /**\n * MCP broker policy limits (server/broker/policy). Missing fields take the defaults in\n * server/broker/policy/store.ts (BROKER_POLICY_DEFAULTS). null caps = no cap.\n */\n \"broker.policy\": {\n /** mcp.call approvals expire after this many hours. */\n approvalTtlHours?: number;\n /** Per agent, risky tool calls (run, queued or of unknown outcome) per rolling hour / 24 hours. */\n riskyPerHour?: number | null;\n riskyPerDay?: number | null;\n };\n \"admin.passwordHash\": string;\n /** When SetupState.verified first had evidence; kept so pruning the audit log doesn't undo it. */\n \"setup.verifiedAt\": string;\n /** When brokerUpstreams was turned on for this install by the console release (SettingsStore.brokerOnOnce). */\n \"broker.defaultOnApplied\": string;\n}\n\nexport type InternalKey = keyof InternalState;\n\nconst USER_KEY = \"settings\";\n\nexport class SettingsStore {\n constructor(\n private readonly db: Db,\n private readonly bus: Bus,\n private readonly config: Config,\n ) {}\n\n defaults(): Settings {\n return {\n publicUrl: defaultPublicUrl(this.config.host, this.config.port),\n ingestMode: \"poll\",\n pollIntervalSeconds: 30,\n maxBodyChars: 20_000,\n retentionDays: 30,\n approvalTtlHours: 72,\n webhookAllowlist: [\"localhost\", \"127.0.0.0/8\", \"::1\"],\n pairingEnabled: true,\n brokerUpstreams: true,\n calendarPollSeconds: 60,\n };\n }\n\n get(): Settings {\n this.brokerOnOnce();\n const row = this.db.get<{ value: string }>(\"SELECT value FROM settings WHERE key = ?\", USER_KEY);\n return { ...this.defaults(), ...json.parse<Partial<Settings>>(row?.value, {}) };\n }\n\n private brokerChecked = false;\n /**\n * The broker shipped off (M1 PRs 1-7 wrote brokerUpstreams: false into saved settings on any save). When the\n * console ships it turns on for everyone, once: a stored false becomes true, and the marker makes a later\n * deliberate \"off\" (Settings → MCP broker) stick.\n */\n private brokerOnOnce(): void {\n if (this.brokerChecked) return;\n this.brokerChecked = true;\n if (this.getState(\"broker.defaultOnApplied\")) return;\n const row = this.db.get<{ value: string }>(\"SELECT value FROM settings WHERE key = ?\", USER_KEY);\n const stored = json.parse<Partial<Settings>>(row?.value, {});\n this.db.tx(() => {\n if (row && stored.brokerUpstreams === false) this.write(USER_KEY, { ...stored, brokerUpstreams: true });\n this.setState(\"broker.defaultOnApplied\", new Date().toISOString());\n });\n }\n\n /** Validates, persists and broadcasts. Throws HttpError(400) on invalid input. */\n update(patch: Partial<Settings>): Settings {\n const next = validate({ ...this.get(), ...stripUndefined(patch) });\n this.write(USER_KEY, next);\n this.bus.emit(\"settings\", next);\n return next;\n }\n\n /** The OAuth redirect URI and MCP snippets are derived from this. Never has a trailing slash. */\n publicUrl(): string {\n return this.get().publicUrl;\n }\n\n getState<K extends InternalKey>(key: K): InternalState[K] | null {\n const row = this.db.get<{ value: string }>(\"SELECT value FROM settings WHERE key = ?\", key);\n return row ? json.parse<InternalState[K] | null>(row.value, null) : null;\n }\n\n setState<K extends InternalKey>(key: K, value: InternalState[K]): void {\n this.write(key, value);\n }\n\n deleteState(key: InternalKey): void {\n this.db.run(\"DELETE FROM settings WHERE key = ?\", key);\n }\n\n private write(key: string, value: unknown): void {\n this.db.run(\n \"INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value\",\n key,\n json.str(value),\n );\n }\n}\n\nconst INGEST_MODES: IngestMode[] = [\"pubsub\", \"poll\"];\n\nfunction validate(s: Settings): Settings {\n let url: URL;\n try {\n url = new URL(s.publicUrl);\n } catch {\n throw badRequest(\"Public URL must be a full URL\", \"For example https://mail.example.com or http://localhost:8425\");\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") throw badRequest(\"Public URL must use http or https\");\n if (url.search || url.hash) throw badRequest(\"Public URL must not contain a query or fragment\");\n const int = (v: number, name: string, min: number, max: number) => {\n if (!Number.isInteger(v) || v < min || v > max) throw badRequest(`${name} must be a whole number from ${min} to ${max}`);\n return v;\n };\n if (!INGEST_MODES.includes(s.ingestMode)) throw badRequest(\"Ingest mode must be pubsub or poll\");\n const allowlist = Array.isArray(s.webhookAllowlist) ? s.webhookAllowlist.map((h) => String(h).trim()).filter(Boolean) : null;\n if (!allowlist || allowlist.length > 100 || allowlist.some((h) => h.length > 253 || /\\s/.test(h))) {\n throw badRequest(\"Webhook allowlist must be a list of hostnames, IPs or CIDRs\");\n }\n return {\n publicUrl: url.origin + url.pathname.replace(/\\/+$/, \"\"),\n ingestMode: s.ingestMode,\n pollIntervalSeconds: int(s.pollIntervalSeconds, \"Poll interval\", 5, 3600),\n maxBodyChars: int(s.maxBodyChars, \"Max body characters\", 0, 1_000_000),\n retentionDays: int(s.retentionDays, \"Retention\", 1, 3650),\n approvalTtlHours: int(s.approvalTtlHours, \"Approval expiry\", 1, 24 * 30),\n webhookAllowlist: [...new Set(allowlist)],\n pairingEnabled: s.pairingEnabled !== false,\n brokerUpstreams: s.brokerUpstreams !== false,\n calendarPollSeconds: int(s.calendarPollSeconds, \"Calendar poll interval\", 15, 3600),\n };\n}\n\nfunction stripUndefined<T extends object>(o: T): Partial<T> {\n return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined)) as Partial<T>;\n}\n\n/**\n * localhost when bound to all interfaces or to 127.0.0.1/::1 (Google accepts http://localhost redirects);\n * otherwise the specific address or name the operator chose with --host.\n */\nexport function defaultPublicUrl(host: string, port: number): string {\n const h = host.trim().toLowerCase();\n const local = !h || h === \"0.0.0.0\" || h === \"::\" || h === \"localhost\" || h === \"::1\" || h === \"127.0.0.1\";\n if (local) return `http://localhost:${port}`;\n return `http://${h.includes(\":\") ? `[${h}]` : h}:${port}`;\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export { t as SettingsStore } from "./settings-B5qSHxRM.js";
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { randomBytes } from "node:crypto";
5
+ //#region server/util/ids.ts
6
+ const ALPHABET = "0123456789abcdefghjkmnpqrstvwxyz";
7
+ /** Random base32 string. 20 chars ≈ 100 bits. */
8
+ function randomToken(length = 20) {
9
+ const bytes = randomBytes(length);
10
+ let out = "";
11
+ for (let i = 0; i < length; i++) out += ALPHABET[bytes[i] & 31];
12
+ return out;
13
+ }
14
+ const newId = (prefix) => `${prefix}_${randomToken(20)}`;
15
+ //#endregion
16
+ //#region server/auth/setup-token.ts
17
+ /**
18
+ * One-time token required to claim a fresh install over the network. It is part of the setup link
19
+ * printed on startup and is persisted (mode 0600) so the link survives restarts and
20
+ * `service install` can show it. Deleted once the instance is claimed.
21
+ */
22
+ const setupTokenPath = (dataDir) => join(dataDir, "setup-token");
23
+ function readSetupToken(dataDir) {
24
+ try {
25
+ return readFileSync(setupTokenPath(dataDir), "utf8").trim() || null;
26
+ } catch {
27
+ return null;
28
+ }
29
+ }
30
+ function ensureSetupToken(dataDir) {
31
+ const existing = readSetupToken(dataDir);
32
+ if (existing) return existing;
33
+ const token = randomToken(24);
34
+ writeFileSync(setupTokenPath(dataDir), token + "\n", { mode: 384 });
35
+ return token;
36
+ }
37
+ /** Replaces any existing token (e.g. after `xaq reset-password`). */
38
+ function regenerateSetupToken(dataDir) {
39
+ deleteSetupToken(dataDir);
40
+ return ensureSetupToken(dataDir);
41
+ }
42
+ function deleteSetupToken(dataDir) {
43
+ rmSync(setupTokenPath(dataDir), { force: true });
44
+ }
45
+ //#endregion
46
+ export { newId as a, regenerateSetupToken as i, ensureSetupToken as n, randomToken as o, readSetupToken as r, deleteSetupToken as t };
47
+
48
+ //# sourceMappingURL=setup-token-CwuSzfLK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-token-CwuSzfLK.js","names":[],"sources":["../server/util/ids.ts","../server/auth/setup-token.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\n\nconst ALPHABET = \"0123456789abcdefghjkmnpqrstvwxyz\"; // Crockford base32, lowercase\n\n/** Random base32 string. 20 chars ≈ 100 bits. */\nexport function randomToken(length = 20): string {\n const bytes = randomBytes(length);\n let out = \"\";\n for (let i = 0; i < length; i++) out += ALPHABET[bytes[i]! & 31];\n return out;\n}\n\nexport type IdPrefix = \"acc\" | \"agt\" | \"grt\" | \"evt\" | \"whk\" | \"dlv\" | \"apr\" | \"par\" | \"con\" | \"rul\";\n\nexport const newId = (prefix: IdPrefix): string => `${prefix}_${randomToken(20)}`;\n","import { readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { randomToken } from \"../util/ids.ts\";\n\n/**\n * One-time token required to claim a fresh install over the network. It is part of the setup link\n * printed on startup and is persisted (mode 0600) so the link survives restarts and\n * `service install` can show it. Deleted once the instance is claimed.\n */\nexport const setupTokenPath = (dataDir: string) => join(dataDir, \"setup-token\");\n\nexport function readSetupToken(dataDir: string): string | null {\n try {\n return readFileSync(setupTokenPath(dataDir), \"utf8\").trim() || null;\n } catch {\n return null;\n }\n}\n\nexport function ensureSetupToken(dataDir: string): string {\n const existing = readSetupToken(dataDir);\n if (existing) return existing;\n const token = randomToken(24);\n writeFileSync(setupTokenPath(dataDir), token + \"\\n\", { mode: 0o600 });\n return token;\n}\n\n/** Replaces any existing token (e.g. after `xaq reset-password`). */\nexport function regenerateSetupToken(dataDir: string): string {\n deleteSetupToken(dataDir);\n return ensureSetupToken(dataDir);\n}\n\nexport function deleteSetupToken(dataDir: string): void {\n rmSync(setupTokenPath(dataDir), { force: true });\n}\n"],"mappings":";;;;;AAEA,MAAM,WAAW;;AAGjB,SAAgB,YAAY,SAAS,IAAY;CAC/C,MAAM,QAAQ,YAAY,MAAM;CAChC,IAAI,MAAM;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK,OAAO,SAAS,MAAM,KAAM;CAC7D,OAAO;AACT;AAIA,MAAa,SAAS,WAA6B,GAAG,OAAO,GAAG,YAAY,EAAE;;;;;;;;ACL9E,MAAa,kBAAkB,YAAoB,KAAK,SAAS,aAAa;AAE9E,SAAgB,eAAe,SAAgC;CAC7D,IAAI;EACF,OAAO,aAAa,eAAe,OAAO,GAAG,MAAM,CAAC,CAAC,KAAK,KAAK;CACjE,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,iBAAiB,SAAyB;CACxD,MAAM,WAAW,eAAe,OAAO;CACvC,IAAI,UAAU,OAAO;CACrB,MAAM,QAAQ,YAAY,EAAE;CAC5B,cAAc,eAAe,OAAO,GAAG,QAAQ,MAAM,EAAE,MAAM,IAAM,CAAC;CACpE,OAAO;AACT;;AAGA,SAAgB,qBAAqB,SAAyB;CAC5D,iBAAiB,OAAO;CACxB,OAAO,iBAAiB,OAAO;AACjC;AAEA,SAAgB,iBAAiB,SAAuB;CACtD,OAAO,eAAe,OAAO,GAAG,EAAE,OAAO,KAAK,CAAC;AACjD"}