@songsid/agend 2.1.12 → 2.2.0-alpha.2

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 (436) hide show
  1. package/README.md +4 -2
  2. package/README.zh-TW.md +4 -2
  3. package/dist/agent-cli.js +6 -1
  4. package/dist/agent-cli.js.map +1 -1
  5. package/dist/agent-endpoint.js +68 -12
  6. package/dist/agent-endpoint.js.map +1 -1
  7. package/dist/agent-token-header.d.ts +13 -0
  8. package/dist/agent-token-header.js +16 -0
  9. package/dist/agent-token-header.js.map +1 -0
  10. package/dist/auth/one-time-code.d.ts +19 -0
  11. package/dist/auth/one-time-code.js +49 -0
  12. package/dist/auth/one-time-code.js.map +1 -0
  13. package/dist/auth-api.d.ts +52 -0
  14. package/dist/auth-api.js +346 -0
  15. package/dist/auth-api.js.map +1 -0
  16. package/dist/backend/antigravity.js +4 -3
  17. package/dist/backend/antigravity.js.map +1 -1
  18. package/dist/backend/claude-code.d.ts +4 -0
  19. package/dist/backend/claude-code.js +97 -0
  20. package/dist/backend/claude-code.js.map +1 -1
  21. package/dist/backend/codex.js +59 -30
  22. package/dist/backend/codex.js.map +1 -1
  23. package/dist/backend/grok.js +1 -1
  24. package/dist/backend/grok.js.map +1 -1
  25. package/dist/backend/kiro-agent.d.ts +66 -0
  26. package/dist/backend/kiro-agent.js +302 -0
  27. package/dist/backend/kiro-agent.js.map +1 -0
  28. package/dist/backend/kiro-identity.d.ts +80 -0
  29. package/dist/backend/kiro-identity.js +537 -0
  30. package/dist/backend/kiro-identity.js.map +1 -0
  31. package/dist/backend/kiro-v2-store-worker.d.ts +1 -0
  32. package/dist/backend/kiro-v2-store-worker.js +87 -0
  33. package/dist/backend/kiro-v2-store-worker.js.map +1 -0
  34. package/dist/backend/kiro-v2-store.d.ts +54 -0
  35. package/dist/backend/kiro-v2-store.js +131 -0
  36. package/dist/backend/kiro-v2-store.js.map +1 -0
  37. package/dist/backend/kiro-v3-identity.d.ts +5 -0
  38. package/dist/backend/kiro-v3-identity.js +22 -0
  39. package/dist/backend/kiro-v3-identity.js.map +1 -1
  40. package/dist/backend/kiro.d.ts +90 -7
  41. package/dist/backend/kiro.js +500 -124
  42. package/dist/backend/kiro.js.map +1 -1
  43. package/dist/backend/muse.js +1 -1
  44. package/dist/backend/muse.js.map +1 -1
  45. package/dist/backend/types.d.ts +51 -3
  46. package/dist/backend/types.js.map +1 -1
  47. package/dist/cache-analysis.d.ts +92 -0
  48. package/dist/cache-analysis.js +147 -0
  49. package/dist/cache-analysis.js.map +1 -0
  50. package/dist/cache-ledger.d.ts +108 -0
  51. package/dist/cache-ledger.js +230 -0
  52. package/dist/cache-ledger.js.map +1 -0
  53. package/dist/cache-prices.d.ts +32 -0
  54. package/dist/cache-prices.js +73 -0
  55. package/dist/cache-prices.js.map +1 -0
  56. package/dist/cache-scan.d.ts +39 -0
  57. package/dist/cache-scan.js +115 -0
  58. package/dist/cache-scan.js.map +1 -0
  59. package/dist/cache-service.d.ts +115 -0
  60. package/dist/cache-service.js +417 -0
  61. package/dist/cache-service.js.map +1 -0
  62. package/dist/channel/adapters/discord.d.ts +1 -0
  63. package/dist/channel/adapters/discord.js +29 -10
  64. package/dist/channel/adapters/discord.js.map +1 -1
  65. package/dist/channel/adapters/telegram.d.ts +1 -0
  66. package/dist/channel/adapters/telegram.js +13 -1
  67. package/dist/channel/adapters/telegram.js.map +1 -1
  68. package/dist/channel/types.d.ts +9 -1
  69. package/dist/classic-channel-manager.d.ts +18 -10
  70. package/dist/classic-channel-manager.js +45 -18
  71. package/dist/classic-channel-manager.js.map +1 -1
  72. package/dist/cli-entry.d.ts +19 -0
  73. package/dist/cli-entry.js +36 -0
  74. package/dist/cli-entry.js.map +1 -0
  75. package/dist/cli.js +471 -146
  76. package/dist/cli.js.map +1 -1
  77. package/dist/command-table.d.ts +5 -3
  78. package/dist/command-table.js +29 -27
  79. package/dist/command-table.js.map +1 -1
  80. package/dist/config-validator.js +46 -0
  81. package/dist/config-validator.js.map +1 -1
  82. package/dist/config.js +12 -0
  83. package/dist/config.js.map +1 -1
  84. package/dist/connection-secrets.d.ts +6 -0
  85. package/dist/connection-secrets.js +4 -0
  86. package/dist/connection-secrets.js.map +1 -1
  87. package/dist/daemon.d.ts +95 -4
  88. package/dist/daemon.js +748 -111
  89. package/dist/daemon.js.map +1 -1
  90. package/dist/darwin-memory.d.ts +6 -1
  91. package/dist/darwin-memory.js +17 -6
  92. package/dist/darwin-memory.js.map +1 -1
  93. package/dist/delivery-consumed-watch.d.ts +85 -0
  94. package/dist/delivery-consumed-watch.js +244 -0
  95. package/dist/delivery-consumed-watch.js.map +1 -0
  96. package/dist/delivery-outbox.d.ts +61 -0
  97. package/dist/delivery-outbox.js +120 -2
  98. package/dist/delivery-outbox.js.map +1 -1
  99. package/dist/delivery-reconciliation.d.ts +14 -5
  100. package/dist/delivery-reconciliation.js +27 -4
  101. package/dist/delivery-reconciliation.js.map +1 -1
  102. package/dist/delivery-reconciliation.test.js +35 -1
  103. package/dist/delivery-reconciliation.test.js.map +1 -1
  104. package/dist/event-log.d.ts +4 -1
  105. package/dist/event-log.js +6 -3
  106. package/dist/event-log.js.map +1 -1
  107. package/dist/event-loop-watch.d.ts +28 -0
  108. package/dist/event-loop-watch.js +75 -3
  109. package/dist/event-loop-watch.js.map +1 -1
  110. package/dist/fleet-context.d.ts +22 -2
  111. package/dist/fleet-control-audit.d.ts +5 -0
  112. package/dist/fleet-control-audit.js +7 -0
  113. package/dist/fleet-control-audit.js.map +1 -1
  114. package/dist/fleet-level-config.d.ts +2 -2
  115. package/dist/fleet-level-config.js +28 -1
  116. package/dist/fleet-level-config.js.map +1 -1
  117. package/dist/fleet-manager.d.ts +339 -12
  118. package/dist/fleet-manager.js +2623 -461
  119. package/dist/fleet-manager.js.map +1 -1
  120. package/dist/full-restart.js +2 -3
  121. package/dist/full-restart.js.map +1 -1
  122. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +3 -1
  123. package/dist/host-memory.d.ts +4 -0
  124. package/dist/host-memory.js.map +1 -1
  125. package/dist/install-lock.d.ts +49 -0
  126. package/dist/install-lock.js +200 -0
  127. package/dist/install-lock.js.map +1 -0
  128. package/dist/instance-config-impact.js +8 -2
  129. package/dist/instance-config-impact.js.map +1 -1
  130. package/dist/instance-lifecycle.d.ts +10 -5
  131. package/dist/instance-lifecycle.js +162 -53
  132. package/dist/instance-lifecycle.js.map +1 -1
  133. package/dist/locale.js +164 -16
  134. package/dist/locale.js.map +1 -1
  135. package/dist/login-controller.d.ts +2 -0
  136. package/dist/login-controller.js +17 -5
  137. package/dist/login-controller.js.map +1 -1
  138. package/dist/memory-pressure.d.ts +7 -8
  139. package/dist/memory-pressure.js +76 -15
  140. package/dist/memory-pressure.js.map +1 -1
  141. package/dist/monotonic-budget.d.ts +2 -0
  142. package/dist/monotonic-budget.js +28 -0
  143. package/dist/monotonic-budget.js.map +1 -0
  144. package/dist/needs-you-hub.d.ts +114 -0
  145. package/dist/needs-you-hub.js +370 -0
  146. package/dist/needs-you-hub.js.map +1 -0
  147. package/dist/needs-you-live.d.ts +116 -0
  148. package/dist/needs-you-live.js +228 -0
  149. package/dist/needs-you-live.js.map +1 -0
  150. package/dist/needs-you.d.ts +132 -0
  151. package/dist/needs-you.js +164 -0
  152. package/dist/needs-you.js.map +1 -0
  153. package/dist/node-version-guard.d.ts +30 -0
  154. package/dist/node-version-guard.js +50 -0
  155. package/dist/node-version-guard.js.map +1 -0
  156. package/dist/operator-control-paths.d.ts +4 -0
  157. package/dist/operator-control-paths.js +24 -0
  158. package/dist/operator-control-paths.js.map +1 -0
  159. package/dist/outbound-handlers.d.ts +2 -0
  160. package/dist/outbound-handlers.js +9 -2
  161. package/dist/outbound-handlers.js.map +1 -1
  162. package/dist/outbound-schemas.d.ts +5 -5
  163. package/dist/outbound-schemas.js +1 -1
  164. package/dist/outbound-schemas.js.map +1 -1
  165. package/dist/package-preimage.d.ts +26 -0
  166. package/dist/package-preimage.js +96 -0
  167. package/dist/package-preimage.js.map +1 -0
  168. package/dist/profile-control.js +4 -20
  169. package/dist/profile-control.js.map +1 -1
  170. package/dist/public-web-gateway.d.ts +18 -0
  171. package/dist/public-web-gateway.js +141 -0
  172. package/dist/public-web-gateway.js.map +1 -0
  173. package/dist/public-web-link.d.ts +53 -0
  174. package/dist/public-web-link.js +175 -0
  175. package/dist/public-web-link.js.map +1 -0
  176. package/dist/quickstart-api.d.ts +8 -1
  177. package/dist/quickstart-api.js +86 -48
  178. package/dist/quickstart-api.js.map +1 -1
  179. package/dist/quickstart.d.ts +1 -0
  180. package/dist/quickstart.js +16 -6
  181. package/dist/quickstart.js.map +1 -1
  182. package/dist/restart-guard.d.ts +52 -0
  183. package/dist/restart-guard.js +109 -0
  184. package/dist/restart-guard.js.map +1 -0
  185. package/dist/scheduler/db.d.ts +7 -1
  186. package/dist/scheduler/db.js +44 -2
  187. package/dist/scheduler/db.js.map +1 -1
  188. package/dist/scheduler/index.d.ts +1 -1
  189. package/dist/scheduler/retry-label.d.ts +11 -0
  190. package/dist/scheduler/retry-label.js +24 -0
  191. package/dist/scheduler/retry-label.js.map +1 -0
  192. package/dist/scheduler/scheduler.d.ts +55 -2
  193. package/dist/scheduler/scheduler.js +220 -8
  194. package/dist/scheduler/scheduler.js.map +1 -1
  195. package/dist/scheduler/types.d.ts +22 -0
  196. package/dist/scheduler/types.js.map +1 -1
  197. package/dist/secret-store.d.ts +5 -0
  198. package/dist/secret-store.js +20 -0
  199. package/dist/secret-store.js.map +1 -1
  200. package/dist/service-activation.d.ts +152 -0
  201. package/dist/service-activation.js +407 -0
  202. package/dist/service-activation.js.map +1 -0
  203. package/dist/service-installer.d.ts +63 -1
  204. package/dist/service-installer.js +141 -16
  205. package/dist/service-installer.js.map +1 -1
  206. package/dist/service-plan.d.ts +65 -0
  207. package/dist/service-plan.js +108 -0
  208. package/dist/service-plan.js.map +1 -0
  209. package/dist/service-restart-selection.d.ts +6 -5
  210. package/dist/service-restart-selection.js +6 -5
  211. package/dist/service-restart-selection.js.map +1 -1
  212. package/dist/settings-api.d.ts +10 -2
  213. package/dist/settings-api.js +216 -72
  214. package/dist/settings-api.js.map +1 -1
  215. package/dist/settings-baseline.d.ts +20 -0
  216. package/dist/settings-baseline.js +104 -0
  217. package/dist/settings-baseline.js.map +1 -0
  218. package/dist/settings-change.d.ts +21 -0
  219. package/dist/settings-change.js +161 -0
  220. package/dist/settings-change.js.map +1 -0
  221. package/dist/settings-confirmation.d.ts +105 -0
  222. package/dist/settings-confirmation.js +232 -0
  223. package/dist/settings-confirmation.js.map +1 -0
  224. package/dist/settings-control.d.ts +41 -0
  225. package/dist/settings-control.js +294 -0
  226. package/dist/settings-control.js.map +1 -0
  227. package/dist/settings-effect.d.ts +24 -0
  228. package/dist/settings-effect.js +169 -0
  229. package/dist/settings-effect.js.map +1 -0
  230. package/dist/settings-http-confirmation.d.ts +29 -0
  231. package/dist/settings-http-confirmation.js +123 -0
  232. package/dist/settings-http-confirmation.js.map +1 -0
  233. package/dist/settings-instance-patch.d.ts +4 -0
  234. package/dist/settings-instance-patch.js +26 -0
  235. package/dist/settings-instance-patch.js.map +1 -0
  236. package/dist/settings-request-capability.d.ts +16 -0
  237. package/dist/settings-request-capability.js +32 -0
  238. package/dist/settings-request-capability.js.map +1 -0
  239. package/dist/settings-transaction.d.ts +65 -0
  240. package/dist/settings-transaction.js +223 -0
  241. package/dist/settings-transaction.js.map +1 -0
  242. package/dist/setup-auth.d.ts +10 -18
  243. package/dist/setup-auth.js +14 -38
  244. package/dist/setup-auth.js.map +1 -1
  245. package/dist/setup-form.d.ts +1 -1
  246. package/dist/setup-form.js +75 -18
  247. package/dist/setup-form.js.map +1 -1
  248. package/dist/setup-guide.d.ts +13 -0
  249. package/dist/setup-guide.js +25 -0
  250. package/dist/setup-guide.js.map +1 -0
  251. package/dist/setup-host.d.ts +16 -0
  252. package/dist/setup-host.js +199 -35
  253. package/dist/setup-host.js.map +1 -1
  254. package/dist/setup-wizard.js +5 -1
  255. package/dist/setup-wizard.js.map +1 -1
  256. package/dist/slash-authz.d.ts +17 -3
  257. package/dist/slash-authz.js +5 -0
  258. package/dist/slash-authz.js.map +1 -1
  259. package/dist/spawn-gate.js +3 -3
  260. package/dist/spawn-gate.js.map +1 -1
  261. package/dist/sqlite-open-errors.d.ts +12 -0
  262. package/dist/sqlite-open-errors.js +13 -0
  263. package/dist/sqlite-open-errors.js.map +1 -0
  264. package/dist/statusline-watcher.d.ts +5 -0
  265. package/dist/statusline-watcher.js +2 -0
  266. package/dist/statusline-watcher.js.map +1 -1
  267. package/dist/steer-capability.d.ts +6 -0
  268. package/dist/steer-capability.js +8 -0
  269. package/dist/steer-capability.js.map +1 -1
  270. package/dist/sync-work-attribution.d.ts +14 -0
  271. package/dist/sync-work-attribution.js +43 -8
  272. package/dist/sync-work-attribution.js.map +1 -1
  273. package/dist/tips.js +10 -5
  274. package/dist/tips.js.map +1 -1
  275. package/dist/tmux-control.d.ts +57 -5
  276. package/dist/tmux-control.js +379 -61
  277. package/dist/tmux-control.js.map +1 -1
  278. package/dist/tmux-manager.d.ts +20 -6
  279. package/dist/tmux-manager.js +90 -47
  280. package/dist/tmux-manager.js.map +1 -1
  281. package/dist/tmux-read.d.ts +59 -0
  282. package/dist/tmux-read.js +213 -0
  283. package/dist/tmux-read.js.map +1 -0
  284. package/dist/topic-commands.d.ts +21 -10
  285. package/dist/topic-commands.js +205 -63
  286. package/dist/topic-commands.js.map +1 -1
  287. package/dist/transcript-delta-reader.js +2 -1
  288. package/dist/transcript-delta-reader.js.map +1 -1
  289. package/dist/tunnel/cloudflared-install.d.ts +2 -0
  290. package/dist/tunnel/cloudflared-install.js +1 -1
  291. package/dist/tunnel/cloudflared-install.js.map +1 -1
  292. package/dist/tunnel/purpose-lane.d.ts +14 -0
  293. package/dist/tunnel/purpose-lane.js +43 -0
  294. package/dist/tunnel/purpose-lane.js.map +1 -0
  295. package/dist/turn-reply-guard.d.ts +2 -0
  296. package/dist/turn-reply-guard.js +10 -1
  297. package/dist/turn-reply-guard.js.map +1 -1
  298. package/dist/types.d.ts +33 -0
  299. package/dist/ui/app.html +18 -0
  300. package/dist/ui/chat-commands.js +43 -0
  301. package/dist/ui/chat-render.js +478 -0
  302. package/dist/ui/chat-store.js +318 -0
  303. package/dist/ui/chat-strings.js +89 -0
  304. package/dist/ui/chat-thread.js +246 -0
  305. package/dist/ui/chat-tour.js +116 -0
  306. package/dist/ui/fleet-cache.js +168 -0
  307. package/dist/ui/fleet-org.js +142 -0
  308. package/dist/ui/panel-chat.js +504 -0
  309. package/dist/ui/panel-fleet.js +427 -0
  310. package/dist/ui/panel-needs.js +202 -0
  311. package/dist/ui/panel-settings.js +754 -0
  312. package/dist/ui/preview-panel.js +202 -0
  313. package/dist/ui/preview.js +270 -0
  314. package/dist/ui/settings-apply.js +239 -0
  315. package/dist/ui/settings-confirm.js +186 -0
  316. package/dist/ui/settings-dialogs.js +546 -0
  317. package/dist/ui/settings-model.js +277 -0
  318. package/dist/ui/settings-strings.js +654 -0
  319. package/dist/ui/settings-wizard.js +140 -0
  320. package/dist/ui/shared/agend-auth.js +93 -0
  321. package/dist/ui/shared/app-ctx.js +80 -0
  322. package/dist/ui/shared/app-html.js +9 -0
  323. package/dist/ui/shared/app-i18n.js +95 -0
  324. package/dist/ui/shared/app-nav.js +73 -0
  325. package/dist/ui/shared/app-needs.js +114 -0
  326. package/dist/ui/shared/app-route.js +73 -0
  327. package/dist/ui/shared/app-session.js +66 -0
  328. package/dist/ui/shared/app-shell.js +346 -0
  329. package/dist/ui/shared/app-store.js +51 -0
  330. package/dist/ui/shared/app-stream.js +201 -0
  331. package/dist/ui/shared/app.css +820 -0
  332. package/dist/ui/shared/app.js +88 -0
  333. package/dist/ui/shared/fonts/OFL.txt +92 -0
  334. package/dist/ui/shared/fonts/README.md +21 -0
  335. package/dist/ui/shared/fonts/inter.woff2 +0 -0
  336. package/dist/ui/shared/htm.module.js +1 -0
  337. package/dist/ui/shared/panel-view.js +655 -0
  338. package/dist/ui/shared/preact-hooks.module.js +2 -0
  339. package/dist/ui/shared/preact.module.js +2 -0
  340. package/dist/ui/shared/signin.js +142 -0
  341. package/dist/ui/shared/theme.js +29 -0
  342. package/dist/ui/shared/tokens.css +153 -0
  343. package/dist/ui/shared/ui-confirm.js +43 -0
  344. package/dist/ui/shared/ui-dialog.js +45 -0
  345. package/dist/ui/shared/ui-icons.js +63 -0
  346. package/dist/ui/shared/ui-menu.js +39 -0
  347. package/dist/ui/shared/ui-states.js +20 -0
  348. package/dist/ui/shared/ui-toast.js +18 -0
  349. package/dist/ui/shared/vendor/htm.LICENSE +202 -0
  350. package/dist/ui/shared/vendor/preact.LICENSE +21 -0
  351. package/dist/ui/shared/vendor/vendor.json +39 -0
  352. package/dist/ui/shared/view-strings.js +309 -0
  353. package/dist/ui/signin.html +52 -0
  354. package/dist/update-check.d.ts +6 -2
  355. package/dist/update-check.js +12 -3
  356. package/dist/update-check.js.map +1 -1
  357. package/dist/update-dispatch.d.ts +28 -0
  358. package/dist/update-dispatch.js +73 -0
  359. package/dist/update-dispatch.js.map +1 -0
  360. package/dist/update-install.d.ts +129 -0
  361. package/dist/update-install.js +262 -0
  362. package/dist/update-install.js.map +1 -0
  363. package/dist/upgrade-notices.d.ts +17 -0
  364. package/dist/upgrade-notices.js +93 -0
  365. package/dist/upgrade-notices.js.map +1 -0
  366. package/dist/usage/statusline-usage.d.ts +2 -0
  367. package/dist/usage/statusline-usage.js +14 -10
  368. package/dist/usage/statusline-usage.js.map +1 -1
  369. package/dist/view-api.d.ts +6 -1
  370. package/dist/view-api.js +62 -51
  371. package/dist/view-api.js.map +1 -1
  372. package/dist/web-api.d.ts +85 -14
  373. package/dist/web-api.js +557 -77
  374. package/dist/web-api.js.map +1 -1
  375. package/dist/web-auth.d.ts +71 -27
  376. package/dist/web-auth.js +169 -69
  377. package/dist/web-auth.js.map +1 -1
  378. package/dist/web-body.d.ts +3 -0
  379. package/dist/web-body.js +55 -0
  380. package/dist/web-body.js.map +1 -0
  381. package/dist/web-channel-echo.d.ts +9 -0
  382. package/dist/web-channel-echo.js +55 -0
  383. package/dist/web-channel-echo.js.map +1 -0
  384. package/dist/web-chat-history.d.ts +125 -0
  385. package/dist/web-chat-history.js +184 -0
  386. package/dist/web-chat-history.js.map +1 -0
  387. package/dist/web-commands.d.ts +77 -0
  388. package/dist/web-commands.js +81 -0
  389. package/dist/web-commands.js.map +1 -0
  390. package/dist/web-continuation.d.ts +7 -0
  391. package/dist/web-continuation.js +22 -0
  392. package/dist/web-continuation.js.map +1 -0
  393. package/dist/web-host-guard.d.ts +34 -0
  394. package/dist/web-host-guard.js +57 -1
  395. package/dist/web-host-guard.js.map +1 -1
  396. package/dist/web-login.d.ts +72 -0
  397. package/dist/web-login.js +132 -0
  398. package/dist/web-login.js.map +1 -0
  399. package/dist/web-org.d.ts +55 -0
  400. package/dist/web-org.js +67 -0
  401. package/dist/web-org.js.map +1 -0
  402. package/dist/web-preview.d.ts +77 -0
  403. package/dist/web-preview.js +240 -0
  404. package/dist/web-preview.js.map +1 -0
  405. package/dist/web-request-context.d.ts +10 -0
  406. package/dist/web-request-context.js +13 -0
  407. package/dist/web-request-context.js.map +1 -0
  408. package/dist/web-session.d.ts +167 -0
  409. package/dist/web-session.js +389 -0
  410. package/dist/web-session.js.map +1 -0
  411. package/dist/web-shell-routes.d.ts +59 -0
  412. package/dist/web-shell-routes.js +96 -0
  413. package/dist/web-shell-routes.js.map +1 -0
  414. package/dist/web-upload.d.ts +183 -0
  415. package/dist/web-upload.js +468 -0
  416. package/dist/web-upload.js.map +1 -0
  417. package/dist/website-tips-renderer.d.ts +2 -2
  418. package/dist/website-tips-renderer.js +3 -3
  419. package/dist/website-tips-renderer.js.map +1 -1
  420. package/launcher/agend +110 -0
  421. package/launcher/agend-agent +110 -0
  422. package/launcher/agend-agent.cjs +4 -0
  423. package/launcher/agend.cjs +4 -0
  424. package/launcher/install-admission.cjs +105 -0
  425. package/launcher/launch.cjs +64 -0
  426. package/launcher/postinstall.cjs +114 -0
  427. package/launcher/run-in-process.cjs +13 -0
  428. package/launcher/runtime-platform.cjs +86 -0
  429. package/launcher/runtime-select.cjs +217 -0
  430. package/package.json +18 -7
  431. package/scripts/preinstall-guard.cjs +55 -0
  432. package/templates/launchd.plist.ejs +2 -2
  433. package/templates/systemd.service.ejs +1 -1
  434. package/dist/ui/dashboard.html +0 -774
  435. package/dist/ui/settings.html +0 -2165
  436. package/dist/ui/view.html +0 -1139
