@songsid/agend 2.2.0 → 2.2.5

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 (447) hide show
  1. package/dist/agent-cli-instructions.md +5 -2
  2. package/dist/agent-cli.js +284 -2
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.d.ts +2 -0
  5. package/dist/agent-endpoint.js +29 -0
  6. package/dist/agent-endpoint.js.map +1 -1
  7. package/dist/agent-file-read.d.ts +38 -0
  8. package/dist/agent-file-read.js +317 -0
  9. package/dist/agent-file-read.js.map +1 -0
  10. package/dist/agent-whats-new.d.ts +11 -0
  11. package/dist/agent-whats-new.js +34 -2
  12. package/dist/agent-whats-new.js.map +1 -1
  13. package/dist/atomic-write.js +9 -1
  14. package/dist/atomic-write.js.map +1 -1
  15. package/dist/auth-api.d.ts +30 -1
  16. package/dist/auth-api.js +61 -12
  17. package/dist/auth-api.js.map +1 -1
  18. package/dist/authority/authority-state.d.ts +38 -0
  19. package/dist/authority/authority-state.js +114 -0
  20. package/dist/authority/authority-state.js.map +1 -0
  21. package/dist/authority/session-authorizations.d.ts +43 -0
  22. package/dist/authority/session-authorizations.js +102 -0
  23. package/dist/authority/session-authorizations.js.map +1 -0
  24. package/dist/authority/web-authority.d.ts +120 -0
  25. package/dist/authority/web-authority.js +157 -0
  26. package/dist/authority/web-authority.js.map +1 -0
  27. package/dist/backend/antigravity.js +3 -3
  28. package/dist/backend/antigravity.js.map +1 -1
  29. package/dist/backend/claude-code.d.ts +2 -2
  30. package/dist/backend/claude-code.js +10 -5
  31. package/dist/backend/claude-code.js.map +1 -1
  32. package/dist/backend/launch-effort.js +1 -1
  33. package/dist/backend/launch-effort.js.map +1 -1
  34. package/dist/backend/muse.js +10 -2
  35. package/dist/backend/muse.js.map +1 -1
  36. package/dist/backend/types.d.ts +14 -0
  37. package/dist/backend/types.js +25 -0
  38. package/dist/backend/types.js.map +1 -1
  39. package/dist/backend-availability.d.ts +120 -0
  40. package/dist/backend-availability.js +396 -0
  41. package/dist/backend-availability.js.map +1 -0
  42. package/dist/backend-command.d.ts +21 -3
  43. package/dist/backend-command.js +23 -4
  44. package/dist/backend-command.js.map +1 -1
  45. package/dist/bundled-skills.d.ts +14 -0
  46. package/dist/bundled-skills.js +29 -0
  47. package/dist/bundled-skills.js.map +1 -0
  48. package/dist/cache-analysis.d.ts +47 -1
  49. package/dist/cache-analysis.js +68 -8
  50. package/dist/cache-analysis.js.map +1 -1
  51. package/dist/cache-ledger.d.ts +16 -3
  52. package/dist/cache-ledger.js +33 -13
  53. package/dist/cache-ledger.js.map +1 -1
  54. package/dist/cache-report-tool.d.ts +17 -0
  55. package/dist/cache-report-tool.js +40 -0
  56. package/dist/cache-report-tool.js.map +1 -0
  57. package/dist/cache-service.d.ts +70 -3
  58. package/dist/cache-service.js +178 -17
  59. package/dist/cache-service.js.map +1 -1
  60. package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
  61. package/dist/channel/adapters/discord-client-retirement.js +57 -0
  62. package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
  63. package/dist/channel/adapters/discord.d.ts +11 -0
  64. package/dist/channel/adapters/discord.js +66 -6
  65. package/dist/channel/adapters/discord.js.map +1 -1
  66. package/dist/channel/adapters/telegram.d.ts +8 -1
  67. package/dist/channel/adapters/telegram.js +74 -4
  68. package/dist/channel/adapters/telegram.js.map +1 -1
  69. package/dist/channel/mcp-tools.js +48 -2
  70. package/dist/channel/mcp-tools.js.map +1 -1
  71. package/dist/channel/types.d.ts +21 -0
  72. package/dist/classic-channel-manager.d.ts +10 -5
  73. package/dist/classic-channel-manager.js +12 -9
  74. package/dist/classic-channel-manager.js.map +1 -1
  75. package/dist/cli.js +142 -110
  76. package/dist/cli.js.map +1 -1
  77. package/dist/config-validator.js +119 -4
  78. package/dist/config-validator.js.map +1 -1
  79. package/dist/daemon.d.ts +10 -0
  80. package/dist/daemon.js +327 -31
  81. package/dist/daemon.js.map +1 -1
  82. package/dist/decision-list.d.ts +25 -0
  83. package/dist/decision-list.js +30 -0
  84. package/dist/decision-list.js.map +1 -0
  85. package/dist/delivery-outbox.d.ts +10 -0
  86. package/dist/delivery-outbox.js +12 -1
  87. package/dist/delivery-outbox.js.map +1 -1
  88. package/dist/fleet-context.d.ts +15 -0
  89. package/dist/fleet-manager.d.ts +514 -12
  90. package/dist/fleet-manager.js +1885 -163
  91. package/dist/fleet-manager.js.map +1 -1
  92. package/dist/fleet-process-handlers.d.ts +18 -0
  93. package/dist/fleet-process-handlers.js +69 -0
  94. package/dist/fleet-process-handlers.js.map +1 -0
  95. package/dist/fleet-traffic.d.ts +74 -0
  96. package/dist/fleet-traffic.js +196 -0
  97. package/dist/fleet-traffic.js.map +1 -0
  98. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +20 -5
  99. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +6 -1
  100. package/dist/general-knowledge/skills/multi-channel/SKILL.md +3 -2
  101. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  102. package/dist/general-knowledge/skills/web-appearance/SKILL.md +492 -0
  103. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +482 -0
  104. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  105. package/dist/human-delivery-receipts.d.ts +24 -1
  106. package/dist/human-delivery-receipts.js +64 -11
  107. package/dist/human-delivery-receipts.js.map +1 -1
  108. package/dist/instance-avatar.js +3 -0
  109. package/dist/instance-avatar.js.map +1 -1
  110. package/dist/instance-config-impact.js +6 -1
  111. package/dist/instance-config-impact.js.map +1 -1
  112. package/dist/instance-lifecycle.d.ts +2 -0
  113. package/dist/instance-lifecycle.js +20 -10
  114. package/dist/instance-lifecycle.js.map +1 -1
  115. package/dist/instance-names.d.ts +4 -0
  116. package/dist/instance-names.js +12 -0
  117. package/dist/instance-names.js.map +1 -0
  118. package/dist/instructions.d.ts +12 -1
  119. package/dist/instructions.js +13 -2
  120. package/dist/instructions.js.map +1 -1
  121. package/dist/locale.js +100 -8
  122. package/dist/locale.js.map +1 -1
  123. package/dist/ls-attach-resolve.d.ts +95 -0
  124. package/dist/ls-attach-resolve.js +174 -0
  125. package/dist/ls-attach-resolve.js.map +1 -0
  126. package/dist/memory-hogs.d.ts +27 -0
  127. package/dist/memory-hogs.js +124 -0
  128. package/dist/memory-hogs.js.map +1 -0
  129. package/dist/needs-you-hub.d.ts +4 -0
  130. package/dist/needs-you-hub.js +31 -6
  131. package/dist/needs-you-hub.js.map +1 -1
  132. package/dist/needs-you.d.ts +1 -13
  133. package/dist/needs-you.js +3 -37
  134. package/dist/needs-you.js.map +1 -1
  135. package/dist/outbound-handlers.d.ts +15 -0
  136. package/dist/outbound-handlers.js +152 -11
  137. package/dist/outbound-handlers.js.map +1 -1
  138. package/dist/outbound-schemas.d.ts +228 -4
  139. package/dist/outbound-schemas.js +147 -1
  140. package/dist/outbound-schemas.js.map +1 -1
  141. package/dist/public-web-gateway.js +21 -1
  142. package/dist/public-web-gateway.js.map +1 -1
  143. package/dist/public-web-link.d.ts +9 -0
  144. package/dist/public-web-link.js +8 -0
  145. package/dist/public-web-link.js.map +1 -1
  146. package/dist/quickstart-api.d.ts +10 -1
  147. package/dist/quickstart-api.js +12 -4
  148. package/dist/quickstart-api.js.map +1 -1
  149. package/dist/reply-buttons-controller.d.ts +4 -0
  150. package/dist/reply-buttons-controller.js +2 -2
  151. package/dist/reply-buttons-controller.js.map +1 -1
  152. package/dist/repo-worktree-guard.d.ts +36 -0
  153. package/dist/repo-worktree-guard.js +143 -0
  154. package/dist/repo-worktree-guard.js.map +1 -0
  155. package/dist/restart-progress.d.ts +65 -1
  156. package/dist/restart-progress.js +236 -10
  157. package/dist/restart-progress.js.map +1 -1
  158. package/dist/rollout-index.d.ts +5 -0
  159. package/dist/rollout-index.js +26 -5
  160. package/dist/rollout-index.js.map +1 -1
  161. package/dist/scheduler/scheduler.d.ts +70 -1
  162. package/dist/scheduler/scheduler.js +256 -17
  163. package/dist/scheduler/scheduler.js.map +1 -1
  164. package/dist/service-installer.d.ts +2 -1
  165. package/dist/service-installer.js +18 -3
  166. package/dist/service-installer.js.map +1 -1
  167. package/dist/settings-api.d.ts +23 -0
  168. package/dist/settings-api.js +233 -2
  169. package/dist/settings-api.js.map +1 -1
  170. package/dist/settings-change.js +112 -0
  171. package/dist/settings-change.js.map +1 -1
  172. package/dist/settings-effect.js +32 -2
  173. package/dist/settings-effect.js.map +1 -1
  174. package/dist/settings-http-confirmation.js +5 -0
  175. package/dist/settings-http-confirmation.js.map +1 -1
  176. package/dist/tmux-manager.d.ts +5 -0
  177. package/dist/tmux-manager.js +16 -0
  178. package/dist/tmux-manager.js.map +1 -1
  179. package/dist/tool-permissions.d.ts +4 -6
  180. package/dist/tool-permissions.js +100 -2
  181. package/dist/tool-permissions.js.map +1 -1
  182. package/dist/topic-commands.d.ts +17 -7
  183. package/dist/topic-commands.js +39 -21
  184. package/dist/topic-commands.js.map +1 -1
  185. package/dist/topic-link.d.ts +128 -0
  186. package/dist/topic-link.js +269 -0
  187. package/dist/topic-link.js.map +1 -0
  188. package/dist/types.d.ts +61 -1
  189. package/dist/ui/app-effects.js +245 -0
  190. package/dist/ui/chat-ambient.js +307 -0
  191. package/dist/ui/chat-effect-posters.js +42 -0
  192. package/dist/ui/chat-effects.js +160 -0
  193. package/dist/ui/chat-live-replies.js +58 -0
  194. package/dist/ui/chat-render.js +25 -7
  195. package/dist/ui/chat-store.js +41 -13
  196. package/dist/ui/chat-strings.js +86 -2
  197. package/dist/ui/chat-thread.js +204 -37
  198. package/dist/ui/chat-tour.js +1 -1
  199. package/dist/ui/effect-trial-controller.js +124 -0
  200. package/dist/ui/effect-trial-offer.js +31 -0
  201. package/dist/ui/effect-trial-panel.js +40 -0
  202. package/dist/ui/fleet-cache.js +23 -1
  203. package/dist/ui/fleet-canvas-layout.js +111 -0
  204. package/dist/ui/fleet-canvas.js +525 -0
  205. package/dist/ui/fleet-org.js +27 -12
  206. package/dist/ui/fleet-traffic.js +343 -0
  207. package/dist/ui/fleet-usage.js +401 -0
  208. package/dist/ui/image-lightbox.js +1 -1
  209. package/dist/ui/panel-chat.js +252 -58
  210. package/dist/ui/panel-details.js +20 -6
  211. package/dist/ui/panel-fleet.js +45 -19
  212. package/dist/ui/panel-log.js +6 -6
  213. package/dist/ui/panel-needs.js +3 -3
  214. package/dist/ui/panel-settings.js +58 -13
  215. package/dist/ui/preview-panel.js +25 -9
  216. package/dist/ui/preview.js +3 -2
  217. package/dist/ui/settings-appearance.js +349 -0
  218. package/dist/ui/settings-catalog.js +92 -0
  219. package/dist/ui/settings-dialogs.js +40 -12
  220. package/dist/ui/settings-effects.js +202 -0
  221. package/dist/ui/settings-guests.js +117 -0
  222. package/dist/ui/settings-learn.js +25 -0
  223. package/dist/ui/settings-model.js +15 -6
  224. package/dist/ui/settings-mods.js +271 -0
  225. package/dist/ui/settings-owner-effects.js +80 -0
  226. package/dist/ui/settings-strings.js +335 -10
  227. package/dist/ui/settings-web-authority.js +91 -0
  228. package/dist/ui/shared/agend-auth.js +28 -4
  229. package/dist/ui/shared/agent-widget.js +248 -0
  230. package/dist/ui/shared/app-i18n.js +6 -2
  231. package/dist/ui/shared/app-prefs.js +34 -13
  232. package/dist/ui/shared/app-route.js +42 -2
  233. package/dist/ui/shared/app-session.js +3 -1
  234. package/dist/ui/shared/app-shell.js +119 -41
  235. package/dist/ui/shared/app-store.js +28 -1
  236. package/dist/ui/shared/app-stream.js +14 -7
  237. package/dist/ui/shared/app-themes.js +206 -0
  238. package/dist/ui/shared/app.css +566 -5
  239. package/dist/ui/shared/app.js +23 -10
  240. package/dist/ui/shared/card-strings.js +32 -0
  241. package/dist/ui/shared/effect-app-runtime.js +297 -0
  242. package/dist/ui/shared/effect-baseline.js +64 -0
  243. package/dist/ui/shared/effect-chat-runtime.js +167 -0
  244. package/dist/ui/shared/effect-cursor.js +125 -0
  245. package/dist/ui/shared/effect-frame.js +146 -0
  246. package/dist/ui/shared/effect-geometry.js +137 -0
  247. package/dist/ui/shared/effect-host-style.js +10 -0
  248. package/dist/ui/shared/effect-owner-regions.js +74 -0
  249. package/dist/ui/shared/effect-owner-source.js +122 -0
  250. package/dist/ui/shared/effect-policy.js +151 -0
  251. package/dist/ui/shared/effect-poster-reader.js +98 -0
  252. package/dist/ui/shared/effect-posters.js +117 -0
  253. package/dist/ui/shared/effect-profiler.js +184 -0
  254. package/dist/ui/shared/effect-profiles.js +65 -0
  255. package/dist/ui/shared/effect-registry.js +543 -0
  256. package/dist/ui/shared/effect-runtime-loader.js +234 -0
  257. package/dist/ui/shared/effect-safety.js +153 -0
  258. package/dist/ui/shared/effect-stock-snapshot.js +43 -0
  259. package/dist/ui/shared/effect-stock-trust.js +217 -0
  260. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  261. package/dist/ui/shared/effect-trial-source.js +103 -0
  262. package/dist/ui/shared/effect-trial-stage.js +170 -0
  263. package/dist/ui/shared/effect-trial.css +40 -0
  264. package/dist/ui/shared/fx-motion.js +67 -0
  265. package/dist/ui/shared/header-tools.js +1 -1
  266. package/dist/ui/shared/identity-card.js +273 -0
  267. package/dist/ui/shared/identity-color.js +261 -0
  268. package/dist/ui/shared/instance-nav.js +215 -41
  269. package/dist/ui/shared/owner-css.js +250 -0
  270. package/dist/ui/shared/owner-effect-prefs.js +117 -0
  271. package/dist/ui/shared/panel-view.js +103 -10
  272. package/dist/ui/shared/signin.js +2 -0
  273. package/dist/ui/shared/tokens.css +9 -3
  274. package/dist/ui/shared/ui-dialog.js +1 -1
  275. package/dist/ui/shared/ui-icons.js +3 -0
  276. package/dist/ui/shared/ui-menu.js +1 -1
  277. package/dist/ui/shared/ui-toast.js +1 -1
  278. package/dist/ui/shared/usage-dialog.js +22 -2
  279. package/dist/ui/shared/view-strings.js +98 -2
  280. package/dist/ui/shared/web-authorize.js +151 -0
  281. package/dist/ui/signin.html +1 -0
  282. package/dist/ui/web-terminal/terminal.css +4 -4
  283. package/dist/usage/providers.d.ts +28 -0
  284. package/dist/usage/providers.js +126 -36
  285. package/dist/usage/providers.js.map +1 -1
  286. package/dist/usage-report.d.ts +158 -0
  287. package/dist/usage-report.js +226 -0
  288. package/dist/usage-report.js.map +1 -0
  289. package/dist/usage-rollup.d.ts +51 -0
  290. package/dist/usage-rollup.js +168 -0
  291. package/dist/usage-rollup.js.map +1 -0
  292. package/dist/view-api.d.ts +68 -0
  293. package/dist/view-api.js +249 -8
  294. package/dist/view-api.js.map +1 -1
  295. package/dist/web-ambient.d.ts +72 -0
  296. package/dist/web-ambient.js +161 -0
  297. package/dist/web-ambient.js.map +1 -0
  298. package/dist/web-api.d.ts +117 -7
  299. package/dist/web-api.js +1283 -70
  300. package/dist/web-api.js.map +1 -1
  301. package/dist/web-appearance-limits.d.ts +82 -0
  302. package/dist/web-appearance-limits.js +83 -0
  303. package/dist/web-appearance-limits.js.map +1 -0
  304. package/dist/web-appearance-policy.d.ts +64 -0
  305. package/dist/web-appearance-policy.js +87 -0
  306. package/dist/web-appearance-policy.js.map +1 -0
  307. package/dist/web-appearance-tools.d.ts +53 -0
  308. package/dist/web-appearance-tools.js +124 -0
  309. package/dist/web-appearance-tools.js.map +1 -0
  310. package/dist/web-appearance-view.d.ts +124 -0
  311. package/dist/web-appearance-view.js +278 -0
  312. package/dist/web-appearance-view.js.map +1 -0
  313. package/dist/web-appearance.d.ts +93 -0
  314. package/dist/web-appearance.js +373 -0
  315. package/dist/web-appearance.js.map +1 -0
  316. package/dist/web-asset-parts.d.ts +93 -0
  317. package/dist/web-asset-parts.js +133 -0
  318. package/dist/web-asset-parts.js.map +1 -0
  319. package/dist/web-auth.js +20 -2
  320. package/dist/web-auth.js.map +1 -1
  321. package/dist/web-card.d.ts +110 -0
  322. package/dist/web-card.js +266 -0
  323. package/dist/web-card.js.map +1 -0
  324. package/dist/web-channel-echo.d.ts +7 -1
  325. package/dist/web-channel-echo.js +6 -2
  326. package/dist/web-channel-echo.js.map +1 -1
  327. package/dist/web-chat-history.d.ts +63 -0
  328. package/dist/web-chat-history.js +109 -6
  329. package/dist/web-chat-history.js.map +1 -1
  330. package/dist/web-commands.d.ts +1 -0
  331. package/dist/web-effect-bootstrap.d.ts +12 -0
  332. package/dist/web-effect-bootstrap.js +49 -0
  333. package/dist/web-effect-bootstrap.js.map +1 -0
  334. package/dist/web-effect-bundle.d.ts +28 -0
  335. package/dist/web-effect-bundle.js +171 -0
  336. package/dist/web-effect-bundle.js.map +1 -0
  337. package/dist/web-effect-canonical.d.ts +8 -0
  338. package/dist/web-effect-canonical.js +27 -0
  339. package/dist/web-effect-canonical.js.map +1 -0
  340. package/dist/web-effect-library.d.ts +114 -0
  341. package/dist/web-effect-library.js +530 -0
  342. package/dist/web-effect-library.js.map +1 -0
  343. package/dist/web-effect-playback.d.ts +30 -0
  344. package/dist/web-effect-playback.js +71 -0
  345. package/dist/web-effect-playback.js.map +1 -0
  346. package/dist/web-effect-poster.d.ts +8 -0
  347. package/dist/web-effect-poster.js +52 -0
  348. package/dist/web-effect-poster.js.map +1 -0
  349. package/dist/web-effect-profiles.d.ts +118 -0
  350. package/dist/web-effect-profiles.js +180 -0
  351. package/dist/web-effect-profiles.js.map +1 -0
  352. package/dist/web-effect-service.d.ts +93 -0
  353. package/dist/web-effect-service.js +335 -0
  354. package/dist/web-effect-service.js.map +1 -0
  355. package/dist/web-effect-tools.d.ts +48 -0
  356. package/dist/web-effect-tools.js +129 -0
  357. package/dist/web-effect-tools.js.map +1 -0
  358. package/dist/web-effect-trials.d.ts +86 -0
  359. package/dist/web-effect-trials.js +204 -0
  360. package/dist/web-effect-trials.js.map +1 -0
  361. package/dist/web-effect-upload.d.ts +27 -0
  362. package/dist/web-effect-upload.js +185 -0
  363. package/dist/web-effect-upload.js.map +1 -0
  364. package/dist/web-effect-worker.d.ts +8 -0
  365. package/dist/web-effect-worker.js +170 -0
  366. package/dist/web-effect-worker.js.map +1 -0
  367. package/dist/web-effect.d.ts +103 -0
  368. package/dist/web-effect.js +153 -0
  369. package/dist/web-effect.js.map +1 -0
  370. package/dist/web-guest-access.d.ts +125 -0
  371. package/dist/web-guest-access.js +234 -0
  372. package/dist/web-guest-access.js.map +1 -0
  373. package/dist/web-guest-rooms.d.ts +82 -0
  374. package/dist/web-guest-rooms.js +135 -0
  375. package/dist/web-guest-rooms.js.map +1 -0
  376. package/dist/web-identity-color.d.ts +87 -0
  377. package/dist/web-identity-color.js +209 -0
  378. package/dist/web-identity-color.js.map +1 -0
  379. package/dist/web-identity-palette.d.ts +113 -0
  380. package/dist/web-identity-palette.js +84 -0
  381. package/dist/web-identity-palette.js.map +1 -0
  382. package/dist/web-image-meta.d.ts +38 -0
  383. package/dist/web-image-meta.js +262 -0
  384. package/dist/web-image-meta.js.map +1 -0
  385. package/dist/web-login.d.ts +47 -0
  386. package/dist/web-login.js +115 -0
  387. package/dist/web-login.js.map +1 -1
  388. package/dist/web-mod-agent.d.ts +50 -0
  389. package/dist/web-mod-agent.js +207 -0
  390. package/dist/web-mod-agent.js.map +1 -0
  391. package/dist/web-mod-bundle.d.ts +157 -0
  392. package/dist/web-mod-bundle.js +529 -0
  393. package/dist/web-mod-bundle.js.map +1 -0
  394. package/dist/web-mod-export.d.ts +68 -0
  395. package/dist/web-mod-export.js +100 -0
  396. package/dist/web-mod-export.js.map +1 -0
  397. package/dist/web-mod-store.d.ts +289 -0
  398. package/dist/web-mod-store.js +638 -0
  399. package/dist/web-mod-store.js.map +1 -0
  400. package/dist/web-org.d.ts +3 -3
  401. package/dist/web-org.js +11 -17
  402. package/dist/web-org.js.map +1 -1
  403. package/dist/web-owner-css-store.d.ts +222 -0
  404. package/dist/web-owner-css-store.js +440 -0
  405. package/dist/web-owner-css-store.js.map +1 -0
  406. package/dist/web-owner-css.d.ts +58 -0
  407. package/dist/web-owner-css.js +552 -0
  408. package/dist/web-owner-css.js.map +1 -0
  409. package/dist/web-prefs.d.ts +62 -0
  410. package/dist/web-prefs.js +232 -36
  411. package/dist/web-prefs.js.map +1 -1
  412. package/dist/web-preview.d.ts +15 -3
  413. package/dist/web-preview.js +28 -9
  414. package/dist/web-preview.js.map +1 -1
  415. package/dist/web-returning-device.d.ts +41 -0
  416. package/dist/web-returning-device.js +57 -5
  417. package/dist/web-returning-device.js.map +1 -1
  418. package/dist/web-session-authorization.d.ts +132 -0
  419. package/dist/web-session-authorization.js +193 -0
  420. package/dist/web-session-authorization.js.map +1 -0
  421. package/dist/web-session.d.ts +70 -10
  422. package/dist/web-session.js +137 -22
  423. package/dist/web-session.js.map +1 -1
  424. package/dist/web-settings-patch.d.ts +67 -2
  425. package/dist/web-settings-patch.js +196 -1
  426. package/dist/web-settings-patch.js.map +1 -1
  427. package/dist/web-settings-tools.d.ts +89 -0
  428. package/dist/web-settings-tools.js +273 -0
  429. package/dist/web-settings-tools.js.map +1 -0
  430. package/dist/web-shell-routes.d.ts +2 -2
  431. package/dist/web-shell-routes.js +2 -2
  432. package/dist/web-shell-routes.js.map +1 -1
  433. package/dist/web-theme-store.d.ts +257 -0
  434. package/dist/web-theme-store.js +627 -0
  435. package/dist/web-theme-store.js.map +1 -0
  436. package/dist/web-theme.d.ts +123 -0
  437. package/dist/web-theme.js +416 -0
  438. package/dist/web-theme.js.map +1 -0
  439. package/dist/web-upload.d.ts +13 -0
  440. package/dist/web-upload.js +39 -3
  441. package/dist/web-upload.js.map +1 -1
  442. package/dist/web-widget.d.ts +72 -0
  443. package/dist/web-widget.js +245 -0
  444. package/dist/web-widget.js.map +1 -0
  445. package/dist/workflow-templates/default.md +1 -1
  446. package/package.json +1 -1
  447. package/templates/systemd.service.ejs +8 -0
