@songsid/agend 2.3.2 → 2.3.3-beta.10

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 (393) hide show
  1. package/dist/agent-cli-instructions.md +2 -2
  2. package/dist/agent-cli.js +13 -112
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.d.ts +0 -1
  5. package/dist/agent-endpoint.js +1 -9
  6. package/dist/agent-endpoint.js.map +1 -1
  7. package/dist/agent-whats-new.d.ts +23 -5
  8. package/dist/agent-whats-new.js +58 -40
  9. package/dist/agent-whats-new.js.map +1 -1
  10. package/dist/auth-api.d.ts +0 -7
  11. package/dist/auth-api.js +1 -15
  12. package/dist/auth-api.js.map +1 -1
  13. package/dist/authority/authority-state.js +1 -1
  14. package/dist/authority/authority-state.js.map +1 -1
  15. package/dist/authority/web-authority.d.ts +9 -4
  16. package/dist/authority/web-authority.js +10 -5
  17. package/dist/authority/web-authority.js.map +1 -1
  18. package/dist/backend/antigravity.js +6 -1
  19. package/dist/backend/antigravity.js.map +1 -1
  20. package/dist/backend/claude-code.d.ts +20 -1
  21. package/dist/backend/claude-code.js +54 -29
  22. package/dist/backend/claude-code.js.map +1 -1
  23. package/dist/backend/claude-transcript-errors.d.ts +18 -0
  24. package/dist/backend/claude-transcript-errors.js +19 -0
  25. package/dist/backend/claude-transcript-errors.js.map +1 -0
  26. package/dist/backend/codex-session-lookup.d.ts +16 -3
  27. package/dist/backend/codex-session-lookup.js +45 -11
  28. package/dist/backend/codex-session-lookup.js.map +1 -1
  29. package/dist/backend/codex.d.ts +16 -0
  30. package/dist/backend/codex.js +184 -35
  31. package/dist/backend/codex.js.map +1 -1
  32. package/dist/backend/grok.js +58 -12
  33. package/dist/backend/grok.js.map +1 -1
  34. package/dist/backend/kiro-reconcile-store.js +8 -1
  35. package/dist/backend/kiro-reconcile-store.js.map +1 -1
  36. package/dist/backend/kiro.d.ts +0 -5
  37. package/dist/backend/kiro.js +2 -10
  38. package/dist/backend/kiro.js.map +1 -1
  39. package/dist/backend/muse.js +2 -1
  40. package/dist/backend/muse.js.map +1 -1
  41. package/dist/backend/types.d.ts +53 -4
  42. package/dist/backend/types.js.map +1 -1
  43. package/dist/bundled-skills.d.ts +4 -6
  44. package/dist/bundled-skills.js +10 -14
  45. package/dist/bundled-skills.js.map +1 -1
  46. package/dist/channel/adapters/discord.js +60 -17
  47. package/dist/channel/adapters/discord.js.map +1 -1
  48. package/dist/channel/mcp-server.js +5 -5
  49. package/dist/channel/mcp-server.js.map +1 -1
  50. package/dist/channel/mcp-tools.d.ts +1 -3
  51. package/dist/channel/mcp-tools.js +4 -58
  52. package/dist/channel/mcp-tools.js.map +1 -1
  53. package/dist/classic-channel-manager.d.ts +4 -1
  54. package/dist/classic-channel-manager.js +21 -7
  55. package/dist/classic-channel-manager.js.map +1 -1
  56. package/dist/cli.js +23 -6
  57. package/dist/cli.js.map +1 -1
  58. package/dist/config-history.d.ts +50 -0
  59. package/dist/config-history.js +263 -0
  60. package/dist/config-history.js.map +1 -0
  61. package/dist/config-validator.js +10 -8
  62. package/dist/config-validator.js.map +1 -1
  63. package/dist/config.d.ts +3 -0
  64. package/dist/config.js +11 -4
  65. package/dist/config.js.map +1 -1
  66. package/dist/cross-instance-envelope.d.ts +10 -5
  67. package/dist/cross-instance-envelope.js +20 -17
  68. package/dist/cross-instance-envelope.js.map +1 -1
  69. package/dist/daemon.d.ts +130 -64
  70. package/dist/daemon.js +603 -428
  71. package/dist/daemon.js.map +1 -1
  72. package/dist/daily-summary.d.ts +8 -1
  73. package/dist/daily-summary.js +8 -5
  74. package/dist/daily-summary.js.map +1 -1
  75. package/dist/dashboard-live.d.ts +1 -1
  76. package/dist/dashboard-live.js +3 -3
  77. package/dist/dashboard-live.js.map +1 -1
  78. package/dist/dashboard-permissions.d.ts +1 -1
  79. package/dist/dashboard-permissions.js +1 -3
  80. package/dist/dashboard-permissions.js.map +1 -1
  81. package/dist/delivery-outbox.d.ts +31 -22
  82. package/dist/delivery-outbox.js +119 -161
  83. package/dist/delivery-outbox.js.map +1 -1
  84. package/dist/delivery-outbox.test.js +10 -25
  85. package/dist/delivery-outbox.test.js.map +1 -1
  86. package/dist/doctor.d.ts +4 -0
  87. package/dist/doctor.js +16 -1
  88. package/dist/doctor.js.map +1 -1
  89. package/dist/fleet-level-config.js +1 -1
  90. package/dist/fleet-level-config.js.map +1 -1
  91. package/dist/fleet-manager.d.ts +74 -66
  92. package/dist/fleet-manager.js +285 -414
  93. package/dist/fleet-manager.js.map +1 -1
  94. package/dist/fleet-process-handlers.d.ts +5 -0
  95. package/dist/fleet-process-handlers.js +21 -0
  96. package/dist/fleet-process-handlers.js.map +1 -1
  97. package/dist/fleet-service-owner.d.ts +11 -0
  98. package/dist/fleet-service-owner.js +3 -0
  99. package/dist/fleet-service-owner.js.map +1 -0
  100. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +11 -1
  101. package/dist/general-knowledge/skills/delegation-playbook/SKILL.md +1 -1
  102. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +1 -1
  103. package/dist/general-knowledge/skills/session-management/SKILL.md +7 -1
  104. package/dist/general-knowledge/skills/web-appearance/SKILL.md +13 -204
  105. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +30 -68
  106. package/dist/instance-lifecycle.d.ts +19 -0
  107. package/dist/instance-lifecycle.js +73 -15
  108. package/dist/instance-lifecycle.js.map +1 -1
  109. package/dist/instructions.js +6 -7
  110. package/dist/instructions.js.map +1 -1
  111. package/dist/kiro-reconcile.js +3 -3
  112. package/dist/kiro-reconcile.js.map +1 -1
  113. package/dist/locale.js +96 -58
  114. package/dist/locale.js.map +1 -1
  115. package/dist/log-service.js +1 -1
  116. package/dist/log-service.js.map +1 -1
  117. package/dist/needs-you-hub.d.ts +1 -0
  118. package/dist/needs-you-hub.js +6 -3
  119. package/dist/needs-you-hub.js.map +1 -1
  120. package/dist/needs-you-live.d.ts +3 -1
  121. package/dist/needs-you-live.js +24 -2
  122. package/dist/needs-you-live.js.map +1 -1
  123. package/dist/needs-you.d.ts +13 -2
  124. package/dist/needs-you.js +11 -1
  125. package/dist/needs-you.js.map +1 -1
  126. package/dist/notify-socket.d.ts +10 -0
  127. package/dist/notify-socket.js +45 -0
  128. package/dist/notify-socket.js.map +1 -0
  129. package/dist/outbound-handlers.js +20 -8
  130. package/dist/outbound-handlers.js.map +1 -1
  131. package/dist/outbound-schemas.d.ts +0 -62
  132. package/dist/outbound-schemas.js +4 -43
  133. package/dist/outbound-schemas.js.map +1 -1
  134. package/dist/parked-notices.d.ts +87 -0
  135. package/dist/parked-notices.js +194 -0
  136. package/dist/parked-notices.js.map +1 -0
  137. package/dist/public-link-progress.d.ts +5 -2
  138. package/dist/public-link-progress.js +4 -3
  139. package/dist/public-link-progress.js.map +1 -1
  140. package/dist/public-web-gateway.js +0 -9
  141. package/dist/public-web-gateway.js.map +1 -1
  142. package/dist/public-web-link.d.ts +12 -0
  143. package/dist/public-web-link.js +29 -5
  144. package/dist/public-web-link.js.map +1 -1
  145. package/dist/quota-notice.d.ts +23 -0
  146. package/dist/quota-notice.js +22 -0
  147. package/dist/quota-notice.js.map +1 -0
  148. package/dist/scheduler/task-board.d.ts +17 -25
  149. package/dist/scheduler/task-board.js +29 -39
  150. package/dist/scheduler/task-board.js.map +1 -1
  151. package/dist/sd-notify.d.ts +23 -15
  152. package/dist/sd-notify.js +88 -29
  153. package/dist/sd-notify.js.map +1 -1
  154. package/dist/search/search-docs.d.ts +1 -1
  155. package/dist/search/search-docs.js +2 -2
  156. package/dist/search/search-docs.js.map +1 -1
  157. package/dist/settings-api.d.ts +16 -1
  158. package/dist/settings-api.js +56 -16
  159. package/dist/settings-api.js.map +1 -1
  160. package/dist/settings-change.js +3 -1
  161. package/dist/settings-change.js.map +1 -1
  162. package/dist/settings-confirmation.d.ts +17 -3
  163. package/dist/settings-confirmation.js +8 -5
  164. package/dist/settings-confirmation.js.map +1 -1
  165. package/dist/settings-effect.js +0 -2
  166. package/dist/settings-effect.js.map +1 -1
  167. package/dist/settings-http-confirmation.js +31 -1
  168. package/dist/settings-http-confirmation.js.map +1 -1
  169. package/dist/setup-wizard.d.ts +3 -0
  170. package/dist/setup-wizard.js +4 -2
  171. package/dist/setup-wizard.js.map +1 -1
  172. package/dist/task-board-waker.d.ts +43 -1
  173. package/dist/task-board-waker.js +121 -9
  174. package/dist/task-board-waker.js.map +1 -1
  175. package/dist/tmux-control.d.ts +1 -1
  176. package/dist/tmux-control.js +3 -2
  177. package/dist/tmux-control.js.map +1 -1
  178. package/dist/tmux-manager.js +18 -16
  179. package/dist/tmux-manager.js.map +1 -1
  180. package/dist/tmux-read.d.ts +2 -0
  181. package/dist/tmux-read.js +7 -1
  182. package/dist/tmux-read.js.map +1 -1
  183. package/dist/tool-permissions.js +3 -10
  184. package/dist/tool-permissions.js.map +1 -1
  185. package/dist/topic-commands.d.ts +29 -7
  186. package/dist/topic-commands.js +97 -37
  187. package/dist/topic-commands.js.map +1 -1
  188. package/dist/transcript-monitor.d.ts +7 -0
  189. package/dist/transcript-monitor.js +48 -3
  190. package/dist/transcript-monitor.js.map +1 -1
  191. package/dist/tunnel/cloudflared.d.ts +5 -0
  192. package/dist/tunnel/cloudflared.js +32 -1
  193. package/dist/tunnel/cloudflared.js.map +1 -1
  194. package/dist/tunnel/named-diagnostics.d.ts +2 -1
  195. package/dist/tunnel/named-diagnostics.js +4 -1
  196. package/dist/tunnel/named-diagnostics.js.map +1 -1
  197. package/dist/tunnel/named-link-test.d.ts +90 -0
  198. package/dist/tunnel/named-link-test.js +270 -0
  199. package/dist/tunnel/named-link-test.js.map +1 -0
  200. package/dist/tunnel/purpose-lane.d.ts +3 -1
  201. package/dist/tunnel/purpose-lane.js +2 -0
  202. package/dist/tunnel/purpose-lane.js.map +1 -1
  203. package/dist/types.d.ts +9 -11
  204. package/dist/ui/chat-ambient.js +4 -4
  205. package/dist/ui/chat-commands.js +3 -2
  206. package/dist/ui/chat-store.js +4 -1
  207. package/dist/ui/chat-strings.js +12 -46
  208. package/dist/ui/chat-thread.js +51 -59
  209. package/dist/ui/fleet-office-skin.js +37 -14
  210. package/dist/ui/fleet-office.js +31 -7
  211. package/dist/ui/html-attachment.js +22 -8
  212. package/dist/ui/panel-chat.js +21 -50
  213. package/dist/ui/panel-log.js +2 -2
  214. package/dist/ui/panel-needs.js +11 -9
  215. package/dist/ui/panel-settings.js +5 -3
  216. package/dist/ui/preview-panel.js +12 -21
  217. package/dist/ui/preview.js +10 -3
  218. package/dist/ui/search-dialog.js +30 -14
  219. package/dist/ui/settings-appearance.js +3 -37
  220. package/dist/ui/settings-confirm.js +18 -0
  221. package/dist/ui/settings-guests.js +13 -4
  222. package/dist/ui/settings-learn.js +1 -1
  223. package/dist/ui/settings-mods.js +5 -12
  224. package/dist/ui/settings-named-test.js +144 -0
  225. package/dist/ui/settings-registry.js +0 -2
  226. package/dist/ui/settings-strings.js +16 -16
  227. package/dist/ui/settings-web-authority.js +4 -3
  228. package/dist/ui/shared/app-i18n.js +15 -4
  229. package/dist/ui/shared/app-needs.js +5 -1
  230. package/dist/ui/shared/app-prefs.js +17 -17
  231. package/dist/ui/shared/app-shell.js +47 -9
  232. package/dist/ui/shared/app-store.js +6 -2
  233. package/dist/ui/shared/app.css +33 -39
  234. package/dist/ui/shared/app.js +5 -4
  235. package/dist/ui/shared/instance-nav.js +9 -9
  236. package/dist/ui/shared/instance-switch.js +8 -2
  237. package/dist/ui/shared/panel-view.js +22 -8
  238. package/dist/ui/shared/view-strings.js +6 -0
  239. package/dist/ui/shared/web-authorize.js +35 -13
  240. package/dist/update-check.d.ts +13 -4
  241. package/dist/update-check.js +17 -4
  242. package/dist/update-check.js.map +1 -1
  243. package/dist/usage/usage-api.d.ts +3 -0
  244. package/dist/usage/usage-api.js +5 -1
  245. package/dist/usage/usage-api.js.map +1 -1
  246. package/dist/view-api.d.ts +2 -0
  247. package/dist/view-api.js +64 -0
  248. package/dist/view-api.js.map +1 -1
  249. package/dist/web-api.d.ts +9 -17
  250. package/dist/web-api.js +257 -371
  251. package/dist/web-api.js.map +1 -1
  252. package/dist/web-appearance-tools.d.ts +0 -2
  253. package/dist/web-appearance-tools.js +2 -5
  254. package/dist/web-appearance-tools.js.map +1 -1
  255. package/dist/web-appearance-view.d.ts +0 -6
  256. package/dist/web-appearance-view.js +0 -1
  257. package/dist/web-appearance-view.js.map +1 -1
  258. package/dist/web-appearance.d.ts +14 -7
  259. package/dist/web-appearance.js +5 -6
  260. package/dist/web-appearance.js.map +1 -1
  261. package/dist/web-asset-parts.d.ts +1 -17
  262. package/dist/web-asset-parts.js +1 -15
  263. package/dist/web-asset-parts.js.map +1 -1
  264. package/dist/web-auth.js +1 -7
  265. package/dist/web-auth.js.map +1 -1
  266. package/dist/web-chat-history.d.ts +3 -7
  267. package/dist/web-chat-history.js +10 -17
  268. package/dist/web-chat-history.js.map +1 -1
  269. package/dist/web-commands.d.ts +9 -1
  270. package/dist/web-commands.js +13 -0
  271. package/dist/web-commands.js.map +1 -1
  272. package/dist/web-experimental.d.ts +3 -8
  273. package/dist/web-experimental.js +9 -33
  274. package/dist/web-experimental.js.map +1 -1
  275. package/dist/web-guest-access.d.ts +40 -2
  276. package/dist/web-guest-access.js +50 -14
  277. package/dist/web-guest-access.js.map +1 -1
  278. package/dist/web-mod-bundle.d.ts +2 -45
  279. package/dist/web-mod-bundle.js +15 -63
  280. package/dist/web-mod-bundle.js.map +1 -1
  281. package/dist/web-mod-store.d.ts +3 -48
  282. package/dist/web-mod-store.js +30 -97
  283. package/dist/web-mod-store.js.map +1 -1
  284. package/dist/web-prefs.d.ts +13 -0
  285. package/dist/web-prefs.js +38 -0
  286. package/dist/web-prefs.js.map +1 -1
  287. package/dist/web-preview.d.ts +6 -13
  288. package/dist/web-preview.js +12 -23
  289. package/dist/web-preview.js.map +1 -1
  290. package/dist/web-session.d.ts +11 -3
  291. package/dist/web-session.js +22 -11
  292. package/dist/web-session.js.map +1 -1
  293. package/dist/web-settings-patch.d.ts +1 -1
  294. package/dist/web-settings-patch.js +9 -7
  295. package/dist/web-settings-patch.js.map +1 -1
  296. package/dist/web-settings-tools.d.ts +0 -13
  297. package/dist/web-settings-tools.js +12 -84
  298. package/dist/web-settings-tools.js.map +1 -1
  299. package/dist/workflow-templates/default.md +2 -2
  300. package/dist/working-recovery.d.ts +0 -2
  301. package/dist/working-recovery.js +2 -23
  302. package/dist/working-recovery.js.map +1 -1
  303. package/launcher/agend-install.cjs +7 -1
  304. package/launcher/fleet-service-owner.cjs +150 -0
  305. package/package.json +1 -1
  306. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +0 -376
  307. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +0 -673
  308. package/dist/task-board-summary.d.ts +0 -101
  309. package/dist/task-board-summary.js +0 -177
  310. package/dist/task-board-summary.js.map +0 -1
  311. package/dist/ui/app-effects.js +0 -251
  312. package/dist/ui/chat-effect-posters.js +0 -42
  313. package/dist/ui/chat-effects.js +0 -167
  314. package/dist/ui/effect-trial-controller.js +0 -124
  315. package/dist/ui/effect-trial-offer.js +0 -2
  316. package/dist/ui/effect-trial-panel.js +0 -40
  317. package/dist/ui/effects-waker.js +0 -2
  318. package/dist/ui/settings-effects.js +0 -202
  319. package/dist/ui/settings-owner-effects.js +0 -82
  320. package/dist/ui/shared/effect-app-runtime.js +0 -299
  321. package/dist/ui/shared/effect-baseline.js +0 -64
  322. package/dist/ui/shared/effect-chat-runtime.js +0 -162
  323. package/dist/ui/shared/effect-cursor.js +0 -126
  324. package/dist/ui/shared/effect-display-metadata.js +0 -39
  325. package/dist/ui/shared/effect-frame.js +0 -146
  326. package/dist/ui/shared/effect-geometry.js +0 -137
  327. package/dist/ui/shared/effect-host-style.js +0 -10
  328. package/dist/ui/shared/effect-owner-regions.js +0 -74
  329. package/dist/ui/shared/effect-owner-source.js +0 -122
  330. package/dist/ui/shared/effect-policy.js +0 -151
  331. package/dist/ui/shared/effect-poster-reader.js +0 -98
  332. package/dist/ui/shared/effect-posters.js +0 -117
  333. package/dist/ui/shared/effect-profiler.js +0 -184
  334. package/dist/ui/shared/effect-profiles.js +0 -65
  335. package/dist/ui/shared/effect-registry.js +0 -545
  336. package/dist/ui/shared/effect-runtime-loader.js +0 -236
  337. package/dist/ui/shared/effect-safety.js +0 -153
  338. package/dist/ui/shared/effect-stock-snapshot.js +0 -43
  339. package/dist/ui/shared/effect-stock-trust.js +0 -217
  340. package/dist/ui/shared/effect-trial-shadow.js +0 -62
  341. package/dist/ui/shared/effect-trial-source.js +0 -103
  342. package/dist/ui/shared/effect-trial-stage.js +0 -170
  343. package/dist/ui/shared/effect-trial.css +0 -40
  344. package/dist/ui/shared/feature-flags.js +0 -127
  345. package/dist/ui/shared/owner-effect-prefs.js +0 -117
  346. package/dist/upgrade-notices.d.ts +0 -17
  347. package/dist/upgrade-notices.js +0 -93
  348. package/dist/upgrade-notices.js.map +0 -1
  349. package/dist/web-effect-bootstrap.d.ts +0 -12
  350. package/dist/web-effect-bootstrap.js +0 -49
  351. package/dist/web-effect-bootstrap.js.map +0 -1
  352. package/dist/web-effect-bundle.d.ts +0 -28
  353. package/dist/web-effect-bundle.js +0 -171
  354. package/dist/web-effect-bundle.js.map +0 -1
  355. package/dist/web-effect-canonical.d.ts +0 -8
  356. package/dist/web-effect-canonical.js +0 -27
  357. package/dist/web-effect-canonical.js.map +0 -1
  358. package/dist/web-effect-library.d.ts +0 -114
  359. package/dist/web-effect-library.js +0 -530
  360. package/dist/web-effect-library.js.map +0 -1
  361. package/dist/web-effect-playback.d.ts +0 -30
  362. package/dist/web-effect-playback.js +0 -71
  363. package/dist/web-effect-playback.js.map +0 -1
  364. package/dist/web-effect-poster.d.ts +0 -8
  365. package/dist/web-effect-poster.js +0 -52
  366. package/dist/web-effect-poster.js.map +0 -1
  367. package/dist/web-effect-profiles.d.ts +0 -118
  368. package/dist/web-effect-profiles.js +0 -181
  369. package/dist/web-effect-profiles.js.map +0 -1
  370. package/dist/web-effect-service.d.ts +0 -93
  371. package/dist/web-effect-service.js +0 -335
  372. package/dist/web-effect-service.js.map +0 -1
  373. package/dist/web-effect-tools.d.ts +0 -48
  374. package/dist/web-effect-tools.js +0 -129
  375. package/dist/web-effect-tools.js.map +0 -1
  376. package/dist/web-effect-trials.d.ts +0 -86
  377. package/dist/web-effect-trials.js +0 -204
  378. package/dist/web-effect-trials.js.map +0 -1
  379. package/dist/web-effect-upload.d.ts +0 -27
  380. package/dist/web-effect-upload.js +0 -185
  381. package/dist/web-effect-upload.js.map +0 -1
  382. package/dist/web-effect-worker.d.ts +0 -8
  383. package/dist/web-effect-worker.js +0 -170
  384. package/dist/web-effect-worker.js.map +0 -1
  385. package/dist/web-effect.d.ts +0 -103
  386. package/dist/web-effect.js +0 -153
  387. package/dist/web-effect.js.map +0 -1
  388. package/dist/web-experimental-http.d.ts +0 -2
  389. package/dist/web-experimental-http.js +0 -12
  390. package/dist/web-experimental-http.js.map +0 -1
  391. package/dist/web-mod-agent.d.ts +0 -50
  392. package/dist/web-mod-agent.js +0 -207
  393. package/dist/web-mod-agent.js.map +0 -1