@@ -0,0 +1,184 @@
1
+ /**
2
+ * What the web chat has said, kept so that a reload — or a dropped SSE stream — does not leave the chat empty.
3
+ *
4
+ * The browser used to hold the only copy (500 messages per instance, in memory): a reload showed nothing, and a
5
+ * stream that reconnected silently lost whatever was said while it was down. Now every chat message the fleet
6
+ * pushes over SSE is recorded here with a monotonically increasing id: `/ui/history` serves the recent messages
7
+ * of one instance, and an EventSource that reconnects with `Last-Event-ID` is sent what it missed.
8
+ *
9
+ * Bounded by count AND by bytes per instance, so a chatty agent cannot grow the fleet process without limit.
10
+ * In memory only: it survives a page reload, not a fleet restart (persisting chat text is a separate decision).
11
+ *
12
+ * Ids count from 1 in every fleet process, so an id alone is not an identity across a restart: each history
13
+ * has a random `boot` generation, every message carries it, and the SSE cursor is `<boot>-<id>`. A cursor
14
+ * from another boot is not compared with this boot's ids at all — that client gets this boot's backlog.
15
+ */
16
+ import { randomBytes } from "node:crypto";
17
+ /**
18
+ * Ranks for the order a message moves through. Events can arrive late or twice (a queued after the spawn
19
+ * settles, a retry): a tick never moves back. `delivered` and `failed` are final; `cancelled` is not, since
20
+ * a Stop races a delivery already under way — what the agent actually got wins.
21
+ */
22
+ const DELIVERY_RANK = { queued: 1, processing: 2, cancelled: 3, delivered: 4, failed: 4 };
23
+ /** The state after `next` arrives at a message in `prev`; `prev` itself when `next` would move it back. */
24
+ export function nextDeliveryState(prev, next) {
25
+ // Own keys only: "__proto__" or "constructor" is in every object, and is no state.
26
+ if (!Object.hasOwn(DELIVERY_RANK, next))
27
+ return prev;
28
+ if (prev === undefined || !Object.hasOwn(DELIVERY_RANK, prev))
29
+ return next;
30
+ return DELIVERY_RANK[next] > DELIVERY_RANK[prev] ? next : prev;
31
+ }
32
+ const ROLES = new Set(["agent", "user", "status"]);
33
+ export const WEB_CHAT_TEXT_MAX = 16_000;
34
+ /**
35
+ * The `message_id` a message from the web chat is delivered under. Unique (two sends in one millisecond used
36
+ * to share `web-<ms>`), and never a platform id: Telegram and Discord ids are digits only.
37
+ */
38
+ export function newWebMessageId() {
39
+ return `web-${Date.now().toString(36)}-${randomBytes(4).toString("hex")}`;
40
+ }
41
+ /** Whether a delivery report is about a message from the web chat rather than one on a platform. */
42
+ export function isWebMessageId(messageId) {
43
+ return messageId.startsWith("web-");
44
+ }
45
+ export class WebChatHistory {
46
+ nextId = 1;
47
+ /** This process's generation: ids are only unique within it. */
48
+ boot;
49
+ byInstance = new Map();
50
+ perInstance;
51
+ perInstanceChars;
52
+ replayMax;
53
+ constructor(opts = {}) {
54
+ this.perInstance = opts.perInstance ?? 500;
55
+ this.perInstanceChars = opts.perInstanceChars ?? 1_000_000;
56
+ this.replayMax = opts.replayMax ?? 500;
57
+ this.boot = opts.boot ?? randomBytes(6).toString("hex");
58
+ }
59
+ /** The id the next message will get minus one: the newest id handed out so far (0 when none). */
60
+ get lastId() { return this.nextId - 1; }
61
+ /** Record one message; returns it with its id. Text beyond WEB_CHAT_TEXT_MAX is cut. */
62
+ record(msg) {
63
+ const entry = {
64
+ boot: this.boot,
65
+ id: this.nextId++,
66
+ instance: String(msg.instance),
67
+ // Anything not one of the three — or absent — is a person's message.
68
+ role: typeof msg.role === "string" && ROLES.has(msg.role) ? msg.role : "user",
69
+ sender: String(msg.sender),
70
+ text: String(msg.text ?? "").slice(0, WEB_CHAT_TEXT_MAX),
71
+ ts: String(msg.ts),
72
+ ...(msg.attachments && msg.attachments.length ? { attachments: msg.attachments.slice(0, 20).map(a => ({ id: a.id, kind: a.kind, name: a.name, size: a.size, mime: a.mime })) } : {}),
73
+ ...(typeof msg.messageId === "string" && msg.messageId ? { messageId: msg.messageId.slice(0, 64) } : {}),
74
+ };
75
+ let slot = this.byInstance.get(entry.instance);
76
+ if (!slot) {
77
+ slot = { messages: [], chars: 0 };
78
+ this.byInstance.set(entry.instance, slot);
79
+ }
80
+ slot.messages.push(entry);
81
+ slot.chars += entry.text.length;
82
+ while (slot.messages.length > 1 && (slot.messages.length > this.perInstance || slot.chars > this.perInstanceChars)) {
83
+ slot.chars -= slot.messages.shift().text.length;
84
+ }
85
+ return entry;
86
+ }
87
+ /** The most recent `limit` messages of one instance, oldest first. */
88
+ list(instance, limit = this.perInstance) {
89
+ const slot = this.byInstance.get(instance);
90
+ if (!slot)
91
+ return [];
92
+ const n = Math.max(0, Math.min(Math.floor(limit), this.perInstance));
93
+ return n === 0 ? [] : slot.messages.slice(-n);
94
+ }
95
+ /**
96
+ * Every message newer than `lastId`, across instances, oldest first, at most `replayMax` (the newest ones).
97
+ * Ids are this boot's: a cursor from another boot goes through replayFor(), never straight here.
98
+ */
99
+ after(lastId) {
100
+ if (!Number.isFinite(lastId) || lastId < 0)
101
+ return [];
102
+ const out = [];
103
+ for (const slot of this.byInstance.values()) {
104
+ for (const m of slot.messages)
105
+ if (m.id > lastId)
106
+ out.push(m);
107
+ }
108
+ out.sort((a, b) => a.id - b.id);
109
+ return out.length > this.replayMax ? out.slice(-this.replayMax) : out;
110
+ }
111
+ /**
112
+ * A delivery report for one of this instance's messages. Returns the message when its state changed (so the
113
+ * caller tells the pages), null when there is no such message or the report would move it back.
114
+ */
115
+ setDelivery(instance, messageId, state) {
116
+ const messages = this.byInstance.get(instance)?.messages ?? [];
117
+ let m;
118
+ for (let i = messages.length - 1; i >= 0 && !m; i--)
119
+ if (messages[i].messageId === messageId)
120
+ m = messages[i];
121
+ if (!m)
122
+ return null;
123
+ const next = nextDeliveryState(m.delivery, state);
124
+ if (next === m.delivery)
125
+ return null;
126
+ m.delivery = next;
127
+ return m;
128
+ }
129
+ /**
130
+ * A Stop on this instance: the web user's messages still waiting (nothing reported, or queued) were dropped
131
+ * from the queue. The queue is first in, first out, so nothing older than a message that got further can
132
+ * still be waiting: the walk goes back from the newest and stops there. Returns the messages it changed.
133
+ */
134
+ /**
135
+ * Where every retained web message got — the ticks — in one list. A delivery report has no cursor of its own and
136
+ * changes a message already sent, so a page that missed one (a dropped stream, a poll) catches up from this:
137
+ * the stream sends it on every (re)connect and each poll carries it (#1253 review). Ticks only move forward on
138
+ * the page, so receiving it twice changes nothing.
139
+ */
140
+ deliveries() {
141
+ const out = [];
142
+ for (const [instance, slot] of this.byInstance) {
143
+ for (const m of slot.messages)
144
+ if (m.messageId !== undefined && m.delivery !== undefined)
145
+ out.push({ instance, messageId: m.messageId, delivery: m.delivery });
146
+ }
147
+ return out;
148
+ }
149
+ cancelPending(instance) {
150
+ const changed = [];
151
+ const messages = this.byInstance.get(instance)?.messages ?? [];
152
+ for (let i = messages.length - 1; i >= 0; i--) {
153
+ const m = messages[i];
154
+ if (m.messageId === undefined)
155
+ continue;
156
+ if (m.delivery !== undefined && m.delivery !== "queued")
157
+ break;
158
+ m.delivery = "cancelled";
159
+ changed.push(m);
160
+ }
161
+ return changed.reverse();
162
+ }
163
+ /** Forget an instance (deleted). */
164
+ forget(instance) { this.byInstance.delete(instance); }
165
+ /** The SSE cursor for one message: `<boot>-<id>`. */
166
+ cursorOf(m) { return `${m.boot}-${m.id}`; }
167
+ /**
168
+ * What a reconnecting stream with this `Last-Event-ID` should be sent. A cursor of this boot replays what
169
+ * came after it; a cursor of another boot (the fleet restarted) gets this boot's whole retained backlog,
170
+ * since none of it can have been seen; no cursor, or one that is not ours in shape, gets nothing.
171
+ */
172
+ replayFor(cursor) {
173
+ if (!cursor)
174
+ return [];
175
+ return cursor.boot === this.boot ? this.after(cursor.id) : this.after(0);
176
+ }
177
+ }
178
+ /** `Last-Event-ID` as `<boot>-<id>`, or null when absent or not that shape. */
179
+ export function parseLastEventId(header) {
180
+ const raw = (Array.isArray(header) ? header[0] : header)?.trim();
181
+ const m = raw === undefined ? null : /^([0-9a-f]{1,32})-(\d{1,15})$/.exec(raw);
182
+ return m ? { boot: m[1], id: Number(m[2]) } : null;
183
+ }
184
+ //# sourceMappingURL=web-chat-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-chat-history.js","sourceRoot":"","sources":["../src/web-chat-history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * #1269 (4): an instance's chat commands, run from the web chat. Only what the instance's own Discord/Telegram topic
3
+ * already accepts, through the same handlers (topic-commands.ts / FleetManager) and the same table (command-table.ts,
4
+ * #754/#1148): nothing here is a capability the platforms do not have.
5
+ *
6
+ * - Who: a signed-in web session holds the full-fleet credential, issued only to a fleet admin (/dashboard is
7
+ * fleet-admin only), so the table's admin levels are met — exactly as a web click on a mirrored prompt is answered
8
+ * "as a fleet admin on the platform". The table can still refuse a command in a kind of channel; that stands.
9
+ * - What: instance commands only. Fleet-level ones (/status, /restart, /update, /login, …) stay in General
10
+ * (Discord-first), and /raw is not a command here (it bypasses the [user:] envelope).
11
+ * - The public link (a gateway request) is the outward-facing surface: /save is refused there — it makes the CLI
12
+ * write a file under a name the caller picks, outside the agent's own judgement.
13
+ * - /clear asks first, as on the platforms: the first call answers a confirmation token; only the second, with that
14
+ * token, clears — and only if the instance is still the one that was asked about.
15
+ */
16
+ import { type CommandScope } from "./command-table.js";
17
+ export declare const WEB_COMMANDS: readonly ["ctx", "compact", "clear", "model", "effort", "cancel", "btw", "steer", "pause", "wake", "save"];
18
+ export type WebCommand = typeof WEB_COMMANDS[number];
19
+ /** Refused on the public link (see the header). */
20
+ export declare const PUBLIC_LINK_REFUSED: ReadonlySet<WebCommand>;
21
+ export declare const MAX_COMMAND_ARGS = 4000;
22
+ export interface WebChoices {
23
+ current: string | null;
24
+ options: Array<{
25
+ id: string;
26
+ label: string;
27
+ }>;
28
+ }
29
+ export interface WebCommandDeps {
30
+ /** The instance is one the web chat may command (a fleet instance or a ClassicBot room), and in which scope. */
31
+ scope(instance: string): CommandScope | null;
32
+ ctx(instance: string): Promise<string>;
33
+ compact(instance: string, instructions: string | undefined): Promise<string>;
34
+ applyModel(instance: string, name: string): Promise<string>;
35
+ /** The model menu from the cached catalog only (never a live probe on this path); null: no list to offer. */
36
+ modelChoices(instance: string): WebChoices | null;
37
+ applyEffort(instance: string, level: string): Promise<string>;
38
+ effortChoices(instance: string): WebChoices | null;
39
+ cancel(instance: string): boolean;
40
+ steer(instance: string, text: string): string;
41
+ btw(instance: string, text: string): string;
42
+ pauseWake(instance: string, action: "pause" | "wake"): Promise<string>;
43
+ save(instance: string, filename: string): Promise<string>;
44
+ /** Ask: a confirmation token (or why not). Confirm: clear, if the token is live and the instance unchanged. */
45
+ clearAsk(instance: string): {
46
+ token: string;
47
+ message: string;
48
+ } | {
49
+ refused: string;
50
+ };
51
+ clearConfirm(instance: string, token: string): Promise<{
52
+ status: number;
53
+ text: string;
54
+ }>;
55
+ t(key: string, ...args: string[]): string;
56
+ }
57
+ export interface WebCommandInput {
58
+ instance: string;
59
+ command: string;
60
+ args?: string;
61
+ confirm?: string;
62
+ }
63
+ export interface WebCommandResult {
64
+ status: number;
65
+ body: {
66
+ text?: string;
67
+ error?: string;
68
+ choices?: WebChoices;
69
+ confirm?: {
70
+ token: string;
71
+ message: string;
72
+ };
73
+ };
74
+ }
75
+ export declare function runWebCommand(deps: WebCommandDeps, input: WebCommandInput, opts: {
76
+ publicLink: boolean;
77
+ }): Promise<WebCommandResult>;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * #1269 (4): an instance's chat commands, run from the web chat. Only what the instance's own Discord/Telegram topic
3
+ * already accepts, through the same handlers (topic-commands.ts / FleetManager) and the same table (command-table.ts,
4
+ * #754/#1148): nothing here is a capability the platforms do not have.
5
+ *
6
+ * - Who: a signed-in web session holds the full-fleet credential, issued only to a fleet admin (/dashboard is
7
+ * fleet-admin only), so the table's admin levels are met — exactly as a web click on a mirrored prompt is answered
8
+ * "as a fleet admin on the platform". The table can still refuse a command in a kind of channel; that stands.
9
+ * - What: instance commands only. Fleet-level ones (/status, /restart, /update, /login, …) stay in General
10
+ * (Discord-first), and /raw is not a command here (it bypasses the [user:] envelope).
11
+ * - The public link (a gateway request) is the outward-facing surface: /save is refused there — it makes the CLI
12
+ * write a file under a name the caller picks, outside the agent's own judgement.
13
+ * - /clear asks first, as on the platforms: the first call answers a confirmation token; only the second, with that
14
+ * token, clears — and only if the instance is still the one that was asked about.
15
+ */
16
+ import { commandSpec, decideCommand } from "./command-table.js";
17
+ import { SAVE_FILENAME_RE } from "./topic-commands.js";
18
+ export const WEB_COMMANDS = ["ctx", "compact", "clear", "model", "effort", "cancel", "btw", "steer", "pause", "wake", "save"];
19
+ /** Refused on the public link (see the header). */
20
+ export const PUBLIC_LINK_REFUSED = new Set(["save"]);
21
+ export const MAX_COMMAND_ARGS = 4000;
22
+ const isWebCommand = (c) => WEB_COMMANDS.includes(c);
23
+ export async function runWebCommand(deps, input, opts) {
24
+ const { instance } = input;
25
+ const command = input.command.replace(/^\//, "");
26
+ if (!isWebCommand(command))
27
+ return { status: 400, body: { error: deps.t("web.command_unknown", `/${command}`) } };
28
+ if (opts.publicLink && PUBLIC_LINK_REFUSED.has(command))
29
+ return { status: 403, body: { error: deps.t("web.command_public_refused", `/${command}`) } };
30
+ const scope = deps.scope(instance);
31
+ if (!scope)
32
+ return { status: 404, body: { error: deps.t("instance.not_found", instance) } };
33
+ // The same table the platforms use; the session is fleet-admin level, so only a scope refusal can stand.
34
+ const spec = commandSpec(command);
35
+ if (!spec)
36
+ return { status: 400, body: { error: deps.t("web.command_unknown", `/${command}`) } };
37
+ const decision = decideCommand(spec, scope, { fleetAdmin: () => "ok", channelAdmin: () => true, classicAdmin: () => true });
38
+ if (!decision.allow)
39
+ return { status: 403, body: { error: deps.t(...decision.reply) } };
40
+ const args = (input.args ?? "").trim();
41
+ const ok = (text) => ({ status: 200, body: { text } });
42
+ switch (command) {
43
+ case "ctx": return ok(await deps.ctx(instance));
44
+ case "compact": return ok(await deps.compact(instance, args || undefined));
45
+ case "model": {
46
+ if (args)
47
+ return ok(await deps.applyModel(instance, args));
48
+ const choices = deps.modelChoices(instance);
49
+ return choices ? { status: 200, body: { choices } } : ok(deps.t("model.list_unavailable", instance));
50
+ }
51
+ case "effort": {
52
+ if (args)
53
+ return ok(await deps.applyEffort(instance, args));
54
+ const choices = deps.effortChoices(instance);
55
+ return choices ? { status: 200, body: { choices } } : { status: 400, body: { error: deps.t("web.command_no_choices", "/effort") } };
56
+ }
57
+ case "cancel": return ok(deps.cancel(instance) ? deps.t("cancel.sent", instance) : deps.t("cancel.not_running", instance));
58
+ case "steer":
59
+ case "btw":
60
+ if (!args)
61
+ return { status: 400, body: { error: deps.t(`${command}.usage`) } };
62
+ return ok(command === "steer" ? deps.steer(instance, args) : deps.btw(instance, args));
63
+ case "pause":
64
+ case "wake": return ok(await deps.pauseWake(instance, command));
65
+ case "save":
66
+ if (!args)
67
+ return { status: 400, body: { error: deps.t("save.usage") } };
68
+ if (!SAVE_FILENAME_RE.test(args))
69
+ return { status: 400, body: { error: deps.t("filename.invalid") } };
70
+ return ok(await deps.save(instance, args));
71
+ case "clear": {
72
+ if (input.confirm) {
73
+ const r = await deps.clearConfirm(instance, input.confirm);
74
+ return { status: r.status, body: r.status === 200 ? { text: r.text } : { error: r.text } };
75
+ }
76
+ const asked = deps.clearAsk(instance);
77
+ return "token" in asked ? { status: 200, body: { confirm: asked } } : { status: 409, body: { error: asked.refused } };
78
+ }
79
+ }
80
+ }
81
+ //# sourceMappingURL=web-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-commands.js","sourceRoot":"","sources":["../src/web-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { WebSessionStore } from "./web-session.js";
3
+ /** Recheck AFTER a body/authorization await and BEFORE admitting a new public mutation. */
4
+ export declare function permitWebContinuation(req: IncomingMessage, res: ServerResponse, ctx: {
5
+ readonly webToken?: string | null;
6
+ readonly webSessions?: WebSessionStore | null;
7
+ }): boolean;
@@ -0,0 +1,22 @@
1
+ import { settingsRequestExecution } from "./settings-request-capability.js";
2
+ import { evaluateWebRequest } from "./web-auth.js";
3
+ import { gatewayRequestContext } from "./web-request-context.js";
4
+ /** Recheck AFTER a body/authorization await and BEFORE admitting a new public mutation. */
5
+ export function permitWebContinuation(req, res, ctx) {
6
+ const execution = settingsRequestExecution(req);
7
+ if (execution) {
8
+ execution.assert();
9
+ return !res.destroyed;
10
+ }
11
+ if (!gatewayRequestContext(req))
12
+ return true;
13
+ const verdict = evaluateWebRequest(req, new URL(req.url ?? "/", "http://localhost"), ctx.webToken ?? null, ctx.webSessions, { touch: false });
14
+ if (verdict.kind === "allow" && !res.destroyed)
15
+ return true;
16
+ if (!res.headersSent && !res.destroyed) {
17
+ res.writeHead(verdict.kind === "reject" ? verdict.status : 401, { "Content-Type": "application/json" });
18
+ res.end(JSON.stringify({ error: "public request no longer authorized" }));
19
+ }
20
+ return false;
21
+ }
22
+ //# sourceMappingURL=web-continuation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-continuation.js","sourceRoot":"","sources":["../src/web-continuation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,2FAA2F;AAC3F,MAAM,UAAU,qBAAqB,CAAC,GAAoB,EAAE,GAAmB,EAC7E,GAAyF;IACzF,MAAM,SAAS,GAAG,wBAAwB,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,SAAS,EAAE,CAAC;QAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;IAAC,CAAC;IAC7D,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,EAAE,GAAG,CAAC,QAAQ,IAAI,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9I,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5D,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACvC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACxG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -26,6 +26,23 @@ export declare const LOOPBACK_HOST_NAMES: readonly string[];
26
26
  * mistaken for it.
27
27
  */
28
28
  export declare function hostnameOf(value: string): string | null;
29
+ /**
30
+ * What a page served here may load and where it may send anything.
31
+ *
32
+ * `script-src` is this origin only — no `'unsafe-inline'` (#1268): a panel's own inline
33
+ * script runs because the panel is served with a per-response nonce for it
34
+ * (sendPanelHtml), and no panel has an inline `on*=` handler. Injected markup can
35
+ * therefore not run script. `connect-src`, `img-src` and `form-action` are this
36
+ * origin, so nothing read can be posted elsewhere, and `base-uri`, `object-src` and
37
+ * `frame-ancestors` are closed. Styles are the same (#1300): `style-src 'self'`, and a
38
+ * panel's own `<style>` block carries the response's nonce. No panel has a `style="…"`
39
+ * attribute — what a script colours or sizes at run time goes through the style object
40
+ * (CSSOM), which the policy does not govern — so injected markup cannot add inline styles of its
41
+ * own (it can still carry the page's existing class names).
42
+ *
43
+ * Fonts, scripts and styles are all served from here; nothing loads from a CDN.
44
+ */
45
+ export declare const WEB_CONTENT_SECURITY_POLICY: string;
29
46
  export interface HostGuardConfig {
30
47
  hostname?: string;
31
48
  web?: {
@@ -45,3 +62,20 @@ export declare function isHostAllowed(hostHeader: string | string[] | undefined,
45
62
  * Node merges `writeHead` headers over `setHeader` ones.
46
63
  */
47
64
  export declare function applyWebSecurityHeaders(res: ServerResponse): void;
65
+ /**
66
+ * The panel policy for one response: WEB_CONTENT_SECURITY_POLICY with this response's nonce for scripts and styles,
67
+ * and — for /ui only, when a preview origin was chosen for this load (#1306) — `frame-src <preview origin>/frame`:
68
+ * path-scoped, so nothing else of that origin can be framed or navigated to. Without it, frames fall back to
69
+ * default-src 'self'.
70
+ */
71
+ export declare function panelContentSecurityPolicy(nonce: string, opts?: {
72
+ frameSrc?: string;
73
+ }): string;
74
+ /**
75
+ * Send a panel page (/ui, /view, /settings, the sign-in page). Its own inline `<script>` and `<style>` blocks get a
76
+ * fresh nonce, and the response's CSP names that nonce and nothing else inline (#1268, #1300): a script or a style
77
+ * that was not in the file as served — anything injected into the page — has no nonce and does not apply.
78
+ */
79
+ export declare function sendPanelHtml(res: ServerResponse, html: string, status?: number, headers?: Record<string, string>, csp?: {
80
+ frameSrc?: string;
81
+ }): void;
@@ -1,3 +1,4 @@
1
+ import { randomBytes } from "node:crypto";
1
2
  export const WEB_HOST_REJECTED_MESSAGE = "Host not allowed — if you reach AgEnD through a reverse proxy or another name, add it to web.allowed_hosts in fleet.yaml";
2
3
  /** Names a browser on this machine uses for a loopback listener. */
3
4
  export const LOOPBACK_HOST_NAMES = ["localhost", "127.0.0.1", "[::1]"];
@@ -30,6 +31,34 @@ export function hostnameOf(value) {
30
31
  // either direction.
31
32
  return match[1].replace(/\.$/, "") || null;
32
33
  }
34
+ /**
35
+ * What a page served here may load and where it may send anything.
36
+ *
37
+ * `script-src` is this origin only — no `'unsafe-inline'` (#1268): a panel's own inline
38
+ * script runs because the panel is served with a per-response nonce for it
39
+ * (sendPanelHtml), and no panel has an inline `on*=` handler. Injected markup can
40
+ * therefore not run script. `connect-src`, `img-src` and `form-action` are this
41
+ * origin, so nothing read can be posted elsewhere, and `base-uri`, `object-src` and
42
+ * `frame-ancestors` are closed. Styles are the same (#1300): `style-src 'self'`, and a
43
+ * panel's own `<style>` block carries the response's nonce. No panel has a `style="…"`
44
+ * attribute — what a script colours or sizes at run time goes through the style object
45
+ * (CSSOM), which the policy does not govern — so injected markup cannot add inline styles of its
46
+ * own (it can still carry the page's existing class names).
47
+ *
48
+ * Fonts, scripts and styles are all served from here; nothing loads from a CDN.
49
+ */
50
+ export const WEB_CONTENT_SECURITY_POLICY = [
51
+ "default-src 'self'",
52
+ "script-src 'self'",
53
+ "style-src 'self'",
54
+ "img-src 'self' data: blob:",
55
+ "font-src 'self' data:",
56
+ "connect-src 'self'",
57
+ "object-src 'none'",
58
+ "base-uri 'none'",
59
+ "form-action 'self'",
60
+ "frame-ancestors 'none'",
61
+ ].join("; ");
33
62
  /** Loopback names, the `hostname:` handed out in /dashboard links, and `web.allowed_hosts`. */
34
63
  export function allowedHostNames(config) {
35
64
  const names = new Set(LOOPBACK_HOST_NAMES);
@@ -67,9 +96,36 @@ export function applyWebSecurityHeaders(res) {
67
96
  // These pages have buttons that restart instances and change configuration;
68
97
  // a page that can be framed can be clicked through.
69
98
  res.setHeader("X-Frame-Options", "DENY");
70
- res.setHeader("Content-Security-Policy", "frame-ancestors 'none'");
99
+ res.setHeader("Content-Security-Policy", WEB_CONTENT_SECURITY_POLICY);
71
100
  // Authorization now depends on a cookie, so a shared cache (a tunnel, a
72
101
  // corporate proxy) must not keep or replay any of it.
73
102
  res.setHeader("Cache-Control", "no-store");
74
103
  }
104
+ /**
105
+ * The panel policy for one response: WEB_CONTENT_SECURITY_POLICY with this response's nonce for scripts and styles,
106
+ * and — for /ui only, when a preview origin was chosen for this load (#1306) — `frame-src <preview origin>/frame`:
107
+ * path-scoped, so nothing else of that origin can be framed or navigated to. Without it, frames fall back to
108
+ * default-src 'self'.
109
+ */
110
+ export function panelContentSecurityPolicy(nonce, opts = {}) {
111
+ const policy = WEB_CONTENT_SECURITY_POLICY
112
+ .replace("script-src 'self'", `script-src 'self' 'nonce-${nonce}'`)
113
+ .replace("style-src 'self'", `style-src 'self' 'nonce-${nonce}'`);
114
+ return opts.frameSrc ? `${policy}; frame-src ${opts.frameSrc}` : policy;
115
+ }
116
+ /**
117
+ * Send a panel page (/ui, /view, /settings, the sign-in page). Its own inline `<script>` and `<style>` blocks get a
118
+ * fresh nonce, and the response's CSP names that nonce and nothing else inline (#1268, #1300): a script or a style
119
+ * that was not in the file as served — anything injected into the page — has no nonce and does not apply.
120
+ */
121
+ export function sendPanelHtml(res, html, status = 200, headers = {}, csp = {}) {
122
+ const nonce = randomBytes(18).toString("base64");
123
+ res.setHeader("Content-Security-Policy", panelContentSecurityPolicy(nonce, csp));
124
+ res.writeHead(status, { "Content-Type": "text/html; charset=utf-8", ...headers });
125
+ // Exactly the page's own bare `<script>` / `<style>` tags, as written in our files, get the nonce: a plain string
126
+ // match, not a tag filter. Any other spelling (`<SCRIPT>`, `<script src=…>`, `<script type=module>`) is left as is
127
+ // and so has no nonce: inline it is blocked, `src=` scripts load by 'self'. Widening the match would hand the
128
+ // nonce to more spellings; nothing here sanitises input.
129
+ res.end(html.split("<script>").join(`<script nonce="${nonce}">`).split("<style>").join(`<style nonce="${nonce}">`));
130
+ }
75
131
  //# sourceMappingURL=web-host-guard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"web-host-guard.js","sourceRoot":"","sources":["../src/web-host-guard.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,yBAAyB,GACpC,0HAA0H,CAAC;AAE7H,oEAAoE;AACpE,MAAM,CAAC,MAAM,mBAAmB,GAAsB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;AAE1F;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAClD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;QACvC,OAAO,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5D,CAAC;IACD,MAAM,KAAK,GAAG,+BAA+B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,0EAA0E;IAC1E,oBAAoB;IACpB,OAAO,KAAK,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC;AAC9C,CAAC;AAOD,+FAA+F;AAC/F,MAAM,UAAU,gBAAgB,CAAC,MAA0C;IACzE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS,mBAAmB,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,CAAC,SAAkB,EAAQ,EAAE;QACvC,IAAI,OAAO,SAAS,KAAK,QAAQ;YAAE,OAAO;QAC1C,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,IAAI;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC;IACF,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACtB,MAAM,KAAK,GAAG,MAAM,EAAE,GAAG,EAAE,aAAa,CAAC;IACzC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,MAAM,KAAK,IAAI,KAAK;YAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IAChE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,UAAyC,EAAE,OAA4B;IACnG,IAAI,OAAO,UAAU,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACjD,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACpC,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAmB;IACzD,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;IACnD,4EAA4E;IAC5E,oDAAoD;IACpD,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;IACzC,GAAG,CAAC,SAAS,CAAC,yBAAyB,EAAE,wBAAwB,CAAC,CAAC;IACnE,wEAAwE;IACxE,sDAAsD;IACtD,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"web-host-guard.js","sourceRoot":"","sources":["../src/web-host-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import type { SessionTier } from "./web-session.js";
2
+ export declare const LOGIN_CODE_TTL_MS: number;
3
+ /** Same reasoning as setup: eight characters on a phone get mistyped. */
4
+ export declare const MAX_LOGIN_CODE_ATTEMPTS = 5;
5
+ export declare const LOGIN_BREAKER_WINDOW_MS: number;
6
+ export declare const LOGIN_BREAKER_THRESHOLD = 20;
7
+ export declare const LOGIN_BREAKER_PAUSE_MS: number;
8
+ export interface LoginCodeOwner {
9
+ /** Server-owned live adapter identity; never accepted from HTTP. */
10
+ readonly binding?: object;
11
+ readonly adapterId: string;
12
+ readonly userId: string;
13
+ readonly chatId: string;
14
+ readonly threadId?: string;
15
+ }
16
+ export interface IssuedLoginCode {
17
+ readonly issuanceId: string;
18
+ /** As typed: `ABCD-EFGH`. */
19
+ readonly display: string;
20
+ readonly expiresAt: number;
21
+ readonly tier: SessionTier;
22
+ }
23
+ export type LoginRedeemResult = {
24
+ readonly kind: "ok";
25
+ readonly tier: SessionTier;
26
+ readonly owner?: LoginCodeOwner;
27
+ }
28
+ /** Wrong, expired, spent, or none issued — deliberately indistinguishable. */
29
+ | {
30
+ readonly kind: "invalid";
31
+ }
32
+ /** The breaker is open. Even a correct code is refused until it closes. */
33
+ | {
34
+ readonly kind: "paused";
35
+ readonly retryAfterMs: number;
36
+ };
37
+ export interface WebLoginCodesOptions {
38
+ readonly now?: () => number;
39
+ /** For tests that need a known code. */
40
+ readonly generate?: () => string;
41
+ readonly onEvent?: (event: "issued" | "spent" | "burned" | "breaker-open") => void;
42
+ }
43
+ export declare class WebLoginCodes {
44
+ private outstanding;
45
+ private failures;
46
+ private pausedUntil;
47
+ private readonly now;
48
+ private readonly generate;
49
+ private readonly onEvent;
50
+ constructor(opts?: WebLoginCodesOptions);
51
+ /**
52
+ * Issue a code, replacing any outstanding one. Only ever called from a channel the operator controls.
53
+ * `epoch` is the current web token's (`tokenEpoch`): rotating the token — from this process or from
54
+ * `agend web-token rotate` in another — withdraws an unused code, because redemption re-checks it.
55
+ */
56
+ issue(opts: {
57
+ tier?: SessionTier;
58
+ epoch: string;
59
+ audience?: string;
60
+ owner?: LoginCodeOwner;
61
+ }): IssuedLoginCode;
62
+ /** Whether a redemption right now would be compared against anything. */
63
+ get hasOutstandingCode(): boolean;
64
+ /** Withdraw the outstanding code without spending it (`/dashboard revoke`). */
65
+ revoke(): void;
66
+ /** `currentEpoch` is the web token's epoch NOW: a code issued under another token is gone. */
67
+ revokeIfCurrent(issuanceId: string): void;
68
+ revokeAudience(audience: string): void;
69
+ redeem(input: string, currentEpoch: string, audience?: string): LoginRedeemResult;
70
+ private activeCode;
71
+ private recordFailure;
72
+ }