package/dist/daemon.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { AGENT_WHATS_NEW, agendVersion, planWhatsNew, readWhatsNewRecord, recordWhatsNew, whatsNewNotice } from "./agent-whats-new.js";
2
- import { join, dirname, basename, resolve } from "node:path";
2
+ import { join, dirname, resolve } from "node:path";
3
+ import { checkoutTarget, readCheckouts, releaseCandidate, reposRoot, verifyWorktree, writeCheckouts } from "./repo-worktree-guard.js";
3
4
  import { mkdirSync, writeFileSync, readFileSync, readdirSync, existsSync, unlinkSync, rmSync, appendFileSync, statSync, renameSync } from "node:fs";
4
5
  import { COMPACT_WATCH_TIMEOUT_MS, launchIdentity } from "./compact-watch.js";
5
6
  import { KIRO_COMPACT_PANE_LINES, KiroCompactPaneFollower } from "./kiro-compact-pane.js";
@@ -19,6 +20,9 @@ import { TranscriptTurnLedger } from "./transcript-turns.js";
19
20
  import { credentialProfileStoreHome, resolveCredentialProfile } from "./backend/credential-profile.js";
20
21
  import { resolveToolSet } from "./tool-permissions.js";
21
22
  import { getAgendHome } from "./paths.js";