@@ -1,101 +0,0 @@
1
- import type { Card, Project, ProjectStats } from "./scheduler/task-board.js";
2
- /** Cards listed per section; the rest are counted. */
3
- export declare const SUMMARY_LISTED = 10;
4
- /**
5
- * `defaults.task_board.summary_at`: `"HH:MM"` (24 h) → itself, `"off"` (any case) or not set → null (off); anything
6
- * else → undefined (the validator refuses it; the clock then sends nothing). Off unless set (2.3.0-beta.25, the
7
- * user's call after beta.24's task-board flood, #2425): a fleet that wants the summary names its time.
8
- */
9
- export declare function summaryTime(value: unknown): string | null | undefined;
10
- /** The wall clock at `now` in `zone` ("YYYY-MM-DD", "HH:MM"); a zone the runtime does not know reads as UTC. */
11
- export declare function wallClock(now: Date, zone: string): {
12
- date: string;
13
- time: string;
14
- };
15
- /** When the last summary went out: its local date and the end of the time it covered. */
16
- export interface SummaryMark {
17
- date: string;
18
- until: string;
19
- }
20
- /** The mark on disk (`<dataDir>/task-board-summary.json`); a missing or unreadable file is no mark. */
21
- export declare function summaryMarkFile(path: string): {
22
- read(): SummaryMark | null;
23
- write(mark: SummaryMark): void;
24
- };
25
- export interface SummaryClockDeps {
26
- /** `defaults.task_board.summary_at` as it is now ("HH:MM"), or null when off. Read at every look. */
27
- at(): string | null;
28
- zone(): string;
29
- now(): Date;
30
- mark: {
31
- read(): SummaryMark | null;
32
- write(mark: SummaryMark): void;
33
- };
34
- /** Gather and post the summary of [since, until). */
35
- send(since: Date, until: Date): void;
36
- /** A look that threw (the data directory gone, a board that cannot be read): logged, and the next look tries again. */
37
- failed?(err: unknown): void;
38
- setInterval?(fn: () => void, ms: number): unknown;
39
- clearInterval?(handle: unknown): void;
40
- }
41
- export declare class TaskBoardSummaryClock {
42
- private readonly deps;
43
- private timer;
44
- private first;
45
- constructor(deps: SummaryClockDeps);
46
- /** A look 5 s after start (a summary missed while the fleet was down), then every minute. */
47
- start(): void;
48
- stop(): void;
49
- /** One look: true when a summary was due today and is now handled (sent, or quiet). */
50
- tick(): boolean;
51
- }
52
- export interface ProjectLine {
53
- name: string;
54
- percent: number;
55
- done: number;
56
- total: number;
57
- waiting: number;
58
- blocked: number;
59
- }
60
- export interface BoardSummary {
61
- since: Date;
62
- until: Date;
63
- review: Card[];
64
- blocked: Card[];
65
- done: Card[];
66
- created: Card[];
67
- projects: ProjectLine[];
68
- }
69
- export interface SummaryRead {
70
- /** What waits for the person now (TaskBoard.waitingForPerson): review cards that need them, blocked cards they handed out. */
71
- waiting: Card[];
72
- done: Card[];
73
- created: Card[];
74
- /** Every live main task's project and assignee: a project's line goes to the chats whose instances hold one. */
75
- mains: Array<{
76
- projectId: number | null;
77
- assignee: string | null;
78
- }>;
79
- }
80
- /**
81
- * One chat's summary: the cards `inChat` keeps (by assignee), and the active projects one of its cards' main tasks is
82
- * in, with the project's numbers over all its cards (projectStats).
83
- */
84
- export declare function buildSummary(read: SummaryRead, since: Date, until: Date, opts: {
85
- inChat(assignee: string | null): boolean;
86
- projects: Project[];
87
- stats: Record<string, ProjectStats>;
88
- }): BoardSummary;
89
- /** Nothing waits and nothing moved: no summary that day. */
90
- export declare function isQuiet(s: BoardSummary): boolean;
91
- type T = (key: string, ...args: (string | number)[]) => string;
92
- /**
93
- * The summary as plain text in the fleet's language (no markup: Telegram, Discord and the web chat read it the same).
94
- * `projectOf`: a main task's project name.
95
- */
96
- export declare function renderSummary(s: BoardSummary, opts: {
97
- zone: string;
98
- t: T;
99
- projectOf(card: Card): string | null;
100
- }): string;
101
- export {};
@@ -1,177 +0,0 @@
1
- /**
2
- * #2246 step 3: the task board's daily summary for the person, as taskhall sends it. Once a day at
3
- * `defaults.task_board.summary_at` (the fleet's zone): what waits for their confirmation and what is blocked now, what
4
- * got done and what was opened since the last summary, and each project's progress. Each chat world's General gets the
5
- * cards of its own instances (a card nobody in a world holds goes to the primary one); the web chat's Generals too.
6
- *
7
- * The clock is taskhall's: it looks every minute, sends at most once a calendar day, and a summary missed while the
8
- * fleet was down goes out when it is back that day, covering the time since the last one (at most a week). A quiet day
9
- * (nothing waits, nothing moved) sends nothing. The first summary after this ships waits for the next morning.
10
- */
11
- import { atomicWriteFileSync } from "./atomic-write.js";
12
- import { readFileSync } from "node:fs";
13
- /** Cards listed per section; the rest are counted. */
14
- export const SUMMARY_LISTED = 10;
15
- const WEEK_MS = 7 * 86_400_000;
16
- /**
17
- * `defaults.task_board.summary_at`: `"HH:MM"` (24 h) → itself, `"off"` (any case) or not set → null (off); anything
18
- * else → undefined (the validator refuses it; the clock then sends nothing). Off unless set (2.3.0-beta.25, the
19
- * user's call after beta.24's task-board flood, #2425): a fleet that wants the summary names its time.
20
- */
21
- export function summaryTime(value) {
22
- if (value === undefined || value === null)
23
- return null;
24
- if (typeof value !== "string")
25
- return undefined;
26
- const v = value.trim().toLowerCase();
27
- if (v === "off")
28
- return null;
29
- return /^([01]\d|2[0-3]):[0-5]\d$/.test(v) ? v : undefined;
30
- }
31
- /** The wall clock at `now` in `zone` ("YYYY-MM-DD", "HH:MM"); a zone the runtime does not know reads as UTC. */
32
- export function wallClock(now, zone) {
33
- let wall;
34
- try {
35
- wall = now.toLocaleString("sv-SE", { timeZone: zone, hour12: false });
36
- }
37
- catch {
38
- wall = now.toLocaleString("sv-SE", { timeZone: "UTC", hour12: false });
39
- }
40
- return { date: wall.slice(0, 10), time: wall.slice(11, 16) };
41
- }
42
- /** The mark on disk (`<dataDir>/task-board-summary.json`); a missing or unreadable file is no mark. */
43
- export function summaryMarkFile(path) {
44
- return {
45
- read() {
46
- try {
47
- const m = JSON.parse(readFileSync(path, "utf8"));
48
- return typeof m.date === "string" && typeof m.until === "string" ? { date: m.date, until: m.until } : null;
49
- }
50
- catch {
51
- return null;
52
- }
53
- },
54
- write(mark) { atomicWriteFileSync(path, JSON.stringify(mark) + "\n"); },
55
- };
56
- }
57
- export class TaskBoardSummaryClock {
58
- deps;
59
- timer = null;
60
- first = null;
61
- constructor(deps) {
62
- this.deps = deps;
63
- }
64
- /** A look 5 s after start (a summary missed while the fleet was down), then every minute. */
65
- start() {
66
- if (this.timer)
67
- return;
68
- const every = this.deps.setInterval ?? ((fn, ms) => { const h = setInterval(fn, ms); h.unref?.(); return h; });
69
- const look = () => { try {
70
- this.tick();
71
- }
72
- catch (err) {
73
- this.deps.failed?.(err);
74
- } };
75
- this.timer = every(look, 60_000);
76
- this.first = setTimeout(look, 5_000);
77
- this.first.unref?.();
78
- }
79
- stop() {
80
- if (this.timer)
81
- (this.deps.clearInterval ?? ((h) => clearInterval(h)))(this.timer);
82
- if (this.first)
83
- clearTimeout(this.first);
84
- this.timer = null;
85
- this.first = null;
86
- }
87
- /** One look: true when a summary was due today and is now handled (sent, or quiet). */
88
- tick() {
89
- const at = this.deps.at();
90
- if (!at)
91
- return false;
92
- const now = this.deps.now();
93
- const wall = wallClock(now, this.deps.zone());
94
- if (wall.time < at)
95
- return false;
96
- const last = this.deps.mark.read();
97
- if (last?.date === wall.date)
98
- return false;
99
- // Marked before it is sent: a send that throws does not repeat every minute.
100
- this.deps.mark.write({ date: wall.date, until: now.toISOString() });
101
- if (!last)
102
- return false; // the first day: nothing to look back on yet; the next one covers from now
103
- const since = Math.min(Math.max(Date.parse(last.until) || 0, now.getTime() - WEEK_MS), now.getTime());
104
- this.deps.send(new Date(since), now);
105
- return true;
106
- }
107
- }
108
- /** Main tasks first, then by number. */
109
- const byNumber = (a, b) => (a.kind === b.kind ? 0 : a.kind === "main" ? -1 : 1) || Number(a.code.slice(2)) - Number(b.code.slice(2));
110
- /**
111
- * One chat's summary: the cards `inChat` keeps (by assignee), and the active projects one of its cards' main tasks is
112
- * in, with the project's numbers over all its cards (projectStats).
113
- */
114
- export function buildSummary(read, since, until, opts) {
115
- const mine = (cards) => cards.filter((c) => opts.inChat(c.assignee)).sort(byNumber);
116
- const here = new Set(read.mains.filter((m) => m.projectId !== null && opts.inChat(m.assignee)).map((m) => m.projectId));
117
- return {
118
- since, until,
119
- review: mine(read.waiting.filter((c) => c.status === "review")),
120
- blocked: mine(read.waiting.filter((c) => c.status === "blocked")),
121
- done: mine(read.done),
122
- created: mine(read.created),
123
- projects: opts.projects.filter((p) => !p.archived && here.has(p.id)).flatMap((p) => {
124
- const st = opts.stats[String(p.id)];
125
- return st && st.mains ? [{ name: p.name, percent: st.percent, done: st.units.done, total: st.units.total, waiting: st.waiting, blocked: st.blocked }] : [];
126
- }),
127
- };
128
- }
129
- /** Nothing waits and nothing moved: no summary that day. */
130
- export function isQuiet(s) {
131
- return !s.review.length && !s.blocked.length && !s.done.length && !s.created.length;
132
- }
133
- const short = (s, n) => (Array.from(s).length > n ? Array.from(s).slice(0, n - 1).join("") + "…" : s);
134
- /** `M/D HH:MM` in the fleet's zone. */
135
- function shortTime(d, zone) {
136
- const { date, time } = wallClock(d, zone);
137
- return `${Number(date.slice(5, 7))}/${Number(date.slice(8, 10))} ${time}`;
138
- }
139
- /**
140
- * The summary as plain text in the fleet's language (no markup: Telegram, Discord and the web chat read it the same).
141
- * `projectOf`: a main task's project name.
142
- */
143
- export function renderSummary(s, opts) {
144
- const { t } = opts;
145
- const ref = (c) => t("board_summary.card", c.code, short(c.title, 30))
146
- + (c.kind === "main" ? (opts.projectOf(c) ? ` · ${opts.projectOf(c)}` : "") : c.assignee ? ` @${c.assignee}` : "");
147
- const list = (cards, line) => {
148
- const out = cards.slice(0, SUMMARY_LISTED).map((c) => `• ${line(c)}`);
149
- if (cards.length > SUMMARY_LISTED)
150
- out.push(`• ${t("board_summary.more", cards.length - SUMMARY_LISTED)}`);
151
- return out;
152
- };
153
- // Finished and new: a main task a line each, sub tasks folded into one line of numbers.
154
- const folded = (cards) => {
155
- const mains = cards.filter((c) => c.kind === "main"), subs = cards.filter((c) => c.kind === "sub");
156
- const out = list(mains, ref);
157
- if (subs.length) {
158
- const codes = subs.slice(0, SUMMARY_LISTED).map((c) => c.code).join(t("board_summary.join"));
159
- out.push(`• ${t(subs.length > SUMMARY_LISTED ? "board_summary.subs_more" : "board_summary.subs", subs.length, codes)}`);
160
- }
161
- return out;
162
- };
163
- const blocks = [t("board_summary.title", shortTime(s.since, opts.zone), shortTime(s.until, opts.zone))];
164
- const section = (title, lines) => { if (lines.length)
165
- blocks.push([title, ...lines].join("\n")); };
166
- section(t("board_summary.review", s.review.length), list(s.review, ref));
167
- section(t("board_summary.blocked", s.blocked.length), list(s.blocked, (c) => ref(c) + (c.kind === "main" && c.assignee ? ` @${c.assignee}` : "") + (c.blockedReason ? t("board_summary.reason", short(c.blockedReason, 60)) : "")));
168
- section(t("board_summary.done", s.done.length), folded(s.done));
169
- section(t("board_summary.created", s.created.length), folded(s.created));
170
- section(t("board_summary.projects"), s.projects.map((p) => {
171
- const extra = [p.waiting ? t("board_summary.project_waiting", p.waiting) : "", p.blocked ? t("board_summary.project_blocked", p.blocked) : ""].filter(Boolean);
172
- return `• ${t("board_summary.project", p.name, p.percent, p.done, p.total)}${extra.length ? t("board_summary.project_extra", extra.join(t("board_summary.join"))) : ""}`;
173
- }));
174
- blocks.push(t("board_summary.footer"));
175
- return blocks.join("\n\n");
176
- }
177
- //# sourceMappingURL=task-board-summary.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"task-board-summary.js","sourceRoot":"","sources":["../src/task-board-summary.ts"],"names":[],"mappings":"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"}
@@ -1,251 +0,0 @@
1
- /** #1629: one session-only app effect owner. Importing this module starts nothing. */
2
- import { appStore } from "/assets/app-store.js";
3
- import { motionBlocked, onMotionChange } from "/assets/fx-motion.js";
4
- import { navStore } from "/assets/app-nav.js";
5
- import { onPrefsChanged } from "/assets/app-prefs.js";
6
- import { resolvedMode, themesStore, themesShown } from "/assets/app-themes.js";
7
- import { ownerCssLifecycle, safeMode } from "/assets/owner-css.js";
8
- import { canvasWorkerEnabled } from "/assets/feature-flags.js";
9
- import { constrainedDevice } from "/assets/effect-policy.js";
10
- import { createAppEffectRuntime } from "/assets/effect-app-runtime.js";
11
- import { effectBootstrapReady } from "/assets/effect-frame.js";
12
- import { createEffectCursor } from "/assets/effect-cursor.js";
13
- import { createOwnerEffectRegions } from "/assets/effect-owner-regions.js";
14
- import { chatEffectIdentity, effectPlaybackIdentity } from "/assets/effect-chat-runtime.js";
15
- import { createEffectTrialController } from "./effect-trial-controller.js";
16
- import { effectTrialMessage } from "./effect-trial-offer.js";
17
- import { claimPanel, panelVersion, panelStore, openTrialPanel, closePanel } from "./preview-panel.js";
18
- const owners = new WeakMap();
19
- export function getAppEffects(host = window) { const value = owners.get(host); return value && !value.dead && value.api?.ok ? value : null; }
20
-
21
- /** Boot once with the page's Chat store, including when the first visible panel is Fleet. */
22
- export function startAppEffects({ store, window: host = window, factories = {} } = {}) {
23
- if (!canvasWorkerEnabled()) return null;
24
- const existing = owners.get(host);
25
- if (existing) { if (!existing.dead) existing.bindStore(store); return getAppEffects(host); }
26
- const playbackIdentity = effectPlaybackIdentity(host), ownerIdentity = chatEffectIdentity(host);
27
- if (!playbackIdentity || typeof host.AgendAuth?.onSessionEnd !== "function" || typeof host.AgendAuth?.sessionEnded !== "function") return null;
28
- const doc = host.document, releases = [], ended = new Set(), updates = new Set(), trialUpdates = new Set(); let replyOff = null, replyStore = null, regions = null, cursor = null, cursorStamp = null, trialControl = null, trialIntent = null, trialHint = ownerIdentity ? null : false, trialSerial = 0, trialStamp = null, chatBinding = null;
29
- const safe = fn => { try { return fn(); } catch { return null; } };
30
- const hold = off => { if (entry.dead) safe(() => off?.()); else releases.push(off); };
31
- const entry = { dead: false, api: null, disposed: null,
32
- cursorSnapshot: () => cursor?.snapshot() ?? { status: "unavailable", id: null },
33
- gates: () => context(),
34
- subscribe(fn) { if (typeof fn !== "function" || entry.dead) return () => {}; updates.add(fn); return () => updates.delete(fn); },
35
- subscribeTrial(fn) { if (typeof fn !== "function" || entry.dead) return () => {}; trialUpdates.add(fn); return () => trialUpdates.delete(fn); },
36
- onEnd(fn) { if (typeof fn !== "function") return () => {}; if (entry.dead) { safe(fn); return () => {}; } ended.add(fn); return () => ended.delete(fn); },
37
- bindStore(value) {
38
- if (entry.dead || value === replyStore) return;
39
- safe(() => replyOff?.()); replyOff = null; replyStore = value;
40
- trialControl?.stop(); chatBinding = null; entry.api?.detachChat();
41
- if (typeof value?.onAgentReply === "function") {
42
- const off = value.onAgentReply(event => { if (!entry.dead && replyStore === value) entry.api?.reply(event); });
43
- if (entry.dead || replyStore !== value) safe(() => off?.()); else replyOff = off;
44
- }
45
- },
46
- trialStatus(message) {
47
- const offer = safe(() => effectTrialMessage(message)), nav = navStore.get();
48
- const now = safe(() => host.Date.now());
49
- if (!offer || !Number.isFinite(now) || now >= offer.expiresAt) return "expired";
50
- if (trialHint === null && !entry.dead) return "checking";
51
- if (entry.dead || !trialHint || trialControl?.ok !== true) return "localAdmin";
52
- if (!chatBinding || safe(() => chatBinding.current()) !== true || message.instance !== nav.route?.instance || nav.route?.panel !== "chat") return "chatChanged";
53
- const state = trialControl.snapshot();
54
- if (state.phase !== "idle" || state.busy) return "busy";
55
- return trialPlaybackStatus();
56
- },
57
- trialFailure(message) {
58
- const offer = safe(() => effectTrialMessage(message)), state = trialControl?.snapshot();
59
- return offer && state?.phase === "idle" && state.offer === offer.offer && !["stopped", "replaced"].includes(state.reason) ? state.reason : null;
60
- },
61
- canTry(message) { return entry.trialStatus(message) === "ready"; },
62
- stopTrial() { trialControl?.stop(); },
63
- startTrial(message) {
64
- if (!entry.canTry(message)) return Promise.resolve(false);
65
- const nav = navStore.get(); trialIntent = { name: message.instance, seq: nav.seq, claim: claimPanel(), handle: null, chat: chatBinding };
66
- return trialControl.start(message);
67
- },
68
- attachChat(options) {
69
- const nav = navStore.get(), name = options?.name;
70
- if (entry.dead || !entry.api?.ok || nav.route?.panel !== "chat" || nav.route.instance !== name || typeof options.current !== "function") return null;
71
- const binding = { current: () => !entry.dead && host.document === doc && navStore.get().seq === nav.seq && navStore.get().route?.panel === "chat" && navStore.get().route?.instance === name && options.current() === true };
72
- chatBinding = binding; trialControl?.stop();
73
- if (entry.dead || chatBinding !== binding) return null;
74
- const handle = entry.api.attachChat({ ...options, current: () => chatBinding === binding && binding.current() });
75
- if (entry.dead || chatBinding !== binding) { safe(() => handle?.dispose()); return null; }
76
- if (!handle) chatBinding = null;
77
- return handle;
78
- },
79
- dispose(restartable = false) {
80
- if (entry.dead) return entry.disposed; entry.dead = true;
81
- if (restartable && owners.get(host) === entry) owners.delete(host);
82
- safe(() => trialControl?.dispose()); const coreDisposed = safe(() => entry.api?.dispose(restartable === true)); safe(() => replyOff?.()); replyOff = null; replyStore = null;
83
- for (const off of releases.splice(0)) safe(off);
84
- updates.clear(); trialUpdates.clear(); const listeners = [...ended]; ended.clear(); for (const fn of listeners) safe(fn);
85
- entry.disposed = Promise.all([coreDisposed, safe(() => cursor?.whenDisposed?.())]);
86
- return entry.disposed;
87
- },
88
- };
89
- owners.set(host, entry); // Reentrant setup never constructs another owner.
90
- let media, coarse;
91
- function ownerCssForPlayback() {
92
- if (doc.body.dataset.tier !== "guest") return ownerCssLifecycle.get().state;
93
- // Guests never install owner CSS. Prove its absence rather than borrowing the uninstalled
94
- // lifecycle's initial unknown, and refuse unexpected styles instead of trusting a missing id.
95
- try {
96
- if (doc.body.dataset.ownerCss || doc.querySelectorAll("#owner-css").length) return "unknown";
97
- // A CSP-refused or disabled STYLE has no paint. Recheck on every proof so enabling
98
- // it never borrows an earlier absence verdict (WebKit capture inserts a refused no-op).
99
- for (const style of doc.querySelectorAll("style")) if (style.sheet && style.sheet.disabled !== true) return "unknown";
100
- const allowed = new Set(["/assets/tokens.css", "/assets/app.css"]);
101
- for (const link of doc.querySelectorAll('link[rel~="stylesheet"]')) {
102
- const url = new URL(link.getAttribute("href"), host.location.origin);
103
- if (url.origin !== host.location.origin || !allowed.has(url.pathname) || url.search || url.hash) return "unknown";
104
- }
105
- return "off";
106
- } catch { return "unknown"; }
107
- }
108
- function guestChatVersion(value) {
109
- if (doc.body.dataset.tier !== "guest") return null;
110
- const name = navStore.get().route?.instance, v = value.instances?.find(i => i.name === name)?.effect_chat_v;
111
- return typeof v === "string" && /^[a-f0-9]{32}$/.test(v) ? v : null;
112
- }
113
- // #2188: whether a dialog, menu or popover is open — a whole-document query when none is (the usual case), asked
114
- // several times per sync. Read once per task: the cached value is dropped at the next microtask, and whenever the
115
- // document changes (the MutationObserver below drops it before it reads).
116
- let modalCache = null;
117
- function modalOpen() {
118
- if (modalCache === null) {
119
- modalCache = !!doc.querySelector("dialog[open],.menu-list,.pop,[role=alertdialog],.oc-keep,.shell.sb-open");
120
- Promise.resolve().then(() => { modalCache = null; });
121
- }
122
- return modalCache;
123
- }
124
- function context() {
125
- return { safe: safeMode(), publicLink: doc.body.dataset.publicLink === "1", reducedMotion: motionBlocked(host), saveData: host.navigator?.connection?.saveData === true,
126
- hidden: doc.visibilityState !== "visible", enabled: entry.api?.playbackAvailable !== false && typeof host.OffscreenCanvas === "function" && typeof host.Worker === "function" && typeof host.MutationObserver === "function" && typeof host.ResizeObserver === "function",
127
- show: themesShown(), transportReady: effectBootstrapReady(host, host.location?.origin, doc.body.dataset.effectBoot),
128
- constrained: constrainedDevice({ memory: host.navigator?.deviceMemory, cores: host.navigator?.hardwareConcurrency, coarse: coarse?.matches === true, width: host.innerWidth }),
129
- modal: modalOpen(), openInstance: null };
130
- }
131
- function trialCurrent(name) {
132
- const intent = trialIntent, nav = navStore.get();
133
- return !entry.dead && host.document === doc && !!intent && !!intent.chat && chatBinding === intent.chat && intent.chat.current() === true && intent.name === name && nav.seq === intent.seq && nav.route?.panel === "chat" && nav.route.instance === name
134
- && (panelVersion() === intent.claim || intent.handle !== null && panelStore.get().open?.handle === intent.handle);
135
- }
136
- // One priority order feeds both presentation and redraw identity: false→different-false must redraw.
137
- function trialPlaybackStatus() {
138
- const c = context();
139
- if (c.safe) return "safe";
140
- if (!c.show) return "effectsOff";
141
- if (c.reducedMotion) return "reducedMotion";
142
- if (!c.enabled) return "unsupported";
143
- if (!c.transportReady) return "transport";
144
- if (c.publicLink) return "localAdmin";
145
- if (c.hidden || doc.hasFocus?.() !== true) return "inactive";
146
- if (c.modal) return "dialog";
147
- return "ready";
148
- }
149
- function trialAllowed() {
150
- const c = context();
151
- return !entry.dead && doc.visibilityState === "visible" && doc.hasFocus?.() === true
152
- && c.enabled && c.show && c.transportReady && !c.safe && !c.publicLink && !c.reducedMotion && !c.hidden && !c.modal;
153
- }
154
- function mountTrial(handle) {
155
- const intent = trialIntent; if (!intent || !trialCurrent(handle.instance) || !handle.current() || !Number.isSafeInteger(++trialSerial)) throw Error("trial_unavailable");
156
- intent.handle = handle;
157
- const binding = Object.freeze({ key: `trial:${trialSerial}:${handle.reply.trial}`, id: handle.reply.offer.id, run: handle.reply.trial, instance: handle.instance, generation: trialSerial });
158
- let stage = null, source = null;
159
- const cleanup = () => {
160
- safe(() => source?.stop()); safe(() => stage?.dispose());
161
- if (panelStore.get().open?.handle === handle) closePanel();
162
- };
163
- try {
164
- openTrialPanel({ key: binding.key, instance: handle.instance, binding, handle,
165
- onStage(value) {
166
- stage = value;
167
- if (!handle.current()) { cleanup(); handle.stop(); return; }
168
- source = entry.api.attachTrial({ reply: handle.reply, offer: handle.reply.offer.offer, startedAt: handle.startedAt, stage,
169
- current: handle.current, onStop: handle.stop });
170
- if (!source) { cleanup(); handle.stop(); }
171
- },
172
- });
173
- } catch (error) { cleanup(); throw error; }
174
- return cleanup;
175
- }
176
- function notifyTrial() {
177
- if (entry.dead) return;
178
- const nav = navStore.get(), next = JSON.stringify([trialHint, safe(() => chatBinding?.current()) === true, trialPlaybackStatus(), nav.route?.panel, nav.route?.instance, trialControl?.snapshot()]);
179
- if (next === trialStamp) return; trialStamp = next;
180
- for (const fn of [...trialUpdates]) safe(fn);
181
- }
182
- const notify = () => { if (!entry.dead) { trialControl?.sync(); notifyTrial(); for (const fn of [...updates]) safe(fn); } };
183
- const cursorDragging = () => doc.body.classList?.contains("side-resizing") === true || !!doc.querySelector(".chat-split.resizing");
184
- function syncCursor() {
185
- if (entry.dead || !cursor) return;
186
- const c = context();
187
- cursor.update(entry.api?.cursorSelection?.() ?? null, c.enabled && c.show && c.transportReady && !c.safe && !c.publicLink && !c.reducedMotion && !c.hidden && !c.modal && !cursorDragging());
188
- }
189
- try {
190
- if (appStore.get().connection === "ended") { entry.dispose(); return null; }
191
- media = host.matchMedia?.("(prefers-reduced-motion: reduce)") ?? { matches: true };
192
- coarse = host.matchMedia?.("(pointer: coarse)") ?? { matches: false };
193
- entry.api = (factories.runtime ?? createAppEffectRuntime)({ window: host, current: () => !entry.dead && host.document === doc,
194
- observe: () => ({ context: context(), ownerCss: ownerCssForPlayback(), mode: resolvedMode() }), onDispose: () => entry.dispose(),
195
- resolveOwnerTarget: (slot, manifest, proof) => !entry.dead ? regions?.resolve?.(slot, manifest.box, proof) ?? null : null,
196
- onChange: () => { syncCursor(); notify(); } });
197
- if (entry.dead || !entry.api.ok) { entry.dispose(); return null; }
198
- if (ownerIdentity) trialControl = (factories.trialController ?? createEffectTrialController)({ window: host, current: trialCurrent, allowed: trialAllowed, onStart: mountTrial, onChange: notify });
199
- hold(() => trialControl?.dispose());
200
- if (ownerIdentity && typeof host.AgendAuth.trialSession === "function") Promise.resolve().then(() => host.AgendAuth.trialSession()).then(value => {
201
- if (entry.dead) return; trialHint = value?.localAdmin === true && value.epoch === chatEffectIdentity(host)?.epoch; notify();
202
- }).catch(() => { if (!entry.dead) { trialHint = false; notify(); } });
203
- hold(panelStore.subscribe(() => { trialControl?.sync(); notifyTrial(); }));
204
- const ownRegions = ownerIdentity && (factories.regions ?? createOwnerEffectRegions)({ window: host, current: () => !entry.dead && host.document === doc });
205
- regions = ownRegions?.ok ? ownRegions : null; hold(() => ownRegions?.dispose?.());
206
- if (entry.dead) return null;
207
- const ownCursor = ownerIdentity && safe(() => (factories.cursor ?? createEffectCursor)({ window: host, current: () => !entry.dead && host.document === doc,
208
- readImage: (selection, signal) => entry.api?.cursorImageSettled?.(selection, signal) ?? Promise.resolve(null),
209
- onChange(value) { const next = JSON.stringify(value); if (next !== cursorStamp) { cursorStamp = next; notify(); } },
210
- }));
211
- cursor = ownCursor?.ok ? ownCursor : null; hold(() => ownCursor?.dispose?.());
212
- if (entry.dead) return null;
213
- const sync = () => { if (!entry.dead) { trialControl?.sync(); entry.api.sync(); syncCursor(); notifyTrial(); } };
214
- let revision = appStore.get().themesRev, prefsRevision = appStore.get().prefsRev, guestRevision = guestChatVersion(appStore.get()), navSeq = navStore.get().seq;
215
- hold(navStore.subscribe(value => { if (entry.dead || value.seq === navSeq) return; navSeq = value.seq; trialControl?.stop(); chatBinding = null; entry.api.detachChat(); syncCursor(); }));
216
- hold(appStore.subscribe(value => {
217
- if (entry.dead) return;
218
- if (!canvasWorkerEnabled()) { entry.dispose(true); return; }
219
- if (value.connection === "ended") { entry.dispose(); return; }
220
- const guestNext = guestChatVersion(value), chatChanged = value.themesRev !== revision || guestNext !== guestRevision, ownerChanged = value.prefsRev !== prefsRevision;
221
- revision = value.themesRev; prefsRevision = value.prefsRev; guestRevision = guestNext;
222
- if (chatChanged) entry.api.changedChat();
223
- if (ownerChanged) entry.api.changedOwner();
224
- if (!chatChanged && !ownerChanged) sync();
225
- }));
226
- hold(ownerCssLifecycle.subscribe(sync)); hold(themesStore.subscribe(sync)); hold(onPrefsChanged(sync)); hold(onMotionChange(sync));
227
- if (typeof host.AgendTheme?.onChange === "function") hold(host.AgendTheme.onChange(sync));
228
- for (const [target, type] of [[media, "change"], [coarse, "change"], [doc, "visibilitychange"], [host, "resize"], [host.navigator?.connection, "change"]]) {
229
- if (target?.addEventListener) { target.addEventListener(type, sync); hold(() => target.removeEventListener(type, sync)); }
230
- }
231
- if (entry.dead) return null;
232
- let modal = context().modal, dragging = cursorDragging(), queuedSurface = false;
233
- // Panel commits can happen after navigation and contain no Chat lease. Reproject fixed owner targets
234
- // once after stock DOM changes. Body-level effect roots/frames/rules do not schedule themselves.
235
- const surfaceChanged = () => {
236
- if (entry.dead || queuedSurface) return; queuedSurface = true;
237
- Promise.resolve().then(() => { queuedSurface = false; sync(); });
238
- };
239
- const barriers = typeof host.MutationObserver === "function" ? new host.MutationObserver(records => {
240
- if (entry.dead) return;
241
- modalCache = null; // the document changed: a dialog may have opened or closed (read it again)
242
- const value = context().modal, drag = cursorDragging(); if (value !== modal || drag !== dragging) { modal = value; dragging = drag; sync(); }
243
- if (Array.isArray(records) && records.some(r => r.target?.closest?.("#app") || r.target === doc.getElementById?.("app"))) surfaceChanged();
244
- }) : null;
245
- hold(() => barriers?.disconnect());
246
- if (entry.dead) return null;
247
- barriers?.observe(doc.documentElement, { subtree: true, childList: true, attributes: true, attributeFilter: ["class", "open", "hidden", "role"] });
248
- entry.bindStore(store); sync();
249
- return getAppEffects(host);
250
- } catch { entry.dispose(); return null; }
251
- }
@@ -1,42 +0,0 @@
1
- /** #1629: static Chat fallback. It requires no preview origin, device consent, Worker or personal identity. */
2
- import { useLayoutEffect } from "/assets/app-html.js";
3
- import { appStore } from "/assets/app-store.js";
4
- import { onPrefsChanged } from "/assets/app-prefs.js";
5
- import { themesShown, themesStore } from "/assets/app-themes.js";
6
- import { ownerCssLifecycle } from "/assets/owner-css.js";
7
- import { effectPlaybackIdentity } from "/assets/effect-chat-runtime.js";
8
- import { effectBootstrapReady } from "/assets/effect-frame.js";
9
- import { motionBlocked, onMotionChange } from "/assets/fx-motion.js";
10
- import { createChatPosters } from "/assets/effect-posters.js";
11
-
12
- export function ChatEffectPosters({ name, lease, element }) {
13
- useLayoutEffect(() => {
14
- let live = true, api = null;
15
- const releases = [], host = window;
16
- const current = () => live && lease.current();
17
- const cleanup = () => { if (!live) return; live = false; try { api?.dispose?.(); } catch { /* optional */ } for (const off of releases) { try { off?.(); } catch { /* release all */ } } };
18
- lease.hold(cleanup);
19
- try {
20
- const motion = host.matchMedia?.("(prefers-reduced-motion: reduce)") ?? { matches: true };
21
- const observe = () => {
22
- // This is a surface fallback, not a replacement for an explicit Pause, queued effect or failed live read.
23
- const playback = effectPlaybackIdentity(host) && typeof host.Worker === "function" && typeof host.OffscreenCanvas === "function" &&
24
- effectBootstrapReady(host, host.location?.origin, host.document.body.dataset.effectBoot) && !motionBlocked(host);
25
- return { shown: themesShown(), fallback: !playback, ownerCss: ownerCssLifecycle.get().state };
26
- };
27
- api = createChatPosters({ window: host, name, element: element.current, current, observe });
28
- if (!api.ok) return cleanup;
29
- const sync = () => { if (current()) api.sync(); };
30
- let revision = appStore.get().themesRev;
31
- releases.push(appStore.subscribe(s => {
32
- if (!current()) return;
33
- if (s.connection === "ended") { api.dispose(); return; }
34
- if (s.themesRev !== revision) { revision = s.themesRev; api.changed(); } else sync();
35
- }));
36
- releases.push(ownerCssLifecycle.subscribe(sync)); releases.push(themesStore.subscribe(sync)); releases.push(onPrefsChanged(sync)); releases.push(onMotionChange(sync));
37
- for (const target of [motion, host.navigator?.connection]) if (target?.addEventListener) { target.addEventListener("change", sync); releases.push(() => target.removeEventListener("change", sync)); }
38
- sync(); return cleanup;
39
- } catch { cleanup(); return cleanup; }
40
- }, [name, lease]);
41
- return null;
42
- }