@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,127 +0,0 @@
1
- // Product feature policy only: this module imports no experimental runtime.
2
- import { appStore } from "./app-store.js";
3
- import { navStore } from "./app-nav.js";
4
- import { ownerEffectsChosen, onOwnerEffectsChanged } from "./app-prefs.js";
5
- import { register } from "./app-i18n.js";
6
- import { html, useEffect, useState } from "./app-html.js";
7
- register("cwControls", { en: { title: "Effects" }, "zh-TW": { title: "效果" } });
8
- export function canvasWorkerEnabled() { return appStore.get().canvasWorker === true; }
9
- export function onCanvasWorkerChange(fn) {
10
- let value = canvasWorkerEnabled();
11
- return appStore.subscribe(() => { const next = canvasWorkerEnabled(); if (next !== value) { value = next; fn(next); } });
12
- }
13
- export function useCanvasWorker() {
14
- const [value, setValue] = useState(canvasWorkerEnabled);
15
- useEffect(() => { setValue(canvasWorkerEnabled()); return onCanvasWorkerChange(setValue); }, []);
16
- return value;
17
- }
18
- // Never evaluate the optional module before admission. An obsolete import may finish, but cannot mount.
19
- export function experimentalComponent(load, select) {
20
- return function ExperimentalComponent(props) {
21
- const enabled = useCanvasWorker(), [component, setComponent] = useState(null);
22
- useEffect(() => {
23
- let current = true;
24
- if (enabled) load().then(module => { if (current && canvasWorkerEnabled()) setComponent(() => select(module)); }, () => {});
25
- return () => { current = false; };
26
- }, [enabled]);
27
- return enabled && component ? html`<${component} ...${props} />` : null;
28
- };
29
- }
30
-
31
- /** effect_chat_v of a chat with no placements: sha256(JSON.stringify([])), first 32 hex (fleet-manager's status row). */
32
- export const EMPTY_CHAT_EFFECTS = "4f53cda18c2baa0c0354bb5f9a3ecbe5";
33
-
34
- let mod = null, waking = null, chatStore = null, started = false, generation = 0, awakeGeneration = -1, retiring = Promise.resolve();
35
- const awakeListeners = new Set();
36
-
37
- /** Whether `name`'s chat has Canvas Worker placements (as the status rows say). */
38
- export function chatHasEffects(name, app = appStore.get()) {
39
- const v = name ? app.instances?.find(i => i.name === name)?.effect_chat_v : undefined;
40
- return canvasWorkerEnabled() && typeof v === "string" && /^[a-f0-9]{32}$/.test(v) && v !== EMPTY_CHAT_EFFECTS;
41
- }
42
-
43
- /** The running effects owner, or null while dormant (or when it could not start: as getAppEffects always was). */
44
- export function getAppEffects(host) { return canvasWorkerEnabled() && mod ? mod.getAppEffects(host) : null; }
45
-
46
- /** Whether the runtime has been asked to start on this page. */
47
- export function effectsAwake() { return waking !== null; }
48
- /** Whether its module has loaded (started, or found it could not: getAppEffects() then says which). */
49
- export function effectsLoaded() { return mod !== null && awakeGeneration === generation; }
50
-
51
- /** Follow every completed runtime episode, including a replacement after an experimental off/on. */
52
- export function onEffectsAwake(fn) {
53
- if (typeof fn !== "function") return () => {};
54
- awakeListeners.add(fn);
55
- if (effectsLoaded()) { try { fn(); } catch { /* a listener's error is its own */ } }
56
- return () => awakeListeners.delete(fn);
57
- }
58
-
59
- /** Load lazily; each explicitly enabled episode owns its startup and cancellation. */
60
- export function wakeEffects() {
61
- if (!canvasWorkerEnabled()) return Promise.resolve(null);
62
- if (waking) return waking;
63
- const episode = generation;
64
- waking = (mod ? Promise.resolve(mod) : import("/ui/js/app-effects.js")).then(async m => {
65
- mod = m;
66
- await retiring;
67
- if (episode !== generation || !canvasWorkerEnabled()) return null;
68
- const owner = chatStore ? m.startAppEffects({ store: chatStore }) : null;
69
- awakeGeneration = episode;
70
- for (const fn of [...awakeListeners]) { try { fn(); } catch { /* the rest still hear */ } }
71
- return owner;
72
- }, () => null);
73
- return waking;
74
- }
75
-
76
- /** Wake when the open chat has placements or the person has a personal effect. */
77
- function check() {
78
- if (!canvasWorkerEnabled()) {
79
- generation++;
80
- const owner = mod?.getAppEffects();
81
- if (owner) retiring = Promise.resolve(owner.dispose?.(true));
82
- waking = null;
83
- return;
84
- }
85
- if (waking) return;
86
- const route = navStore.get().route;
87
- if ((route?.panel === "chat" && chatHasEffects(route.instance)) || ownerEffectsChosen()) void wakeEffects();
88
- }
89
-
90
- /** Boot (once per page, with the Chat store the runtime binds to). Starts nothing but the watch. */
91
- export function startEffectsWaker({ store }) {
92
- chatStore = store;
93
- if (started) return;
94
- started = true;
95
- appStore.subscribe(check); navStore.subscribe(check); onOwnerEffectsChanged(check);
96
- check();
97
- }
98
-
99
- // Full Canvas Worker metadata stays in the experimental graph, never in ordinary chat boot.
100
- let metadata = null, metadataPending = null;
101
- const metadataListeners = new Set();
102
- export function onCanvasMetadataChange(fn) { metadataListeners.add(fn); return () => metadataListeners.delete(fn); }
103
- export function loadCanvasWorkerMetadata() {
104
- if (!canvasWorkerEnabled()) return Promise.resolve(null);
105
- if (metadata) return Promise.resolve(metadata);
106
- if (metadataPending?.episode === generation) return metadataPending.promise;
107
- const episode = generation, op = { episode, promise: null };
108
- metadataPending = op;
109
- op.promise = import("./effect-display-metadata.js").then(value => {
110
- if (episode !== generation || !canvasWorkerEnabled()) return null;
111
- metadata = value;
112
- for (const fn of [...metadataListeners]) { try { fn(); } catch { /* independent viewers */ } }
113
- appStore.set({ canvasMetadataEpoch: episode });
114
- return metadata;
115
- }, () => null).finally(() => { if (metadataPending === op) metadataPending = null; });
116
- return op.promise;
117
- }
118
- export function readCanvasTrialMessage(message) {
119
- if (!canvasWorkerEnabled()) return null;
120
- if (!metadata) { void loadCanvasWorkerMetadata(); return undefined; }
121
- return metadata.effectTrialMessage(message);
122
- }
123
- export function canvasWorkerMenuAvailable(host) {
124
- if (!canvasWorkerEnabled()) return false;
125
- if (!metadata) { void loadCanvasWorkerMetadata(); return false; }
126
- return metadata.chatEffectIdentity(host) !== null;
127
- }
@@ -1,117 +0,0 @@
1
- // #1629: host-authoritative personal choices. No local cache, migration, frame, code fetch or automatic resend.
2
- import { createStore, appStore } from "./app-store.js";
3
- import { OWNER_EFFECT_PREF_KEYS } from "./app-prefs.js";
4
- import { checkEffectOwnerSlots } from "./effect-runtime-loader.js";
5
- const KEYS = OWNER_EFFECT_PREF_KEYS, ID = /^[a-f0-9]{32}$/, EPOCH = /^[a-f0-9]{16}$/;
6
- const plain = x => !!x && typeof x === "object" && Object.getPrototypeOf(x) === Object.prototype;
7
- const own = (x, k) => Object.hasOwn(x, k);
8
- const unknownSlots = () => Object.fromEntries(KEYS.map(k => [k, { status: "unknown", id: null }]));
9
- const publicPage = () => typeof document === "undefined" || document.body?.dataset.publicLink === "1" || document.body?.dataset.mode === "view-only";
10
- function bootScope() {
11
- try {
12
- const x = JSON.parse(document.documentElement.getAttribute("data-prefs") || "null");
13
- return plain(x) && ["person", "operator"].includes(x.ownerScope) && typeof x.ownerEpoch === "string" && EPOCH.test(x.ownerEpoch)
14
- ? Object.freeze({ scope: x.ownerScope, epoch: x.ownerEpoch }) : null;
15
- } catch { return null; }
16
- }
17
- const owner = bootScope();
18
- export const ownerEffectsStore = createStore({ scope: owner?.scope ?? "none", status: "unknown", revoked: false, busy: false, slots: unknownSlots(), error: null });
19
- let watchers = 0, generation = 0, active = null, queuedRead = false, unsubscribe = null, rev = -1, seen = null, failedAt = -Infinity;
20
- const clock = () => { try { const n = performance.now(); return Number.isFinite(n) && n >= 0 ? n : null; } catch { return null; } };
21
- const eligible = () => !!owner && watchers > 0 && !publicPage() && !ownerEffectsStore.get().revoked;
22
- const current = op => eligible() && op.generation === generation && active === op;
23
- function revoke() {
24
- queuedRead = false;
25
- ownerEffectsStore.set({ status: "unknown", revoked: true, slots: unknownSlots(), error: "sign_in_changed" });
26
- }
27
- function unknown(error) { const n = clock(); failedAt = n === null ? Infinity : n; ownerEffectsStore.set({ status: "unknown", slots: unknownSlots(), error }); }
28
- function claim() {
29
- if (!eligible() || active) return null;
30
- const controller = new AbortController(), op = { controller, generation };
31
- active = op; ownerEffectsStore.set({ busy: true, error: null }); return op;
32
- }
33
- async function call(op, path, init = {}) {
34
- const started = clock();
35
- if (started === null || op.controller.signal.aborted) return { ok: false, status: 0, body: null };
36
- const timer = setTimeout(() => op.controller.abort(), 10000);
37
- try {
38
- const res = await fetch(path, { credentials: "same-origin", ...init, signal: op.controller.signal });
39
- let body = null; try { body = await res.json(); } catch { /* unknown */ }
40
- const ended = clock();
41
- if (op.controller.signal.aborted || ended === null || ended < started || ended - started >= 10000) return { ok: false, status: 0, body: null };
42
- return { ok: res.ok, status: res.status, body };
43
- } catch { return { ok: false, status: 0, body: null }; }
44
- finally { clearTimeout(timer); }
45
- }
46
- function finish(op) {
47
- if (active !== op) return;
48
- active = null; ownerEffectsStore.set({ busy: false });
49
- const again = queuedRead; queuedRead = false;
50
- const n = clock();
51
- if (again && eligible() && n !== null && n - failedAt >= 5000) refreshOwnerEffects();
52
- }
53
- /** An owner response is closed and bounded. Unavailable means a stored id, not an empty slot or private manifest. */
54
- export function checkOwnerSlots(body) { return checkEffectOwnerSlots(body); }
55
-
56
- async function read(op) {
57
- const r = await call(op, `/ui/effects/owner?ownerEpoch=${owner.epoch}`);
58
- if (!current(op)) return false;
59
- if ([401, 403, 409].includes(r.status)) { revoke(); return false; }
60
- const data = r.ok ? checkOwnerSlots(r.body) : null;
61
- if (!data) { unknown("unreadable"); return false; }
62
- if (data.rev < rev) { unknown("stale"); return false; }
63
- rev = data.rev; failedAt = -Infinity;
64
- ownerEffectsStore.set({ status: "known", slots: data.slots, error: null }); return true;
65
- }
66
- export async function refreshOwnerEffects() {
67
- if (!eligible()) return false;
68
- if (active) { queuedRead = true; return false; }
69
- const op = claim(); if (!op) return false;
70
- try { return await read(op); } finally { finish(op); }
71
- }
72
- /** One physical operation survives until settlement, including after abort. At most one coalesced read follows. */
73
- export function watchOwnerEffects() {
74
- watchers++;
75
- if (watchers === 1 && eligible()) {
76
- const check = () => {
77
- const next = appStore.get().prefsRev, n = clock();
78
- if (next !== seen || ownerEffectsStore.get().status === "unknown" && n !== null && n - failedAt >= 5000) { seen = next; refreshOwnerEffects(); }
79
- };
80
- unsubscribe = appStore.subscribe(check); check();
81
- }
82
- let ended = false;
83
- return () => {
84
- if (ended) return; ended = true;
85
- if (--watchers > 0) return;
86
- generation++; queuedRead = false; unsubscribe?.(); unsubscribe = null; active?.controller.abort();
87
- ownerEffectsStore.set({ status: "unknown", slots: unknownSlots(), error: null });
88
- };
89
- }
90
- export async function saveOwnerEffects(set) {
91
- if (!plain(set) || !Object.keys(set).length || Object.keys(set).some(k => !KEYS.includes(k) || set[k] !== null && (typeof set[k] !== "string" || !ID.test(set[k])))) return { ok: false, error: "invalid" };
92
- // Snapshot both data and immutable boot context before the first wait. No optimistic runtime selection.
93
- const values = { ...set }, op = claim(); if (!op) return { ok: false, error: "busy_or_unavailable" };
94
- let saved = false;
95
- try {
96
- const r = await call(op, "/ui/prefs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ set: values, ownerEpoch: owner.epoch }) });
97
- if (!current(op)) return { ok: false, error: "superseded" };
98
- if ([401, 403, 409].includes(r.status)) { revoke(); return { ok: false, error: "sign_in_changed" }; }
99
- if (r.ok && plain(r.body) && (r.body.ownerEpoch !== owner.epoch || r.body.ownerScope !== owner.scope)) { revoke(); return { ok: false, error: "sign_in_changed" }; }
100
- if (!r.ok || !plain(r.body) || !plain(r.body.values) || !Number.isSafeInteger(r.body.rev) || r.body.rev < 0 || r.body.rev < rev || r.body.unreadable) { unknown("not_saved"); return { ok: false, error: "not_saved" }; }
101
- if (!Object.entries(values).every(([k, v]) => v === null ? !own(r.body.values, k) : r.body.values[k] === v)) { unknown("not_saved"); return { ok: false, error: "not_saved" }; }
102
- saved = true;
103
- const refreshed = await read(op); return { ok: refreshed, saved, error: refreshed ? null : "refresh_failed" };
104
- } finally { finish(op); }
105
- }
106
- /** Runtime adapter asks only for the exact, currently known selection; a cursor can never request Worker source. */
107
- export function ownerEffectUrl(key, id, kind = "resource") {
108
- const row = ownerEffectsStore.get().slots[key];
109
- if (!eligible() || ownerEffectsStore.get().status !== "known" || !KEYS.includes(key) || !row || row.status !== "available" || row.id !== id || !["resource", "poster", "cursor"].includes(kind) || kind === "resource" && key === "fx.cursor") return null;
110
- const path = kind === "resource" ? `/ui/effects/resource/${id}` : `/ui/effects/image/${id}/${kind}.png`;
111
- return `${path}?slot=${encodeURIComponent(key)}&ownerEpoch=${owner.epoch}`;
112
- }
113
- export function markOwnerEffectUnavailable(key, id) {
114
- const s = ownerEffectsStore.get(), row = s.slots[key];
115
- if (!eligible() || s.status !== "known" || !KEYS.includes(key) || row?.id !== id) return;
116
- ownerEffectsStore.set({ slots: { ...s.slots, [key]: { status: "unavailable", id } } });
117
- }
@@ -1,17 +0,0 @@
1
- export declare const WEB_CHAT_NOTICE = "web-chat-2.2";
2
- /** Where the web chat notice points a phone user, until the public link (#1367) gives them a menu option. */
3
- export declare const WEB_REMOTE_DOCS_URL = "https://github.com/songsid/AgEnD/blob/main/docs/web-dashboard.md#reaching-it-from-elsewhere";
4
- export declare function upgradeNoticesPath(dataDir: string): string;
5
- /**
6
- * Whether this version has web chat: 2.2 or later, prereleases included. The 2.2 betas (2.2.0-beta.N) are where
7
- * upgrading users first meet it, although SemVer orders them before 2.2.0. A version that does not parse (a dev
8
- * checkout says 1.22.0, an unknown one says "unknown") is not.
9
- */
10
- export declare function hasWebChat(version: string): boolean;
11
- /**
12
- * Record that `notice` is being sent to `adapterId`. True only when this call recorded it: false when it was
13
- * recorded before, or when the file cannot be read or written (then the caller sends nothing).
14
- */
15
- export declare function claimNotice(path: string, notice: string, adapterId: string): boolean;
16
- /** Undo a claim whose send failed, so the next start tries again. Best effort: false when it could not be undone. */
17
- export declare function releaseNotice(path: string, notice: string, adapterId: string): boolean;
@@ -1,93 +0,0 @@
1
- /**
2
- * One-time notices for people who upgrade into a release that changed how AgEnD is used (#1366).
3
- *
4
- * The first is web chat (2.2): a fleet that has run 2.1 for months gives no sign that its agents can now be talked
5
- * to from a browser. The first time a fleet runs 2.2 or later, each chat platform's General is told once.
6
- *
7
- * What was announced where is recorded in `<AGEND_HOME>/upgrade-notices.json`: `{ "<notice>": ["<adapter id>", …] }`.
8
- * A notice is claimed in that file before it is sent, and the claim is released if the send fails, so the next start
9
- * tries again. When the file cannot be read or written, nothing is sent: a missed notice is better than one that
10
- * repeats on every restart.
11
- */
12
- import { readFileSync } from "node:fs";
13
- import { join } from "node:path";
14
- import { writeFileAtomic } from "./backend/kiro-engine-ledger.js";
15
- export const WEB_CHAT_NOTICE = "web-chat-2.2";
16
- /** Where the web chat notice points a phone user, until the public link (#1367) gives them a menu option. */
17
- export const WEB_REMOTE_DOCS_URL = "https://github.com/songsid/AgEnD/blob/main/docs/web-dashboard.md#reaching-it-from-elsewhere";
18
- export function upgradeNoticesPath(dataDir) {
19
- return join(dataDir, "upgrade-notices.json");
20
- }
21
- /**
22
- * Whether this version has web chat: 2.2 or later, prereleases included. The 2.2 betas (2.2.0-beta.N) are where
23
- * upgrading users first meet it, although SemVer orders them before 2.2.0. A version that does not parse (a dev
24
- * checkout says 1.22.0, an unknown one says "unknown") is not.
25
- */
26
- export function hasWebChat(version) {
27
- const m = /^(\d+)\.(\d+)\.\d+(?:[-+].*)?$/.exec(version.trim());
28
- if (!m)
29
- return false;
30
- const major = Number(m[1]), minor = Number(m[2]);
31
- return major > 2 || (major === 2 && minor >= 2);
32
- }
33
- /** The state, `{}` when there is no file yet, or null when it exists but cannot be read or understood. */
34
- function readState(path) {
35
- let text;
36
- try {
37
- text = readFileSync(path, "utf8");
38
- }
39
- catch (err) {
40
- return err.code === "ENOENT" ? {} : null;
41
- }
42
- try {
43
- const parsed = JSON.parse(text);
44
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
45
- return null;
46
- const state = {};
47
- for (const [notice, adapters] of Object.entries(parsed)) {
48
- if (!Array.isArray(adapters) || !adapters.every(a => typeof a === "string"))
49
- return null;
50
- state[notice] = adapters;
51
- }
52
- return state;
53
- }
54
- catch {
55
- return null;
56
- }
57
- }
58
- /**
59
- * Record that `notice` is being sent to `adapterId`. True only when this call recorded it: false when it was
60
- * recorded before, or when the file cannot be read or written (then the caller sends nothing).
61
- */
62
- export function claimNotice(path, notice, adapterId) {
63
- const state = readState(path);
64
- if (!state || state[notice]?.includes(adapterId))
65
- return false;
66
- state[notice] = [...(state[notice] ?? []), adapterId];
67
- try {
68
- writeFileAtomic(path, JSON.stringify(state, null, 2) + "\n");
69
- }
70
- catch {
71
- return false;
72
- }
73
- return true;
74
- }
75
- /** Undo a claim whose send failed, so the next start tries again. Best effort: false when it could not be undone. */
76
- export function releaseNotice(path, notice, adapterId) {
77
- const state = readState(path);
78
- if (!state)
79
- return false;
80
- const left = (state[notice] ?? []).filter(a => a !== adapterId);
81
- if (left.length > 0)
82
- state[notice] = left;
83
- else
84
- delete state[notice];
85
- try {
86
- writeFileAtomic(path, JSON.stringify(state, null, 2) + "\n");
87
- }
88
- catch {
89
- return false;
90
- }
91
- return true;
92
- }
93
- //# sourceMappingURL=upgrade-notices.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"upgrade-notices.js","sourceRoot":"","sources":["../src/upgrade-notices.ts"],"names":[],"mappings":"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"}
@@ -1,12 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from "node:http";
2
- /** #2118: fixed trusted document; no uploaded source, account data or resource authorization lives here. */
3
- export declare const EFFECT_BOOTSTRAP_PATH = "/effect-bootstrap";
4
- export declare function effectBootstrapResponse(boot: string): {
5
- body: Buffer;
6
- headers: Readonly<Record<string, string>>;
7
- };
8
- /** Call only after the listener's Host/shutdown admission. No session lookup/touch or credential parsing. */
9
- export declare function createEffectBootstrap(boot?: string): {
10
- readonly boot: string;
11
- handle(req: IncomingMessage, res: ServerResponse): boolean;
12
- };
@@ -1,49 +0,0 @@
1
- import { createHash, randomBytes } from "node:crypto";
2
- import { buildCanvasEffectShim } from "./web-effect-worker.js";
3
- import { gatewayRequestContext } from "./web-request-context.js";
4
- /** #2118: fixed trusted document; no uploaded source, account data or resource authorization lives here. */
5
- export const EFFECT_BOOTSTRAP_PATH = "/effect-bootstrap";
6
- export function effectBootstrapResponse(boot) {
7
- if (!/^[0-9a-f]{32}$/.test(boot))
8
- throw new Error("invalid effect bootstrap boot");
9
- // The URL's origin is the actual navigation origin, even though the sandboxed realm is opaque. Do not derive
10
- // the parent allowlist from Origin, forwarded headers, cookies, a preview listener or a request parameter.
11
- const html = buildCanvasEffectShim(boot, [], true), body = Buffer.from(html, "utf8");
12
- const script = /<script>([\s\S]*?)<\/script>/.exec(html)[1];
13
- const style = /<style>([\s\S]*?)<\/style>/.exec(html)[1];
14
- const hash = (value) => "'sha256-" + createHash("sha256").update(value).digest("base64") + "'";
15
- const csp = [
16
- "default-src 'none'", "script-src " + hash(script) + " blob:", "style-src " + hash(style),
17
- "worker-src blob:", "img-src data: blob:", "font-src 'none'", "media-src 'none'",
18
- "connect-src 'none'", "frame-src 'none'", "child-src 'none'", "object-src 'none'",
19
- "form-action 'none'", "base-uri 'none'", "manifest-src 'none'", "webrtc 'block'",
20
- "frame-ancestors 'self'", "sandbox allow-scripts",
21
- ].join("; ");
22
- return { body, headers: Object.freeze({
23
- "Content-Type": "text/html; charset=utf-8", "Content-Length": String(body.length),
24
- "Content-Security-Policy": csp, "Cache-Control": "no-store", "X-Content-Type-Options": "nosniff",
25
- "Referrer-Policy": "no-referrer", "Cross-Origin-Resource-Policy": "same-origin",
26
- "Permissions-Policy": "camera=(), microphone=(), geolocation=(), clipboard-read=(), clipboard-write=(), usb=(), serial=(), hid=(), bluetooth=(), payment=(), display-capture=(), fullscreen=()",
27
- }) };
28
- }
29
- /** Call only after the listener's Host/shutdown admission. No session lookup/touch or credential parsing. */
30
- export function createEffectBootstrap(boot = randomBytes(16).toString("hex")) {
31
- const response = effectBootstrapResponse(boot);
32
- return Object.freeze({ boot, handle(req, res) {
33
- const raw = req.url ?? "/";
34
- if (raw.split(/[?#]/, 1)[0] !== EFFECT_BOOTSTRAP_PATH)
35
- return false;
36
- const gateway = gatewayRequestContext(req);
37
- if (raw !== EFFECT_BOOTSTRAP_PATH || req.method !== "GET" || gateway && !gateway.isCurrent()) {
38
- res.writeHead(404, { "Content-Length": "0", "Cache-Control": "no-store" });
39
- res.end();
40
- return true;
41
- }
42
- // The ordinary shell must stay unframable; this document is instead confined by response CSP sandbox.
43
- res.removeHeader("X-Frame-Options");
44
- res.writeHead(200, response.headers);
45
- res.end(response.body);
46
- return true;
47
- } });
48
- }
49
- //# sourceMappingURL=web-effect-bootstrap.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"web-effect-bootstrap.js","sourceRoot":"","sources":["../src/web-effect-bootstrap.ts"],"names":[],"mappings":"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"}
@@ -1,28 +0,0 @@
1
- import { type WebEffectManifest } from "./web-effect.js";
2
- export declare const WEB_EFFECT_MAX_BYTES: number;
3
- export declare const WEB_EFFECT_RAW_MAX_BYTES: number;
4
- export declare const WEB_EFFECT_ASSET_MAX = 16;
5
- export interface CheckedWebEffect {
6
- id: string;
7
- sha256: string;
8
- manifest: WebEffectManifest;
9
- bytes: number;
10
- files: ReadonlyMap<string, Uint8Array>;
11
- warnings: string[];
12
- }
13
- export type EffectEntryResult = ({
14
- ok: true;
15
- } & CheckedWebEffect) | {
16
- ok: false;
17
- problems: Array<{
18
- path: string;
19
- problem: string;
20
- }>;
21
- };
22
- export declare function checkEffectEntry(input: ReadonlyMap<string, Uint8Array>): EffectEntryResult;
23
- /** Already normalized files only: assets become decoded ImageBitmaps inside the trusted frame. */
24
- export declare function effectRasterAssets(entry: CheckedWebEffect): Array<{
25
- name: string;
26
- mime: string;
27
- bytes: Uint8Array;
28
- }>;
@@ -1,171 +0,0 @@
1
- /** CW1: synchronous validation and normalization. No I/O, JS execution, or image decoding. */
2
- import { Script } from "node:vm";
3
- import { imageSize, sniffMedia, stripMetadata, MEDIA_MIME } from "./web-image-meta.js";
4
- import { effectBundleIdentity, effectManifestJson } from "./web-effect-canonical.js";
5
- import { parseWebEffectManifest } from "./web-effect.js";
6
- export const WEB_EFFECT_MAX_BYTES = 1024 * 1024;
7
- export const WEB_EFFECT_RAW_MAX_BYTES = 8 * 1024 * 1024;
8
- export const WEB_EFFECT_ASSET_MAX = 16;
9
- const utf8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
10
- const assetPath = /^assets\/[a-z0-9][a-z0-9_-]{0,63}\.(png|jpe?g|webp|gif)$/;
11
- const fail = (path, problem) => ({ ok: false, problems: [{ path, problem }] });
12
- /** Advisory text lint only, never validation or a security boundary. Keep quoted URLs while ignoring comments. */
13
- function workerLintText(code) {
14
- const parts = [];
15
- let copied = 0, at = 0;
16
- while (at < code.length) {
17
- const c = code[at];
18
- if (c === '"' || c === "'" || c === "`") {
19
- const quote = c;
20
- at++;
21
- while (at < code.length) {
22
- if (code[at] === "\\") {
23
- at += 2;
24
- continue;
25
- }
26
- if (code[at++] === quote)
27
- break;
28
- }
29
- continue;
30
- }
31
- // Escaped slashes in a regular-expression literal are not comment openers.
32
- if (c === "\\") {
33
- at += 2;
34
- continue;
35
- }
36
- if (c === "/" && (code[at + 1] === "/" || code[at + 1] === "*")) {
37
- parts.push(code.slice(copied, at), " ");
38
- if (code[at + 1] === "/") {
39
- at += 2;
40
- while (at < code.length && !/[\r\n\u2028\u2029]/.test(code[at]))
41
- at++;
42
- }
43
- else {
44
- at += 2;
45
- while (at < code.length && !(code[at] === "*" && code[at + 1] === "/"))
46
- at++;
47
- at = Math.min(code.length, at + 2);
48
- }
49
- copied = at;
50
- continue;
51
- }
52
- at++;
53
- }
54
- parts.push(code.slice(copied));
55
- return parts.join("");
56
- }
57
- export function checkEffectEntry(input) {
58
- try {
59
- if (!(input instanceof Map) || input.size < 2 || input.size > 20)
60
- return fail("<entry>", "invalid_files");
61
- let raw = 0, assets = 0, seen = 0;
62
- const snapshot = new Map();
63
- for (const [path, bytes] of input) {
64
- if (++seen > 20)
65
- return fail("<entry>", "invalid_files");
66
- if (typeof path !== "string" || !["effect.json", "worker.js", "poster.png", "cursor.png"].includes(path) && !assetPath.test(path))
67
- return fail("<entry>", "unsupported_path");
68
- if (!(bytes instanceof Uint8Array))
69
- return fail(path, "invalid_bytes");
70
- raw += bytes.byteLength;
71
- if (raw > WEB_EFFECT_RAW_MAX_BYTES)
72
- return fail("<entry>", "raw_entry_too_large");
73
- if (assetPath.test(path) && ++assets > WEB_EFFECT_ASSET_MAX)
74
- return fail("<entry>", "too_many_assets");
75
- if (snapshot.has(path))
76
- return fail("<entry>", "invalid_files");
77
- snapshot.set(path, new Uint8Array(bytes));
78
- }
79
- const manifestBytes = snapshot.get("effect.json"), script = snapshot.get("worker.js");
80
- if (!manifestBytes || !script)
81
- return fail("<entry>", "missing_entry");
82
- if (manifestBytes.byteLength > 64 * 1024)
83
- return fail("effect.json", "manifest_too_large");
84
- if (script.byteLength > WEB_EFFECT_MAX_BYTES)
85
- return fail("worker.js", "entry_too_large");
86
- let decoded, code;
87
- try {
88
- decoded = JSON.parse(utf8.decode(manifestBytes));
89
- }
90
- catch {
91
- return fail("effect.json", "invalid_manifest");
92
- }
93
- const parsed = parseWebEffectManifest(decoded);
94
- if (!parsed.ok)
95
- return fail("effect.json", "invalid_manifest");
96
- try {
97
- code = utf8.decode(script);
98
- }
99
- catch {
100
- return fail("worker.js", "invalid_utf8");
101
- }
102
- let manifest = parsed.manifest;
103
- if (manifest.poster && !snapshot.has("poster.png"))
104
- return fail("poster.png", "missing_poster");
105
- if (!!manifest.cursor !== snapshot.has("cursor.png"))
106
- return fail("cursor.png", "cursor_manifest_mismatch");
107
- if (snapshot.has("poster.png"))
108
- manifest = { ...manifest, poster: "poster.png" };
109
- let pixels = 0;
110
- const files = new Map();
111
- files.set("worker.js", Uint8Array.from(script));
112
- for (const [path, bytes] of snapshot) {
113
- if (path === "effect.json" || path === "worker.js")
114
- continue;
115
- const kind = sniffMedia(bytes);
116
- if (!kind || kind === "woff2")
117
- return fail(path, "invalid_raster");
118
- const extension = path.slice(path.lastIndexOf(".") + 1), expected = extension === "jpg" ? "jpeg" : extension;
119
- if (kind !== expected)
120
- return fail(path, "media_mismatch");
121
- const size = imageSize(bytes, kind);
122
- if (!size || size.width < 1 || size.height < 1 || size.width > 4096 || size.height > 4096 || size.width * size.height > 8 * 1024 * 1024)
123
- return fail(path, "image_dimensions");
124
- pixels += size.width * size.height;
125
- if (pixels > 8 * 1024 * 1024)
126
- return fail(path, "image_dimensions");
127
- const stripped = stripMetadata(bytes, kind);
128
- if (!stripped)
129
- return fail(path, "invalid_raster");
130
- if (path === "cursor.png") {
131
- if (kind !== "png" || stripped.byteLength > 32 * 1024 || size.width !== size.height || size.width > 64)
132
- return fail(path, "invalid_cursor");
133
- if (manifest.cursor.hotspot.some((point, index) => point >= (index === 0 ? size.width : size.height)))
134
- return fail(path, "invalid_hotspot");
135
- }
136
- files.set(path, Uint8Array.from(stripped));
137
- }
138
- files.set("effect.json", new TextEncoder().encode(effectManifestJson(manifest)));
139
- const bytes = [...files.values()].reduce((n, v) => n + v.byteLength, 0);
140
- if (bytes > WEB_EFFECT_MAX_BYTES)
141
- return fail("<entry>", "entry_too_large");
142
- // Compile classic syntax only. Never run the result or expose parser excerpts.
143
- try {
144
- new Script(code, { filename: "worker.js" });
145
- }
146
- catch {
147
- return fail("worker.js", "invalid_classic_script");
148
- }
149
- const identity = effectBundleIdentity(manifest, files);
150
- const warnings = [];
151
- if (/\b(?:fetch|XMLHttpRequest|WebSocket|RTCPeerConnection|importScripts)\b|https?:\/\/|["\'`]\/\/|\bimport\s*\(|\btop\.|\bparent\.location/.test(workerLintText(code)))
152
- warnings.push("network_or_import_api_unsupported");
153
- return { ok: true, id: identity.id, sha256: identity.sha256, manifest, files, bytes, warnings };
154
- }
155
- catch {
156
- return fail("<entry>", "invalid_entry");
157
- }
158
- }
159
- /** Already normalized files only: assets become decoded ImageBitmaps inside the trusted frame. */
160
- export function effectRasterAssets(entry) {
161
- const assets = [];
162
- for (const [name, bytes] of entry.files)
163
- if (assetPath.test(name)) {
164
- const kind = sniffMedia(bytes);
165
- if (!kind || kind === "woff2")
166
- throw Error("Invalid normalized raster");
167
- assets.push({ name, mime: MEDIA_MIME[kind], bytes: Uint8Array.from(bytes) });
168
- }
169
- return assets;
170
- }
171
- //# sourceMappingURL=web-effect-bundle.js.map