23
+ import { readAgentEffect, sendEffectInParts } from "./web-effect-upload.js";
24
+ import { readAgentFile } from "./agent-file-read.js";
25
+ import { ASSET_UPLOAD_MAX_BYTES, MOD_FILE, MOD_MAX_PARTS, MOD_UPLOAD_MAX_BYTES, receiveFiles, receivePreview, sendAssetInParts, writeModFile, writePreview } from "./web-asset-parts.js";
22
26
  import { LOGIN_FLOWS } from "./login-flows.js";
23
27
  import { ProgressAccumulator, summarizeProgress } from "./tool-progress.js";
24
28
  import { assembleSystemPrompt, resolveWorkflowText } from "./prompt-file-ref.js";
@@ -52,9 +56,33 @@ import { codexLiveRowMatches } from "./backend/codex.js";
52
56
  import { claudeConfigDirFor, claudeProfileConfigDir, claudeSwitchDialog, claudeSwitchTargetMatches } from "./backend/claude-code.js";
53
57
  import { InteractionObservation, INTERACTION_CONFIRM_MS, sameInteractionOwner } from "./interaction-observation.js";
54
58
  import { unrecognisedPromptShape } from "./unrecognised-prompt.js";
59
+ /** #2140: deliveries that may carry an unwritten what's-new notice before it is recorded anyway. */
60
+ const WHATS_NEW_MAX_UNWRITTEN = 3;
55
61
  const __filename = fileURLToPath(import.meta.url);
56
62
  const __dirname = dirname(__filename);
57
63
  // Tool routing sets — module-level to avoid re-creation on every handleToolCall
64
+ /** #1629: the caller's own web theme tools, each its own typed IPC message (one tool per type, for the permission check). */
65
+ const WEB_THEME_IPC = Object.freeze({
66
+ get_web_theme: "fleet_get_web_theme", set_web_theme: "fleet_set_web_theme",
67
+ set_web_theme_asset: "fleet_set_web_theme_asset", reset_web_theme: "fleet_reset_web_theme",
68
+ // r4 §1: how it appears — read-only; a preview's files are written here, on the agent's side.
69
+ get_web_appearance: "fleet_get_web_appearance", preview_web_appearance: "fleet_preview_web_appearance",
70
+ // r4-4: its own declarative widgets.
71
+ set_web_widget: "fleet_set_web_widget", remove_web_widget: "fleet_remove_web_widget",
72
+ // #2117: its own declarative ambient.
73
+ set_web_ambient: "fleet_set_web_ambient", clear_web_ambient: "fleet_clear_web_ambient",
74
+ // r4-5b: mods — an export's file is written here, a proposal's file read here (on the agent's side).
75
+ export_web_mod: "fleet_export_web_mod", propose_web_mod: "fleet_propose_web_mod",
76
+ upload_web_effect: "fleet_upload_web_effect",
77
+ list_web_effects: "fleet_list_web_effects",
78
+ preview_web_effect: "fleet_preview_web_effect",
79
+ profile_web_effect: "fleet_profile_web_effect",
80
+ apply_web_effect: "fleet_apply_web_effect",
81
+ remove_web_effect: "fleet_remove_web_effect",
82
+ delete_web_effect: "fleet_delete_web_effect",
83
+ });
84
+ /** The largest picture any slot may take (a card slot's ceiling; the fleet checks the limit in force): read no more. */
85
+ const WEB_THEME_ASSET_MAX_BYTES = ASSET_UPLOAD_MAX_BYTES;
58
86
  const CROSS_INSTANCE_TOOLS = new Set(["send_to_instance", "broadcast", "list_instances", "start_instance", "restart_instance", "create_instance", "delete_instance", "replace_instance", "request_information", "delegate_task", "report_result", "delivery_status", "describe_instance"]);
59
87
  const SCHEDULE_TOOLS = new Set(["create_schedule", "list_schedules", "update_schedule", "delete_schedule"]);
60
88
  const DECISION_TOOLS = new Set(["post_decision", "list_decisions", "update_decision"]);
@@ -1073,7 +1101,7 @@ export class BlockingProcessDetector {
1073
1101
  /** Response types the fleet sends back for tool calls the daemon forwarded. */
1074
1102
  const FLEET_RESPONSE_TYPES = new Set([
1075
1103
  "fleet_schedule_response", "fleet_outbound_response", "fleet_decision_response", "fleet_task_response",
1076
- "fleet_display_name_response", "fleet_description_response", "fleet_persona_emoji_response",
1104
+ "fleet_display_name_response", "fleet_description_response", "fleet_persona_emoji_response", "fleet_web_theme_response",
1077
1105
  ]);
1078
1106
  export class Daemon extends EventEmitter {
1079
1107
  name;
@@ -1466,6 +1494,8 @@ export class Daemon extends EventEmitter {
1466
1494
  pendingInstructionsNotice = false;
1467
1495
  /** #1633: the one-time "what's new for you" notice, pasted before the next real delivery; recorded once pasted. */
1468
1496
  pendingWhatsNew = null;
1497
+ /** #2140: deliveries tried for the pending what's-new notice that never reached the pane (capped: never before every message). */
1498
+ whatsNewUnwritten = 0;
1469
1499
  // Whether the warmup steering-reload notice should be injected after spawn.
1470
1500
  // Set in trySpawn by comparing the freshly-built instructions against the
1471
1501
  // last value the agent was told about (prev-instructions). Skipped when
@@ -1535,6 +1565,7 @@ export class Daemon extends EventEmitter {
1535
1565
  windowQueryFailureTicks = 0;
1536
1566
  mcpRestartPending = false;
1537
1567
  mcpRestartStaleTimer = null;
1568
+ mcpRestartCooldownTimer = null;
1538
1569
  /** In-flight replacement grace; also the guard against three triggers stacking. */
1539
1570
  mcpRestartGraceTimer = null;
1540
1571
  /**
@@ -2553,6 +2584,24 @@ export class Daemon extends EventEmitter {
2553
2584
  this.fireMcpRestartRequest("already_idle");
2554
2585
  }
2555
2586
  }
2587
+ /** Keep a cooldown-suppressed revival alive without bypassing the idle gate. */
2588
+ deferMcpRestart(delayMs) {
2589
+ this.clearMcpRestartRequest();
2590
+ if (this.config.mcp_auto_restart === false || this.authFailureUnresolved
2591
+ || this.mcpRestartCancelledByRecovery("cooldown"))
2592
+ return;
2593
+ this.mcpRestartPending = true;
2594
+ this.mcpRestartCooldownTimer = setTimeout(() => {
2595
+ this.mcpRestartCooldownTimer = null;
2596
+ if (this.mcpRestartCancelledByRecovery("cooldown_expired"))
2597
+ return;
2598
+ this.clearMcpRestartRequest();
2599
+ if (this.config.mcp_auto_restart === false || this.authFailureUnresolved || this.mcpServerAlive().alive)
2600
+ return;
2601
+ this.armMcpRestartWhenIdle();
2602
+ }, Math.max(0, delayMs));
2603
+ this.mcpRestartCooldownTimer.unref?.();
2604
+ }
2556
2605
  /**
2557
2606
  * Single chokepoint for all three revival triggers (already_idle, idle_edge,
2558
2607
  * stale_timeout) — and therefore the one place worth re-checking reality.
@@ -2570,6 +2619,8 @@ export class Daemon extends EventEmitter {
2570
2619
  fireMcpRestartRequest(trigger) {
2571
2620
  if (this.mcpRestartCancelledByRecovery(trigger))
2572
2621
  return;
2622
+ if (this.mcpRestartCooldownTimer)
2623
+ return;
2573
2624
  // Authoritative re-read — the CLI may have replaced the server since the
2574
2625
  // health tick that armed this.
2575
2626
  if (this.mcpServerAlive().alive) {
@@ -2764,6 +2815,10 @@ export class Daemon extends EventEmitter {
2764
2815
  }
2765
2816
  clearMcpRestartRequest() {
2766
2817
  this.mcpRestartPending = false;
2818
+ if (this.mcpRestartCooldownTimer) {
2819
+ clearTimeout(this.mcpRestartCooldownTimer);
2820
+ this.mcpRestartCooldownTimer = null;
2821
+ }
2767
2822
  if (this.mcpRestartStaleTimer) {
2768
2823
  clearTimeout(this.mcpRestartStaleTimer);
2769
2824
  this.mcpRestartStaleTimer = null;
@@ -6770,15 +6825,30 @@ export class Daemon extends EventEmitter {
6770
6825
  const whatsNew = this.pendingWhatsNew ? this.currentWhatsNew(this.pendingWhatsNew) : null;
6771
6826
  if (whatsNew) {
6772
6827
  // #1633: here, inside the delivery lock and ahead of a real delivery — never into a busy turn, never to an
6773
- // instance nobody writes to. Recorded only once pasted: a failed or cancelled paste stays pending.
6774
- const pasted = await this.deliverMessage(whatsNew.notice, undefined, { deliveryEpoch });
6775
- if (pasted && this.pendingWhatsNew === whatsNew) {
6776
- this.pendingWhatsNew = null;
6777
- try {
6778
- recordWhatsNew(this.instanceDir, whatsNew.ids, whatsNew.version);
6779
- }
6780
- catch (err) {
6781
- this.logger.warn({ err }, "what's-new record not written — the notice may repeat once");
6828
+ // instance nobody writes to. #2140: told at most once. Once its paste reached the pane it is recorded, proven
6829
+ // submitted or not. A system paste has no unique id: its only pane proof is its opening line on the screen, and
6830
+ // a long notice (every entry since an old session began) scrolls that line above the captured rows once Claude
6831
+ // paints it — unproven, though the agent read it. One that never reached the pane (cancelled, never idle) is
6832
+ // tried again, at most WHATS_NEW_MAX_UNWRITTEN times, then recorded with a warning.
6833
+ const attempt = { reached: false };
6834
+ const pasted = await this.deliverMessage(whatsNew.notice, undefined, { deliveryEpoch, verdict: attempt });
6835
+ if (this.pendingWhatsNew === whatsNew) {
6836
+ const written = pasted || attempt.paneWriteStarted === true;
6837
+ if (!written)
6838
+ this.whatsNewUnwritten++;
6839
+ if (written || this.whatsNewUnwritten >= WHATS_NEW_MAX_UNWRITTEN) {
6840
+ if (!pasted) {
6841
+ this.logger.warn({ entries: whatsNew.ids, written, attempts: this.whatsNewUnwritten, phase: attempt.phase, proof: attempt.proof }, written ? "what's-new notice pasted but its submission could not be proven — recorded so it is not sent again"
6842
+ : "what's-new notice did not reach the pane after several deliveries — recorded so it is not sent again");
6843
+ }
6844
+ this.pendingWhatsNew = null;
6845
+ this.whatsNewUnwritten = 0;
6846
+ try {
6847
+ recordWhatsNew(this.instanceDir, whatsNew.ids, whatsNew.version);
6848
+ }
6849
+ catch (err) {
6850
+ this.logger.warn({ err }, "what's-new record not written — the notice may repeat once");
6851
+ }
6782
6852
  }
6783
6853
  }
6784
6854
  if (!this.isDeliveryEpochCurrent(deliveryEpoch))
@@ -9945,6 +10015,169 @@ export class Daemon extends EventEmitter {
9945
10015
  });
9946
10016
  return;
9947
10017
  }
10018
+ // #1629: the caller's own web theme. set_web_theme_asset's file is read HERE, on the agent's side (in its working
10019
+ // directory, no symlink, size-capped): the fleet receives bytes, never a workspace path.
10020
+ if (Object.hasOwn(WEB_THEME_IPC, tool)) {
10021
+ // Answered exactly once, whatever happens on the way (#1887 review: a throw here once left the call unanswered).
10022
+ let answered = false;
10023
+ const reply = (result, error) => { if (answered)
10024
+ return; answered = true; respond(result, error); };
10025
+ // One fleet request; resolves with its answer, or an error string (never rejects).
10026
+ const ask = (payload) => new Promise((resolve) => {
10027
+ const fleetReqId = `theme_${++this.fleetRequestSeq}_${requestId}`;
10028
+ const timeout = setTimeout(() => {
10029
+ this.pendingIpcRequests.delete(fleetReqId);
10030
+ resolve({ result: null, error: `${tool} timed out` });
10031
+ }, daemonBudgetMs(tool));
10032
+ this.pendingIpcRequests.set(fleetReqId, (respMsg) => {
10033
+ clearTimeout(timeout);
10034
+ resolve({ result: respMsg.result, error: respMsg.error });
10035
+ });
10036
+ this.ipcServer?.broadcast({ type: WEB_THEME_IPC[tool], payload, meta: { instance_name: this.name }, fleetRequestId: fleetReqId });
10037
+ });
10038
+ void (async () => {
10039
+ if (tool === "preview_web_appearance") {
10040
+ // The fleet builds the SVGs (whole, or in parts); they are written here, in the working directory.
10041
+ const first = await ask({ ...(args.modes !== undefined ? { modes: args.modes } : {}) });
10042
+ if (first.error) {
10043
+ reply(null, first.error);
10044
+ return;
10045
+ }
10046
+ let failed;
10047
+ const got = await receivePreview((first.result && typeof first.result === "object" ? first.result : {}), async (payload) => {
10048
+ const r = await ask(payload);
10049
+ if (r.error) {
10050
+ failed = r.error;
10051
+ return { error: r.error };
10052
+ }
10053
+ return (r.result && typeof r.result === "object" ? r.result : {});
10054
+ });
10055
+ if (failed) {
10056
+ reply(null, failed);
10057
+ return;
10058
+ }
10059
+ if ("error" in got) {
10060
+ reply(got, undefined);
10061
+ return;
10062
+ }
10063
+ const written = await writePreview(got.files, { workspace: this.config.working_directory, configuredWorkspace: this.config.working_directory, stateDir: getAgendHome(), instance: this.name });
10064
+ if ("error" in written) {
10065
+ reply(null, `preview_web_appearance: ${written.error}`);
10066
+ return;
10067
+ }
10068
+ reply(written, undefined);
10069
+ return;
10070
+ }
10071
+ if (tool === "export_web_mod") {
10072
+ // The fleet builds the file (whole, or in parts); it is written here, in the working directory.
10073
+ const first = await ask(args);
10074
+ if (first.error) {
10075
+ reply(null, first.error);
10076
+ return;
10077
+ }
10078
+ let failed;
10079
+ const firstResult = (first.result && typeof first.result === "object" ? first.result : {});
10080
+ const got = await receiveFiles(firstResult, async (payload) => {
10081
+ const r = await ask(payload);
10082
+ if (r.error) {
10083
+ failed = r.error;
10084
+ return { error: r.error };
10085
+ }
10086
+ return (r.result && typeof r.result === "object" ? r.result : {});
10087
+ }, { name: MOD_FILE, idKey: "transfer", what: "export", maxParts: MOD_MAX_PARTS });
10088
+ if (failed) {
10089
+ reply(null, failed);
10090
+ return;
10091
+ }
10092
+ if ("error" in got) {
10093
+ reply(got, undefined);
10094
+ return;
10095
+ }
10096
+ const written = await writeModFile(got.files, { workspace: this.config.working_directory, configuredWorkspace: this.config.working_directory, stateDir: getAgendHome(), instance: this.name });
10097
+ if ("error" in written) {
10098
+ reply(null, `export_web_mod: ${written.error}`);
10099
+ return;
10100
+ }
10101
+ reply({ ...written, ...(firstResult.effects_omitted ? { effects_omitted: firstResult.effects_omitted } : {}) }, undefined);
10102
+ return;
10103
+ }
10104
+ if (tool === "propose_web_mod") {
10105
+ const read = await readAgentFile(args.file, { workspace: this.config.working_directory, configuredWorkspace: this.config.working_directory, stateDir: getAgendHome(), instance: this.name, maxBytes: MOD_UPLOAD_MAX_BYTES });
10106
+ const named = typeof args.file === "string" ? args.file.slice(0, 200) : "the file argument";
10107
+ if (!read.ok) {
10108
+ reply(null, `propose_web_mod: ${named} — ${read.reason}`);
10109
+ return;
10110
+ }
10111
+ let failed;
10112
+ const answer = await sendAssetInParts("mod", read.bytes, async (payload) => {
10113
+ const r = await ask(payload);
10114
+ if (r.error) {
10115
+ failed = r.error;
10116
+ return { error: r.error };
10117
+ }
10118
+ return (r.result && typeof r.result === "object" ? r.result : {});
10119
+ });
10120
+ reply(failed ? null : answer, failed);
10121
+ return;
10122
+ }
10123
+ if (tool === "upload_web_effect") {
10124
+ const owner = { fence: this.launchFenceEpoch, spawn: this.spawnGeneration, boot: this.bootId, ipc: this.ipcServer };
10125
+ const current = () => !!owner.ipc && owner.ipc === this.ipcServer && owner.fence === this.launchFenceEpoch && owner.spawn === this.spawnGeneration && owner.boot === this.bootId && !this.deliveryWritesStopping && !this.startupAborted;
10126
+ if (!current()) {
10127
+ reply(null, "upload_web_effect: launch no longer current");
10128
+ return;
10129
+ }
10130
+ const read = await readAgentEffect(args.dir, { workspace: this.config.working_directory, configuredWorkspace: this.config.working_directory, stateDir: getAgendHome(), instance: this.name });
10131
+ if (!current()) {
10132
+ reply(null, "upload_web_effect: launch no longer current");
10133
+ return;
10134
+ }
10135
+ if (!read.ok) {
10136
+ reply(null, `upload_web_effect: ${read.reason}`);
10137
+ return;
10138
+ }
10139
+ let failed;
10140
+ const answer = await sendEffectInParts(read.files, async (payload) => {
10141
+ if (!current()) {
10142
+ failed = "upload_web_effect: launch no longer current";
10143
+ return { error: failed };
10144
+ }
10145
+ const r = await ask(payload);
10146
+ if (r.error) {
10147
+ failed = r.error;
10148
+ return { error: r.error };
10149
+ }
10150
+ return (r.result && typeof r.result === "object" ? r.result : {});
10151
+ });
10152
+ reply(failed ? null : answer, failed);
10153
+ return;
10154
+ }
10155
+ if (tool !== "set_web_theme_asset") {
10156
+ const r = await ask(args);
10157
+ reply(r.result, r.error);
10158
+ return;
10159
+ }
10160
+ const read = await readAgentFile(args.file, { workspace: this.config.working_directory, configuredWorkspace: this.config.working_directory, stateDir: getAgendHome(), instance: this.name, maxBytes: WEB_THEME_ASSET_MAX_BYTES });
10161
+ // The path as the agent gave it — only a string is shown (an object from raw JSON args is never coerced).
10162
+ const named = typeof args.file === "string" ? args.file.slice(0, 200) : "the file argument";
10163
+ if (!read.ok) {
10164
+ reply(null, `set_web_theme_asset: ${named} — ${read.reason}`);
10165
+ return;
10166
+ }
10167
+ // A picture larger than one IPC message goes up in parts (r4 §1: a card portrait may be megabytes).
10168
+ let failed;
10169
+ const answer = await sendAssetInParts(args.slot, read.bytes, async (payload) => {
10170
+ const r = await ask(payload);
10171
+ if (r.error) {
10172
+ failed = r.error;
10173
+ return { error: r.error };
10174
+ }
10175
+ return (r.result && typeof r.result === "object" ? r.result : {});
10176
+ });
10177
+ reply(failed ? null : answer, failed);
10178
+ })().catch((err) => reply(null, `${tool} failed: ${err instanceof Error ? err.message : "error"}`));
10179
+ return;
10180
+ }
9948
10181
  if (tool === TASK_TOOL) {
9949
10182
  const fleetReqId = `task_${++this.fleetRequestSeq}_${requestId}`;
9950
10183
  const timeout = setTimeout(() => {
@@ -11198,14 +11431,39 @@ export class Daemon extends EventEmitter {
11198
11431
  }
11199
11432
  if (ids.length === pending.ids.length)
11200
11433
  return pending;
11201
- const narrowed = { notice: whatsNewNotice(pending.version, AGENT_WHATS_NEW.filter(e => ids.includes(e.id))), ids, version: pending.version };
11434
+ // #2163: rebuilt as planned — only the entries this instance's roles are told; the rest are recorded with them.
11435
+ const roles = this.whatsNewRoles();
11436
+ const shown = AGENT_WHATS_NEW.filter(e => ids.includes(e.id) && (!e.audience || e.audience.some(r => roles.includes(r))));
11437
+ if (!shown.length) {
11438
+ this.pendingWhatsNew = null;
11439
+ try {
11440
+ recordWhatsNew(this.instanceDir, ids, pending.version);
11441
+ }
11442
+ catch (err) {
11443
+ this.logger.warn({ err }, "what's-new record not written — the notice may repeat once");
11444
+ }
11445
+ return null;
11446
+ }
11447
+ const narrowed = { notice: whatsNewNotice(pending.version, shown), ids, version: pending.version };
11202
11448
  this.pendingWhatsNew = narrowed;
11203
11449
  return narrowed;
11204
11450
  }
11451
+ /**
11452
+ * #2163: who this instance is to the what's-new notices — a ClassicBot room's agent, General, or a fleet worker (with
11453
+ * `coordinator` too when its tool set is coordinator or full, the ones that carry get_/set_web_settings).
11454
+ */
11455
+ whatsNewRoles() {
11456
+ if (this.runtimeIdentity?.kind === "classic")
11457
+ return ["classic"];
11458
+ if (this.config.general_topic === true || this.name === "general")
11459
+ return ["general"];
11460
+ const set = resolveToolSet(this.config, this.name);
11461
+ return set === "coordinator" || set === "full" ? ["worker", "coordinator"] : ["worker"];
11462
+ }
11205
11463
  /** #1633: what this instance has not been told about its AgEnD version yet (see agent-whats-new.ts). */
11206
11464
  prepareWhatsNew(fresh, version = agendVersion()) {
11207
11465
  try {
11208
- const plan = planWhatsNew({ record: readWhatsNewRecord(this.instanceDir), fresh, version });
11466
+ const plan = planWhatsNew({ record: readWhatsNewRecord(this.instanceDir), fresh, version, roles: this.whatsNewRoles() });
11209
11467
  if (!plan) {
11210
11468
  this.pendingWhatsNew = null;
11211
11469
  return;
@@ -11216,6 +11474,7 @@ export class Daemon extends EventEmitter {
11216
11474
  return;
11217
11475
  }
11218
11476
  this.pendingWhatsNew = plan;
11477
+ this.whatsNewUnwritten = 0;
11219
11478
  this.logger.info({ entries: plan.ids }, "what's-new notice pending for the next delivery");
11220
11479
  }
11221
11480
  catch (err) {
@@ -12055,16 +12314,29 @@ export class Daemon extends EventEmitter {
12055
12314
  respond(null, `Not a git repository: ${source}`);
12056
12315
  return;
12057
12316
  }
12058
- const repoDir = join(this.instanceDir, "repos");
12059
- mkdirSync(repoDir, { recursive: true });
12060
- const safeName = `${basename(source)}-${branch.replace(/\//g, "-")}`;
12061
- const worktreePath = join(repoDir, safeName);
12317
+ mkdirSync(join(this.instanceDir, "repos"), { recursive: true });
12318
+ // Only a fresh direct child of a real repos/ directory (never through a symlinked repos/, never an existing path).
12319
+ const target = checkoutTarget(this.instanceDir, source, branch);
12320
+ if (!target.ok) {
12321
+ respond(null, `checkout_repo: ${target.reason}`);
12322
+ return;
12323
+ }
12324
+ const worktreePath = target.path;
12062
12325
  try {
12063
- // Resolve branch/ref to verify it exists. Use `--` so git never treats
12064
- // branch as an option flag (defense in depth on top of the regex above).
12065
- await execFileAsync("git", ["rev-parse", "--verify", "--", branch], { cwd: source });
12066
- await execFileAsync("git", ["worktree", "add", "--detach", worktreePath, branch], { cwd: source });
12326
+ // Resolve branch/ref to verify it exists. `--end-of-options` keeps git from ever reading branch as an option
12327
+ // flag (defense in depth on top of the regex above). Not `--`: rev-parse then reads branch as a path, and
12328
+ // `--verify` fails for every ref ("Needed a single revision"), which broke checkout_repo entirely.
12329
+ await execFileAsync("git", ["rev-parse", "--verify", "--end-of-options", `${branch}^{commit}`], { cwd: source });
12330
+ await execFileAsync("git", ["worktree", "add", "--detach", worktreePath, "--end-of-options", branch], { cwd: source });
12067
12331
  const { stdout: commitHash } = await execFileAsync("git", ["rev-parse", "--short", "HEAD"], { cwd: worktreePath });
12332
+ // Recorded so release_repo can tell this instance's checkout of this repository from anything else.
12333
+ try {
12334
+ const { stdout: common } = await execFileAsync("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], { cwd: worktreePath });
12335
+ const root = reposRoot(this.instanceDir);
12336
+ if (root.ok)
12337
+ writeCheckouts(root.path, { ...readCheckouts(root.path), [worktreePath]: common.trim() });
12338
+ }
12339
+ catch { /* unrecorded: release still requires a listed linked worktree */ }
12068
12340
  respond({ path: worktreePath, branch, source, commit: commitHash.trim() });
12069
12341
  }
12070
12342
  catch (err) {
@@ -12072,26 +12344,50 @@ export class Daemon extends EventEmitter {
12072
12344
  }
12073
12345
  }
12074
12346
  async handleReleaseRepo(args, respond) {
12075
- const repoPath = args.path;
12076
- const reposDir = join(this.instanceDir, "repos");
12077
- // Safety: only allow releasing paths under our repos/ directory
12078
- if (!repoPath.startsWith(reposDir)) {
12079
- respond(null, `Cannot release path outside instance repos directory`);
12347
+ // Containment first (real paths, strictly inside this instance's repos/), then proof it is a git worktree.
12348
+ // Nothing that fails either check is ever removed.
12349
+ const candidate = releaseCandidate(this.instanceDir, args.path);
12350
+ if (!candidate.ok) {
12351
+ respond(null, `Cannot release: ${candidate.reason}`);
12352
+ return;
12353
+ }
12354
+ const root = reposRoot(this.instanceDir);
12355
+ if (!root.ok) {
12356
+ respond(null, `Cannot release: ${root.reason}`);
12357
+ return;
12358
+ }
12359
+ const { execFile: execFileCb } = await import("node:child_process");
12360
+ const { promisify } = await import("node:util");
12361
+ const execFileAsync = promisify(execFileCb);
12362
+ const git = async (gitArgs, cwd) => (await execFileAsync("git", gitArgs, { cwd })).stdout;
12363
+ const worktree = await verifyWorktree(root.path, candidate.path, git);
12364
+ if (!worktree.ok) {
12365
+ respond(null, `Cannot release: ${worktree.reason}`);
12080
12366
  return;
12081
12367
  }
12368
+ const repoPath = candidate.path;
12082
12369
  try {
12083
- const { execFile: execFileCb } = await import("node:child_process");
12084
- const { promisify } = await import("node:util");
12085
- const execFileAsync = promisify(execFileCb);
12086
- await execFileAsync("git", ["worktree", "remove", "--force", repoPath]);
12370
+ await git(["--git-dir", worktree.commonDir, "worktree", "remove", "--force", repoPath], worktree.commonDir);
12087
12371
  }
12088
12372
  catch {
12089
- // Fallback: rm directly if git worktree remove fails
12373
+ // Fallback for a verified worktree only: remove it, then let its repository forget it.
12090
12374
  try {
12091
12375
  rmSync(repoPath, { recursive: true, force: true });
12092
12376
  }
12093
12377
  catch { /* best effort */ }
12378
+ try {
12379
+ await git(["--git-dir", worktree.commonDir, "worktree", "prune"], worktree.commonDir);
12380
+ }
12381
+ catch { /* best effort */ }
12382
+ }
12383
+ try {
12384
+ const records = readCheckouts(root.path);
12385
+ if (repoPath in records) {
12386
+ delete records[repoPath];
12387
+ writeCheckouts(root.path, records);
12388
+ }
12094
12389
  }
12390
+ catch { /* the worktree is gone; a stale record only refuses a later, different repo at this path */ }
12095
12391
  respond({ released: true, path: repoPath });
12096
12392
  }
12097
12393
  buildSnapshotPrompt() {