@songsid/agend 2.3.0-beta.8 → 2.3.0

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 (736) hide show
  1. package/README.md +16 -8
  2. package/README.zh-TW.md +16 -8
  3. package/dist/adapter-world.js.map +1 -1
  4. package/dist/agend-home.d.ts +5 -0
  5. package/dist/agend-home.js +7 -0
  6. package/dist/agend-home.js.map +1 -0
  7. package/dist/agent-cli-instructions.md +9 -2
  8. package/dist/agent-cli.js +44 -0
  9. package/dist/agent-cli.js.map +1 -1
  10. package/dist/agent-endpoint.d.ts +9 -0
  11. package/dist/agent-endpoint.js +23 -0
  12. package/dist/agent-endpoint.js.map +1 -1
  13. package/dist/agent-file-read.js +1 -1
  14. package/dist/agent-file-read.js.map +1 -1
  15. package/dist/agent-whats-new.d.ts +16 -0
  16. package/dist/agent-whats-new.js +54 -11
  17. package/dist/agent-whats-new.js.map +1 -1
  18. package/dist/apply-job.js.map +1 -1
  19. package/dist/atomic-write.js.map +1 -1
  20. package/dist/auth-api.d.ts +12 -0
  21. package/dist/auth-api.js +77 -22
  22. package/dist/auth-api.js.map +1 -1
  23. package/dist/authority/authority-state.d.ts +4 -0
  24. package/dist/authority/authority-state.js +17 -8
  25. package/dist/authority/authority-state.js.map +1 -1
  26. package/dist/authority/session-authorizations.js.map +1 -1
  27. package/dist/authority/web-authority.d.ts +16 -8
  28. package/dist/authority/web-authority.js +19 -5
  29. package/dist/authority/web-authority.js.map +1 -1
  30. package/dist/backend/antigravity.d.ts +2 -2
  31. package/dist/backend/antigravity.js +2 -1
  32. package/dist/backend/antigravity.js.map +1 -1
  33. package/dist/backend/claude-code.js +13 -4
  34. package/dist/backend/claude-code.js.map +1 -1
  35. package/dist/backend/codex-metadata.d.ts +8 -0
  36. package/dist/backend/codex-metadata.js +74 -17
  37. package/dist/backend/codex-metadata.js.map +1 -1
  38. package/dist/backend/codex-package.d.ts +30 -0
  39. package/dist/backend/codex-package.js +133 -0
  40. package/dist/backend/codex-package.js.map +1 -0
  41. package/dist/backend/codex-session-lookup.js.map +1 -1
  42. package/dist/backend/codex.d.ts +2 -0
  43. package/dist/backend/codex.js +25 -5
  44. package/dist/backend/codex.js.map +1 -1
  45. package/dist/backend/credential-profile.d.ts +2 -0
  46. package/dist/backend/credential-profile.js +2 -0
  47. package/dist/backend/credential-profile.js.map +1 -1
  48. package/dist/backend/effort-metadata.js.map +1 -1
  49. package/dist/backend/grok.js +58 -3
  50. package/dist/backend/grok.js.map +1 -1
  51. package/dist/backend/kiro-engine-ledger.js.map +1 -1
  52. package/dist/backend/kiro-kas-store.js.map +1 -1
  53. package/dist/backend/kiro-v2-store.js.map +1 -1
  54. package/dist/backend/kiro-v3-identity.js.map +1 -1
  55. package/dist/backend/kiro.d.ts +9 -1
  56. package/dist/backend/kiro.js +102 -1
  57. package/dist/backend/kiro.js.map +1 -1
  58. package/dist/backend/launch-effort.js.map +1 -1
  59. package/dist/backend/mock.js.map +1 -1
  60. package/dist/backend/muse.js.map +1 -1
  61. package/dist/backend/opencode-permission.js +1 -1
  62. package/dist/backend/opencode-permission.js.map +1 -1
  63. package/dist/backend/opencode.js +2 -1
  64. package/dist/backend/opencode.js.map +1 -1
  65. package/dist/backend/session-signals.js.map +1 -1
  66. package/dist/backend-availability.js.map +1 -1
  67. package/dist/backend-command.d.ts +2 -0
  68. package/dist/backend-command.js +3 -1
  69. package/dist/backend-command.js.map +1 -1
  70. package/dist/backend-outage.js.map +1 -1
  71. package/dist/binary-probe.js +1 -1
  72. package/dist/binary-probe.js.map +1 -1
  73. package/dist/bug-report-cli.d.ts +30 -0
  74. package/dist/bug-report-cli.js +139 -0
  75. package/dist/bug-report-cli.js.map +1 -0
  76. package/dist/bug-report.d.ts +47 -0
  77. package/dist/bug-report.js +137 -0
  78. package/dist/bug-report.js.map +1 -0
  79. package/dist/bundled-skills.d.ts +18 -0
  80. package/dist/bundled-skills.js +38 -0
  81. package/dist/bundled-skills.js.map +1 -0
  82. package/dist/cache-service.js +1 -1
  83. package/dist/cache-service.js.map +1 -1
  84. package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
  85. package/dist/channel/adapters/discord-client-retirement.js +57 -0
  86. package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
  87. package/dist/channel/adapters/discord.d.ts +4 -0
  88. package/dist/channel/adapters/discord.js +57 -12
  89. package/dist/channel/adapters/discord.js.map +1 -1
  90. package/dist/channel/adapters/telegram.d.ts +6 -0
  91. package/dist/channel/adapters/telegram.js +54 -14
  92. package/dist/channel/adapters/telegram.js.map +1 -1
  93. package/dist/channel/mcp-server.js +21 -4
  94. package/dist/channel/mcp-server.js.map +1 -1
  95. package/dist/channel/mcp-tools.d.ts +3 -1
  96. package/dist/channel/mcp-tools.js +43 -6
  97. package/dist/channel/mcp-tools.js.map +1 -1
  98. package/dist/channel/message-queue.js.map +1 -1
  99. package/dist/channel/sticker-download.js.map +1 -1
  100. package/dist/channel/tool-router.js.map +1 -1
  101. package/dist/child-process.d.ts +21 -0
  102. package/dist/child-process.js +54 -0
  103. package/dist/child-process.js.map +1 -0
  104. package/dist/classic-channel-manager.js +3 -2
  105. package/dist/classic-channel-manager.js.map +1 -1
  106. package/dist/cli-entry.js.map +1 -1
  107. package/dist/cli-flags.js.map +1 -1
  108. package/dist/cli.d.ts +1 -0
  109. package/dist/cli.js +443 -311
  110. package/dist/cli.js.map +1 -1
  111. package/dist/command-table.d.ts +1 -1
  112. package/dist/command-table.js +1 -1
  113. package/dist/command-table.js.map +1 -1
  114. package/dist/compact-watch.js.map +1 -1
  115. package/dist/completion-install.js.map +1 -1
  116. package/dist/completion.js.map +1 -1
  117. package/dist/config-validator.d.ts +6 -0
  118. package/dist/config-validator.js +81 -8
  119. package/dist/config-validator.js.map +1 -1
  120. package/dist/config.d.ts +15 -3
  121. package/dist/config.js +41 -10
  122. package/dist/config.js.map +1 -1
  123. package/dist/connection-secrets.js.map +1 -1
  124. package/dist/context-guardian.js.map +1 -1
  125. package/dist/coredump-filter.js.map +1 -1
  126. package/dist/cpu-profile.js.map +1 -1
  127. package/dist/cross-instance-envelope.js.map +1 -1
  128. package/dist/cross-instance-notice.d.ts +7 -0
  129. package/dist/cross-instance-notice.js +10 -0
  130. package/dist/cross-instance-notice.js.map +1 -1
  131. package/dist/daemon.d.ts +39 -1
  132. package/dist/daemon.js +234 -15
  133. package/dist/daemon.js.map +1 -1
  134. package/dist/daily-summary.js.map +1 -1
  135. package/dist/darwin-memory.js +1 -1
  136. package/dist/darwin-memory.js.map +1 -1
  137. package/dist/dashboard-live.d.ts +8 -0
  138. package/dist/dashboard-live.js +35 -0
  139. package/dist/dashboard-live.js.map +1 -0
  140. package/dist/dashboard-permissions.d.ts +69 -0
  141. package/dist/dashboard-permissions.js +138 -0
  142. package/dist/dashboard-permissions.js.map +1 -0
  143. package/dist/decision-list.d.ts +25 -0
  144. package/dist/decision-list.js +30 -0
  145. package/dist/decision-list.js.map +1 -0
  146. package/dist/delivery-consumed-watch.js.map +1 -1
  147. package/dist/delivery-outbox.js +5 -0
  148. package/dist/delivery-outbox.js.map +1 -1
  149. package/dist/delivery-outbox.test.js.map +1 -1
  150. package/dist/delivery-reconciliation.test.js.map +1 -1
  151. package/dist/diagnostic-redaction.d.ts +10 -0
  152. package/dist/diagnostic-redaction.js +167 -0
  153. package/dist/diagnostic-redaction.js.map +1 -0
  154. package/dist/doctor.d.ts +8 -0
  155. package/dist/doctor.js +52 -0
  156. package/dist/doctor.js.map +1 -1
  157. package/dist/e2e-isolation.js.map +1 -1
  158. package/dist/event-log.js.map +1 -1
  159. package/dist/export-import.js +7 -5
  160. package/dist/export-import.js.map +1 -1
  161. package/dist/fleet-control-audit.js.map +1 -1
  162. package/dist/fleet-label.js.map +1 -1
  163. package/dist/fleet-level-config.d.ts +1 -1
  164. package/dist/fleet-level-config.js +2 -0
  165. package/dist/fleet-level-config.js.map +1 -1
  166. package/dist/fleet-lock.js +3 -2
  167. package/dist/fleet-lock.js.map +1 -1
  168. package/dist/fleet-manager.d.ts +258 -15
  169. package/dist/fleet-manager.js +1605 -304
  170. package/dist/fleet-manager.js.map +1 -1
  171. package/dist/fleet-process-handlers.d.ts +18 -0
  172. package/dist/fleet-process-handlers.js +70 -0
  173. package/dist/fleet-process-handlers.js.map +1 -0
  174. package/dist/fleet-startup.d.ts +14 -0
  175. package/dist/fleet-startup.js +30 -0
  176. package/dist/fleet-startup.js.map +1 -0
  177. package/dist/fleet-traffic.d.ts +36 -0
  178. package/dist/fleet-traffic.js +100 -0
  179. package/dist/fleet-traffic.js.map +1 -1
  180. package/dist/forged-envelope-scan.d.ts +0 -20
  181. package/dist/forged-envelope-scan.js +3 -2
  182. package/dist/forged-envelope-scan.js.map +1 -1
  183. package/dist/full-restart.d.ts +5 -5
  184. package/dist/full-restart.js +5 -5
  185. package/dist/full-restart.js.map +1 -1
  186. package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
  187. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +52 -11
  188. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +5 -1
  189. package/dist/general-knowledge/skills/fleet-config/SKILL.md +3 -1
  190. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
  191. package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
  192. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  193. package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
  194. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +321 -0
  195. package/dist/general-knowledge/skills/web-appearance/SKILL.md +28 -4
  196. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +553 -0
  197. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +170 -35
  198. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  199. package/dist/general-knowledge/steering/core-rules.md +1 -1
  200. package/dist/host-memory.js.map +1 -1
  201. package/dist/idle-gate-log.d.ts +19 -0
  202. package/dist/idle-gate-log.js +15 -0
  203. package/dist/idle-gate-log.js.map +1 -0
  204. package/dist/instance-config-impact.js +25 -4
  205. package/dist/instance-config-impact.js.map +1 -1
  206. package/dist/instance-lifecycle.d.ts +10 -1
  207. package/dist/instance-lifecycle.js +86 -25
  208. package/dist/instance-lifecycle.js.map +1 -1
  209. package/dist/instructions.d.ts +12 -6
  210. package/dist/instructions.js +19 -10
  211. package/dist/instructions.js.map +1 -1
  212. package/dist/kiro-compact-pane.js.map +1 -1
  213. package/dist/kiro-db-reader.js.map +1 -1
  214. package/dist/kiro-engine-status.js.map +1 -1
  215. package/dist/kiro-log-gate.js.map +1 -1
  216. package/dist/kiro-transcript-lane.js.map +1 -1
  217. package/dist/locale.js +428 -20
  218. package/dist/locale.js.map +1 -1
  219. package/dist/log-service.js.map +1 -1
  220. package/dist/log-steps.d.ts +1 -0
  221. package/dist/log-steps.js +15 -0
  222. package/dist/log-steps.js.map +1 -1
  223. package/dist/logger.js +3 -2
  224. package/dist/logger.js.map +1 -1
  225. package/dist/login-controller.d.ts +45 -0
  226. package/dist/login-controller.js +101 -5
  227. package/dist/login-controller.js.map +1 -1
  228. package/dist/login-flows.js +1 -1
  229. package/dist/login-manager.js.map +1 -1
  230. package/dist/login-shell.js +3 -1
  231. package/dist/login-shell.js.map +1 -1
  232. package/dist/ls-attach-resolve.d.ts +96 -0
  233. package/dist/ls-attach-resolve.js +180 -0
  234. package/dist/ls-attach-resolve.js.map +1 -0
  235. package/dist/ls-rows.d.ts +12 -0
  236. package/dist/ls-rows.js +83 -4
  237. package/dist/ls-rows.js.map +1 -1
  238. package/dist/memory-pressure.js.map +1 -1
  239. package/dist/muse-usage-relay.js.map +1 -1
  240. package/dist/needs-you-hub.d.ts +98 -1
  241. package/dist/needs-you-hub.js +313 -44
  242. package/dist/needs-you-hub.js.map +1 -1
  243. package/dist/needs-you-live.d.ts +5 -2
  244. package/dist/needs-you-live.js +6 -3
  245. package/dist/needs-you-live.js.map +1 -1
  246. package/dist/needs-you.d.ts +68 -3
  247. package/dist/needs-you.js +38 -4
  248. package/dist/needs-you.js.map +1 -1
  249. package/dist/network-family.js.map +1 -1
  250. package/dist/operator-control-paths.js +3 -4
  251. package/dist/operator-control-paths.js.map +1 -1
  252. package/dist/outbound-handlers.d.ts +3 -0
  253. package/dist/outbound-handlers.js +76 -19
  254. package/dist/outbound-handlers.js.map +1 -1
  255. package/dist/outbound-schemas.d.ts +112 -64
  256. package/dist/outbound-schemas.js +39 -12
  257. package/dist/outbound-schemas.js.map +1 -1
  258. package/dist/outbox-open-error.js.map +1 -1
  259. package/dist/pane-context-cache.js.map +1 -1
  260. package/dist/paths.js.map +1 -1
  261. package/dist/private-dir.js.map +1 -1
  262. package/dist/probe-worker-pool.js.map +1 -1
  263. package/dist/profile-control.js.map +1 -1
  264. package/dist/prompt-file-ref.js.map +1 -1
  265. package/dist/provider-probe.js.map +1 -1
  266. package/dist/provider-secret-registry.d.ts +5 -3
  267. package/dist/provider-secret-registry.js +8 -2
  268. package/dist/provider-secret-registry.js.map +1 -1
  269. package/dist/public-link-auto-open.d.ts +32 -0
  270. package/dist/public-link-auto-open.js +86 -0
  271. package/dist/public-link-auto-open.js.map +1 -0
  272. package/dist/public-link-owner.d.ts +10 -0
  273. package/dist/public-link-owner.js +36 -0
  274. package/dist/public-link-owner.js.map +1 -0
  275. package/dist/public-link-progress.d.ts +12 -1
  276. package/dist/public-link-progress.js +5 -10
  277. package/dist/public-link-progress.js.map +1 -1
  278. package/dist/public-preview.js.map +1 -1
  279. package/dist/public-tunnel-config.d.ts +11 -0
  280. package/dist/public-tunnel-config.js +68 -0
  281. package/dist/public-tunnel-config.js.map +1 -0
  282. package/dist/public-web-gateway.d.ts +2 -0
  283. package/dist/public-web-gateway.js +19 -6
  284. package/dist/public-web-gateway.js.map +1 -1
  285. package/dist/public-web-link.d.ts +48 -3
  286. package/dist/public-web-link.js +177 -51
  287. package/dist/public-web-link.js.map +1 -1
  288. package/dist/quickstart-api.d.ts +9 -0
  289. package/dist/quickstart-api.js +82 -0
  290. package/dist/quickstart-api.js.map +1 -1
  291. package/dist/quickstart.d.ts +5 -0
  292. package/dist/quickstart.js +40 -25
  293. package/dist/quickstart.js.map +1 -1
  294. package/dist/reply-buttons-controller.js.map +1 -1
  295. package/dist/reply-dedup.js.map +1 -1
  296. package/dist/resource-report.js +1 -1
  297. package/dist/resource-report.js.map +1 -1
  298. package/dist/restart-guard.js.map +1 -1
  299. package/dist/restart-progress.d.ts +80 -1
  300. package/dist/restart-progress.js +306 -21
  301. package/dist/restart-progress.js.map +1 -1
  302. package/dist/rollout-index.js.map +1 -1
  303. package/dist/runtime-cpu-profile.js.map +1 -1
  304. package/dist/scheduler/db.d.ts +40 -13
  305. package/dist/scheduler/db.js +123 -89
  306. package/dist/scheduler/db.js.map +1 -1
  307. package/dist/scheduler/scheduler.js.map +1 -1
  308. package/dist/scheduler/task-board-text.d.ts +26 -0
  309. package/dist/scheduler/task-board-text.js +140 -0
  310. package/dist/scheduler/task-board-text.js.map +1 -0
  311. package/dist/scheduler/task-board.d.ts +730 -0
  312. package/dist/scheduler/task-board.js +2179 -0
  313. package/dist/scheduler/task-board.js.map +1 -0
  314. package/dist/scheduler/types.d.ts +6 -1
  315. package/dist/sd-notify.js +2 -1
  316. package/dist/sd-notify.js.map +1 -1
  317. package/dist/search/search-docs.d.ts +58 -0
  318. package/dist/search/search-docs.js +63 -0
  319. package/dist/search/search-docs.js.map +1 -0
  320. package/dist/search/search-index.d.ts +141 -0
  321. package/dist/search/search-index.js +440 -0
  322. package/dist/search/search-index.js.map +1 -0
  323. package/dist/search/search-store.d.ts +122 -0
  324. package/dist/search/search-store.js +236 -0
  325. package/dist/search/search-store.js.map +1 -0
  326. package/dist/search/search-worker.d.ts +1 -0
  327. package/dist/search/search-worker.js +163 -0
  328. package/dist/search/search-worker.js.map +1 -0
  329. package/dist/secret-file.js.map +1 -1
  330. package/dist/secret-store.d.ts +2 -0
  331. package/dist/secret-store.js +21 -0
  332. package/dist/secret-store.js.map +1 -1
  333. package/dist/service-installer.d.ts +75 -0
  334. package/dist/service-installer.js +206 -0
  335. package/dist/service-installer.js.map +1 -1
  336. package/dist/service-owner.d.ts +44 -0
  337. package/dist/service-owner.js +48 -0
  338. package/dist/service-owner.js.map +1 -0
  339. package/dist/service-plan.d.ts +39 -2
  340. package/dist/service-plan.js +188 -6
  341. package/dist/service-plan.js.map +1 -1
  342. package/dist/session-oom.d.ts +21 -0
  343. package/dist/session-oom.js +139 -0
  344. package/dist/session-oom.js.map +1 -0
  345. package/dist/settings-api.d.ts +13 -0
  346. package/dist/settings-api.js +73 -12
  347. package/dist/settings-api.js.map +1 -1
  348. package/dist/settings-baseline.js.map +1 -1
  349. package/dist/settings-change.d.ts +5 -0
  350. package/dist/settings-change.js +167 -6
  351. package/dist/settings-change.js.map +1 -1
  352. package/dist/settings-confirmation.d.ts +9 -1
  353. package/dist/settings-confirmation.js +18 -8
  354. package/dist/settings-confirmation.js.map +1 -1
  355. package/dist/settings-control.js +2 -1
  356. package/dist/settings-control.js.map +1 -1
  357. package/dist/settings-effect.js +29 -4
  358. package/dist/settings-effect.js.map +1 -1
  359. package/dist/settings-http-confirmation.d.ts +13 -0
  360. package/dist/settings-http-confirmation.js +15 -3
  361. package/dist/settings-http-confirmation.js.map +1 -1
  362. package/dist/settings-instance-patch.js +13 -1
  363. package/dist/settings-instance-patch.js.map +1 -1
  364. package/dist/settings-request-capability.d.ts +4 -1
  365. package/dist/settings-request-capability.js +11 -3
  366. package/dist/settings-request-capability.js.map +1 -1
  367. package/dist/settings-transaction.js.map +1 -1
  368. package/dist/setup-auth.d.ts +1 -0
  369. package/dist/setup-auth.js +2 -1
  370. package/dist/setup-auth.js.map +1 -1
  371. package/dist/setup-form.d.ts +1 -1
  372. package/dist/setup-form.js +23 -7
  373. package/dist/setup-form.js.map +1 -1
  374. package/dist/setup-host.d.ts +6 -1
  375. package/dist/setup-host.js +15 -4
  376. package/dist/setup-host.js.map +1 -1
  377. package/dist/setup-wizard.js +6 -3
  378. package/dist/setup-wizard.js.map +1 -1
  379. package/dist/spawn-gate.d.ts +5 -0
  380. package/dist/spawn-gate.js +28 -8
  381. package/dist/spawn-gate.js.map +1 -1
  382. package/dist/start-attempt.d.ts +1 -0
  383. package/dist/start-attempt.js +18 -0
  384. package/dist/start-attempt.js.map +1 -0
  385. package/dist/start-failure-notice.d.ts +4 -0
  386. package/dist/start-failure-notice.js +20 -0
  387. package/dist/start-failure-notice.js.map +1 -0
  388. package/dist/start-failure.d.ts +147 -0
  389. package/dist/start-failure.js +281 -0
  390. package/dist/start-failure.js.map +1 -0
  391. package/dist/startup-memory-deadline.d.ts +23 -0
  392. package/dist/startup-memory-deadline.js +55 -0
  393. package/dist/startup-memory-deadline.js.map +1 -0
  394. package/dist/statusline-watcher.js.map +1 -1
  395. package/dist/storm-window.js.map +1 -1
  396. package/dist/systemd-peer-bus.js.map +1 -1
  397. package/dist/target-queue-worker.js.map +1 -1
  398. package/dist/task-board-summary.d.ts +101 -0
  399. package/dist/task-board-summary.js +177 -0
  400. package/dist/task-board-summary.js.map +1 -0
  401. package/dist/task-board-tool.d.ts +25 -0
  402. package/dist/task-board-tool.js +155 -0
  403. package/dist/task-board-tool.js.map +1 -0
  404. package/dist/task-board-waker.d.ts +51 -0
  405. package/dist/task-board-waker.js +141 -0
  406. package/dist/task-board-waker.js.map +1 -0
  407. package/dist/tips.js.map +1 -1
  408. package/dist/tmux-control.js +1 -1
  409. package/dist/tmux-control.js.map +1 -1
  410. package/dist/tmux-exec-helper.d.ts +104 -0
  411. package/dist/tmux-exec-helper.js +412 -0
  412. package/dist/tmux-exec-helper.js.map +1 -0
  413. package/dist/tmux-manager.d.ts +1 -0
  414. package/dist/tmux-manager.js +29 -13
  415. package/dist/tmux-manager.js.map +1 -1
  416. package/dist/tmux-read.js +2 -2
  417. package/dist/tmux-read.js.map +1 -1
  418. package/dist/tool-permissions.js +9 -42
  419. package/dist/tool-permissions.js.map +1 -1
  420. package/dist/tool-progress.js.map +1 -1
  421. package/dist/topic-archiver.js.map +1 -1
  422. package/dist/topic-commands.d.ts +13 -0
  423. package/dist/topic-commands.js +56 -33
  424. package/dist/topic-commands.js.map +1 -1
  425. package/dist/topic-link.js.map +1 -1
  426. package/dist/transcript-delta-reader.js.map +1 -1
  427. package/dist/transcript-jsonl.js.map +1 -1
  428. package/dist/transcript-monitor.js +5 -0
  429. package/dist/transcript-monitor.js.map +1 -1
  430. package/dist/transcript-sources.d.ts +2 -0
  431. package/dist/transcript-sources.js +4 -0
  432. package/dist/transcript-sources.js.map +1 -1
  433. package/dist/tunnel/cloudflared-install.js +3 -1
  434. package/dist/tunnel/cloudflared-install.js.map +1 -1
  435. package/dist/tunnel/cloudflared.d.ts +7 -16
  436. package/dist/tunnel/cloudflared.js +100 -13
  437. package/dist/tunnel/cloudflared.js.map +1 -1
  438. package/dist/tunnel/lease.js +3 -2
  439. package/dist/tunnel/lease.js.map +1 -1
  440. package/dist/tunnel/manager.js.map +1 -1
  441. package/dist/tunnel/named-diagnostics.d.ts +13 -0
  442. package/dist/tunnel/named-diagnostics.js +52 -0
  443. package/dist/tunnel/named-diagnostics.js.map +1 -0
  444. package/dist/tunnel/public-fetch.js.map +1 -1
  445. package/dist/tunnel/purpose-lane.js.map +1 -1
  446. package/dist/tunnel/types.d.ts +4 -1
  447. package/dist/tunnel/types.js.map +1 -1
  448. package/dist/types.d.ts +55 -2
  449. package/dist/ui/app-effects.js +27 -5
  450. package/dist/ui/app.html +2 -0
  451. package/dist/ui/backend-signin.js +297 -0
  452. package/dist/ui/chat-effects.js +15 -7
  453. package/dist/ui/chat-msg-actions.js +176 -0
  454. package/dist/ui/chat-render.js +67 -20
  455. package/dist/ui/chat-store.js +218 -48
  456. package/dist/ui/chat-strings.js +42 -10
  457. package/dist/ui/chat-thread.js +249 -23
  458. package/dist/ui/effect-trial-controller.js +13 -8
  459. package/dist/ui/effect-trial-offer.js +2 -31
  460. package/dist/ui/effects-waker.js +2 -0
  461. package/dist/ui/fleet-canvas-layout.js +13 -4
  462. package/dist/ui/fleet-canvas.js +120 -43
  463. package/dist/ui/fleet-office-editor.js +149 -0
  464. package/dist/ui/fleet-office-model.js +358 -0
  465. package/dist/ui/fleet-office-pack.js +199 -0
  466. package/dist/ui/fleet-office-skin.js +474 -0
  467. package/dist/ui/fleet-office-store.js +49 -0
  468. package/dist/ui/fleet-office-zones.js +177 -0
  469. package/dist/ui/fleet-office.js +434 -0
  470. package/dist/ui/fleet-org.js +21 -8
  471. package/dist/ui/fleet-route-scene.js +272 -0
  472. package/dist/ui/fleet-route-worker.js +21 -0
  473. package/dist/ui/fleet-route.js +88 -0
  474. package/dist/ui/fleet-task-card.js +436 -0
  475. package/dist/ui/fleet-task-common.js +482 -0
  476. package/dist/ui/fleet-task-work.js +107 -0
  477. package/dist/ui/fleet-tasks.js +569 -0
  478. package/dist/ui/fleet-traffic.js +227 -45
  479. package/dist/ui/fleet-usage.js +36 -2
  480. package/dist/ui/guest-refused.html +41 -0
  481. package/dist/ui/icons/icon-192.png +0 -0
  482. package/dist/ui/icons/icon-512.png +0 -0
  483. package/dist/ui/image-lightbox.js +45 -1
  484. package/dist/ui/image-zoom.js +242 -0
  485. package/dist/ui/panel-chat.js +282 -89
  486. package/dist/ui/panel-details.js +2 -0
  487. package/dist/ui/panel-fleet.js +32 -71
  488. package/dist/ui/panel-needs.js +23 -6
  489. package/dist/ui/panel-settings.js +158 -32
  490. package/dist/ui/preview-panel.js +2 -1
  491. package/dist/ui/search-dialog.js +350 -0
  492. package/dist/ui/settings-appearance.js +170 -10
  493. package/dist/ui/settings-apply.js +3 -3
  494. package/dist/ui/settings-confirm.js +7 -2
  495. package/dist/ui/settings-dialogs.js +46 -21
  496. package/dist/ui/settings-discord.js +6 -2
  497. package/dist/ui/settings-guests.js +2 -1
  498. package/dist/ui/settings-learn.js +1 -0
  499. package/dist/ui/settings-model.js +51 -18
  500. package/dist/ui/settings-mods.js +8 -3
  501. package/dist/ui/settings-owner-effects.js +6 -4
  502. package/dist/ui/settings-strings.js +180 -6
  503. package/dist/ui/settings-token.js +3 -1
  504. package/dist/ui/settings-web-authority.js +13 -5
  505. package/dist/ui/settings-wizard.js +13 -7
  506. package/dist/ui/shared/agend-auth.js +3 -1
  507. package/dist/ui/shared/app-i18n.js +12 -5
  508. package/dist/ui/shared/app-needs.js +2 -2
  509. package/dist/ui/shared/app-prefs.js +15 -0
  510. package/dist/ui/shared/app-route.js +18 -0
  511. package/dist/ui/shared/app-shell.js +172 -28
  512. package/dist/ui/shared/app-store.js +3 -2
  513. package/dist/ui/shared/app-stream.js +7 -2
  514. package/dist/ui/shared/app-themes.js +116 -1
  515. package/dist/ui/shared/app.css +681 -54
  516. package/dist/ui/shared/app.js +9 -1
  517. package/dist/ui/shared/card-strings.js +4 -0
  518. package/dist/ui/shared/effect-app-runtime.js +7 -5
  519. package/dist/ui/shared/effect-chat-runtime.js +2 -7
  520. package/dist/ui/shared/effect-cursor.js +3 -2
  521. package/dist/ui/shared/effect-display-metadata.js +39 -0
  522. package/dist/ui/shared/effect-owner-source.js +8 -1
  523. package/dist/ui/shared/effect-policy.js +2 -2
  524. package/dist/ui/shared/effect-registry.js +30 -11
  525. package/dist/ui/shared/effect-runtime-loader.js +3 -1
  526. package/dist/ui/shared/effect-stock-snapshot.js +9 -0
  527. package/dist/ui/shared/effect-stock-trust.js +40 -9
  528. package/dist/ui/shared/effect-trial-source.js +1 -1
  529. package/dist/ui/shared/effect-trial-stage.js +27 -21
  530. package/dist/ui/shared/effect-trial.css +1 -1
  531. package/dist/ui/shared/feature-flags.js +127 -0
  532. package/dist/ui/shared/guest-refused.js +35 -0
  533. package/dist/ui/shared/header-tools.js +2 -2
  534. package/dist/ui/shared/identity-card.js +26 -8
  535. package/dist/ui/shared/identity-color.js +17 -10
  536. package/dist/ui/shared/instance-nav.js +183 -28
  537. package/dist/ui/shared/owner-css.js +30 -1
  538. package/dist/ui/shared/panel-view.js +14 -29
  539. package/dist/ui/shared/text-undo.js +210 -0
  540. package/dist/ui/shared/tokens.css +13 -3
  541. package/dist/ui/shared/ui-dialog.js +5 -4
  542. package/dist/ui/shared/ui-icons.js +4 -0
  543. package/dist/ui/shared/ui-menu.js +20 -7
  544. package/dist/ui/shared/ui-toast.js +16 -3
  545. package/dist/ui/shared/usage-dialog.js +206 -16
  546. package/dist/ui/shared/view-strings.js +68 -4
  547. package/dist/ui/shared/web-authorize.js +50 -1
  548. package/dist/ui/signin.html +2 -0
  549. package/dist/ui/web-terminal/terminal.css +4 -4
  550. package/dist/ui/web-terminal/terminal.html +10 -10
  551. package/dist/ui/web-terminal/terminal.js +58 -12
  552. package/dist/update-check.js.map +1 -1
  553. package/dist/update-dispatch.js +1 -1
  554. package/dist/update-dispatch.js.map +1 -1
  555. package/dist/update-install.js.map +1 -1
  556. package/dist/update-launch.d.ts +10 -1
  557. package/dist/update-launch.js +39 -14
  558. package/dist/update-launch.js.map +1 -1
  559. package/dist/update-marker.js.map +1 -1
  560. package/dist/update-preflight.js +1 -1
  561. package/dist/update-preflight.js.map +1 -1
  562. package/dist/update-progress.d.ts +3 -1
  563. package/dist/update-progress.js +3 -1
  564. package/dist/update-progress.js.map +1 -1
  565. package/dist/usage/format-rich.js +6 -3
  566. package/dist/usage/format-rich.js.map +1 -1
  567. package/dist/usage/i18n-keys.d.ts +1 -1
  568. package/dist/usage/i18n-keys.js +2 -1
  569. package/dist/usage/i18n-keys.js.map +1 -1
  570. package/dist/usage/i18n.d.ts +13 -1
  571. package/dist/usage/i18n.js +29 -0
  572. package/dist/usage/i18n.js.map +1 -1
  573. package/dist/usage/providers.d.ts +89 -2
  574. package/dist/usage/providers.js +247 -41
  575. package/dist/usage/providers.js.map +1 -1
  576. package/dist/usage/statusline-usage.js.map +1 -1
  577. package/dist/usage/usage-api.d.ts +5 -1
  578. package/dist/usage/usage-api.js +185 -58
  579. package/dist/usage/usage-api.js.map +1 -1
  580. package/dist/usage-report.js.map +1 -1
  581. package/dist/usage-rollup.js +1 -1
  582. package/dist/usage-rollup.js.map +1 -1
  583. package/dist/user-systemd.d.ts +24 -0
  584. package/dist/user-systemd.js +75 -0
  585. package/dist/user-systemd.js.map +1 -0
  586. package/dist/view-api.d.ts +7 -0
  587. package/dist/view-api.js +16 -4
  588. package/dist/view-api.js.map +1 -1
  589. package/dist/wake-coordinator.js.map +1 -1
  590. package/dist/web-ambient.js +9 -2
  591. package/dist/web-ambient.js.map +1 -1
  592. package/dist/web-api.d.ts +58 -10
  593. package/dist/web-api.js +1104 -71
  594. package/dist/web-api.js.map +1 -1
  595. package/dist/web-app-icon-worker.d.ts +1 -0
  596. package/dist/web-app-icon-worker.js +16 -0
  597. package/dist/web-app-icon-worker.js.map +1 -0
  598. package/dist/web-app-icon.d.ts +109 -0
  599. package/dist/web-app-icon.js +257 -0
  600. package/dist/web-app-icon.js.map +1 -0
  601. package/dist/web-appearance-policy.js.map +1 -1
  602. package/dist/web-appearance-tools.d.ts +1 -0
  603. package/dist/web-appearance-tools.js +7 -3
  604. package/dist/web-appearance-tools.js.map +1 -1
  605. package/dist/web-appearance-view.js.map +1 -1
  606. package/dist/web-appearance.d.ts +4 -10
  607. package/dist/web-appearance.js +7 -4
  608. package/dist/web-appearance.js.map +1 -1
  609. package/dist/web-auth.d.ts +8 -4
  610. package/dist/web-auth.js +33 -21
  611. package/dist/web-auth.js.map +1 -1
  612. package/dist/web-backend-login.d.ts +130 -0
  613. package/dist/web-backend-login.js +225 -0
  614. package/dist/web-backend-login.js.map +1 -0
  615. package/dist/web-card.js.map +1 -1
  616. package/dist/web-channel-echo.js.map +1 -1
  617. package/dist/web-chat-history.d.ts +118 -8
  618. package/dist/web-chat-history.js +220 -25
  619. package/dist/web-chat-history.js.map +1 -1
  620. package/dist/web-commands.d.ts +5 -1
  621. package/dist/web-commands.js +1 -1
  622. package/dist/web-commands.js.map +1 -1
  623. package/dist/web-cookie-names.d.ts +5 -0
  624. package/dist/web-cookie-names.js +12 -0
  625. package/dist/web-cookie-names.js.map +1 -0
  626. package/dist/web-effect-bundle.d.ts +2 -2
  627. package/dist/web-effect-library.js.map +1 -1
  628. package/dist/web-effect-playback.js.map +1 -1
  629. package/dist/web-effect-profiles.d.ts +16 -16
  630. package/dist/web-effect-profiles.js +3 -2
  631. package/dist/web-effect-profiles.js.map +1 -1
  632. package/dist/web-effect-service.js.map +1 -1
  633. package/dist/web-effect-tools.js.map +1 -1
  634. package/dist/web-effect-trials.js.map +1 -1
  635. package/dist/web-effect-upload.js.map +1 -1
  636. package/dist/web-effect.d.ts +6 -6
  637. package/dist/web-effect.js.map +1 -1
  638. package/dist/web-experimental-http.d.ts +2 -0
  639. package/dist/web-experimental-http.js +12 -0
  640. package/dist/web-experimental-http.js.map +1 -0
  641. package/dist/web-experimental.d.ts +11 -0
  642. package/dist/web-experimental.js +49 -0
  643. package/dist/web-experimental.js.map +1 -0
  644. package/dist/web-guest-access.d.ts +4 -2
  645. package/dist/web-guest-access.js +22 -10
  646. package/dist/web-guest-access.js.map +1 -1
  647. package/dist/web-guest-rooms.js.map +1 -1
  648. package/dist/web-host-guard.d.ts +11 -0
  649. package/dist/web-host-guard.js +11 -0
  650. package/dist/web-host-guard.js.map +1 -1
  651. package/dist/web-icons.d.ts +33 -1
  652. package/dist/web-icons.js +83 -11
  653. package/dist/web-icons.js.map +1 -1
  654. package/dist/web-identity-color.js.map +1 -1
  655. package/dist/web-image-meta.d.ts +13 -0
  656. package/dist/web-image-meta.js +62 -0
  657. package/dist/web-image-meta.js.map +1 -1
  658. package/dist/web-images.js.map +1 -1
  659. package/dist/web-libavoid.d.ts +14 -0
  660. package/dist/web-libavoid.js +46 -0
  661. package/dist/web-libavoid.js.map +1 -0
  662. package/dist/web-login.js.map +1 -1
  663. package/dist/web-mentions.js.map +1 -1
  664. package/dist/web-mod-agent.js.map +1 -1
  665. package/dist/web-mod-store.d.ts +2 -0
  666. package/dist/web-mod-store.js +10 -0
  667. package/dist/web-mod-store.js.map +1 -1
  668. package/dist/web-office-store.d.ts +104 -0
  669. package/dist/web-office-store.js +236 -0
  670. package/dist/web-office-store.js.map +1 -0
  671. package/dist/web-owner-css-store.d.ts +44 -1
  672. package/dist/web-owner-css-store.js +70 -9
  673. package/dist/web-owner-css-store.js.map +1 -1
  674. package/dist/web-owner-css.js.map +1 -1
  675. package/dist/web-png.d.ts +33 -0
  676. package/dist/web-png.js +329 -0
  677. package/dist/web-png.js.map +1 -0
  678. package/dist/web-prefs.d.ts +6 -0
  679. package/dist/web-prefs.js +29 -3
  680. package/dist/web-prefs.js.map +1 -1
  681. package/dist/web-preview.d.ts +2 -0
  682. package/dist/web-preview.js +2 -0
  683. package/dist/web-preview.js.map +1 -1
  684. package/dist/web-profile.js.map +1 -1
  685. package/dist/web-reactions.d.ts +35 -0
  686. package/dist/web-reactions.js +47 -0
  687. package/dist/web-reactions.js.map +1 -0
  688. package/dist/web-request-context.d.ts +5 -0
  689. package/dist/web-request-context.js.map +1 -1
  690. package/dist/web-returning-device.d.ts +4 -2
  691. package/dist/web-returning-device.js +13 -6
  692. package/dist/web-returning-device.js.map +1 -1
  693. package/dist/web-schedules.js.map +1 -1
  694. package/dist/web-send-dedupe.d.ts +36 -0
  695. package/dist/web-send-dedupe.js +69 -0
  696. package/dist/web-send-dedupe.js.map +1 -0
  697. package/dist/web-session-authorization.js.map +1 -1
  698. package/dist/web-session.js +1 -1
  699. package/dist/web-session.js.map +1 -1
  700. package/dist/web-settings-patch.d.ts +3 -1
  701. package/dist/web-settings-patch.js +11 -5
  702. package/dist/web-settings-patch.js.map +1 -1
  703. package/dist/web-settings-tools.d.ts +6 -0
  704. package/dist/web-settings-tools.js +52 -17
  705. package/dist/web-settings-tools.js.map +1 -1
  706. package/dist/web-terminal-http.js +15 -2
  707. package/dist/web-terminal-http.js.map +1 -1
  708. package/dist/web-terminal.js +1 -1
  709. package/dist/web-terminal.js.map +1 -1
  710. package/dist/web-theme-store.d.ts +2 -2
  711. package/dist/web-theme-store.js +6 -3
  712. package/dist/web-theme-store.js.map +1 -1
  713. package/dist/web-theme.d.ts +29 -0
  714. package/dist/web-theme.js +89 -1
  715. package/dist/web-theme.js.map +1 -1
  716. package/dist/web-upload.d.ts +18 -1
  717. package/dist/web-upload.js +45 -7
  718. package/dist/web-upload.js.map +1 -1
  719. package/dist/web-widget.js.map +1 -1
  720. package/dist/webhook-emitter.js.map +1 -1
  721. package/dist/windows-shortcuts.d.ts +78 -0
  722. package/dist/windows-shortcuts.js +203 -0
  723. package/dist/windows-shortcuts.js.map +1 -0
  724. package/dist/workflow-templates/default.md +4 -1
  725. package/dist/ws-server.js.map +1 -1
  726. package/dist/yaml-shared-nodes.d.ts +25 -0
  727. package/dist/yaml-shared-nodes.js +185 -0
  728. package/dist/yaml-shared-nodes.js.map +1 -0
  729. package/launcher/agend-install.cjs +828 -0
  730. package/launcher/install-admission.cjs +4 -39
  731. package/launcher/postinstall.cjs +14 -12
  732. package/launcher/private-home.cjs +43 -0
  733. package/package.json +16 -13
  734. package/scripts/preinstall-guard.cjs +2 -5
  735. package/templates/windows-shortcuts.ps1 +181 -0
  736. package/launcher/old-updater-note.cjs +0 -48
@@ -8,8 +8,9 @@
8
8
  // #1665 first: the host's preferences go into this browser's cache before any module below reads its key.
9
9
  import { bootPrefs } from "./app-prefs.js";
10
10
  import { html, render } from "./app-html.js";
11
- import { Shell, handleKey, showDialog, closeDrawer, openDrawer, shellStore, retryable, setNewInstanceOpener } from "./app-shell.js";
11
+ import { Shell, handleKey, handleSearchKey, showDialog, closeDrawer, openDrawer, shellStore, retryable, setNewInstanceOpener, isMacLike } from "./app-shell.js";
12
12
  import { installSwipe } from "./app-swipe.js";
13
+ import { installTextUndo } from "./text-undo.js";
13
14
  import { startRouter, navStore, navigate } from "./app-nav.js";
14
15
  import { createStream } from "./app-stream.js";
15
16
  import { appStore, applyStatus, applyActivity, guestPage } from "./app-store.js";
@@ -93,6 +94,8 @@ if (mode === "full") {
93
94
  panels.set("log", { load: () => loadLog().then((m) => m.LogPanel) });
94
95
  // #1386 §6.3: desktop notifications for new "Needs you" items, in any panel, while this signed-in page is open.
95
96
  startNeedsNotifier({ open: (instance) => navigate(chatPath(instance)) });
97
+ // #2233: a backend sign-in running anywhere is shown on every admin page (the module lives behind the session gate).
98
+ import("/ui/js/backend-signin.js").then((m) => m.installSignIn(), () => {});
96
99
  }
97
100
  // #1665: this device's first upload of its own choices (once), then another device's changes at each status frame.
98
101
  // A guest's page only reads them (prefsWritable is false there).
@@ -121,6 +124,11 @@ if (!guest) installOwnerCss();
121
124
  }
122
125
 
123
126
  document.addEventListener("keydown", handleKey);
127
+ // #2293: Ctrl+K / ⌘K (and Ctrl+F in a chat) — an admin's full app only; the server refuses a guest's search anyway.
128
+ if (mode === "full" && !guest) document.addEventListener("keydown", handleSearchKey);
129
+ // #2342: Ctrl/⌘+Z and Ctrl+Shift+Z / Ctrl+Y / ⌘⇧Z in every text field, one history per field (the browser's is one
130
+ // for the whole page, and any script write wipes it).
131
+ installTextUndo({ mac: isMacLike() });
124
132
  // #1605: on a phone (the sidebar is a drawer), swipe right in the main area to open it, left to close it — the same
125
133
  // open/close as ☰ and the scrim. Nothing that owns a sideways drag (code, tables, the terminal, inputs, dialogs) and
126
134
  // never the left edge (iOS: "back").
@@ -11,8 +11,10 @@ register("card", {
11
11
  sizeSName: "Small", sizeMName: "Medium", sizeLName: "Large",
12
12
  byHuman: "set by a person",
13
13
  byAgent: "set by the agent",
14
+ menu: "Identity card",
14
15
  show: "Show card",
15
16
  hide: "Hide card",
17
+ showRow: "Show picture and bio",
16
18
  bannerSafe: "Every screen",
17
19
  bannerPhone: "Phone · M card",
18
20
  },
@@ -24,8 +26,10 @@ register("card", {
24
26
  sizeSName: "小", sizeMName: "中", sizeLName: "大",
25
27
  byHuman: "由人設定",
26
28
  byAgent: "由 agent 設定",
29
+ menu: "身分卡",
27
30
  show: "顯示卡片",
28
31
  hide: "隱藏卡片",
32
+ showRow: "顯示小圖和介紹",
29
33
  bannerSafe: "所有螢幕",
30
34
  bannerPhone: "手機 · 中卡片",
31
35
  },
@@ -13,7 +13,7 @@ const episodes = new WeakSet();
13
13
 
14
14
  /** `current` belongs to the page/session episode. Route cleanup only releases its contribution. */
15
15
  export function createAppEffectRuntime({ window: host, current, observe, onChange = () => {}, onDispose = () => {}, resolveOwnerTarget = null, onOwnerUnavailable = () => {}, factories = {} }) {
16
- let dead = false, error = null, loader = null, registry = null, writer = null, source = null, personal = null, trial = null, pending = null, lastMetadata = null, serial = 0, revision = 0, stamp = null, syncing = false, queued = false;
16
+ let dead = false, claimed = false, error = null, loader = null, registry = null, writer = null, source = null, personal = null, trial = null, pending = null, lastMetadata = null, serial = 0, revision = 0, stamp = null, syncing = false, queued = false;
17
17
  const bindings = new Map(), profiles = new Map();
18
18
  let lastContext = null, playbackUnavailable = null;
19
19
  const identity = effectPlaybackIdentity(host), auth = host?.AgendAuth;
@@ -26,7 +26,7 @@ export function createAppEffectRuntime({ window: host, current, observe, onChang
26
26
  };
27
27
  const placementIdentity = p => JSON.stringify([p.by, p.manifest.layer, p.params]);
28
28
  const clock = () => host.performance.now();
29
- let offAuth = null;
29
+ let offAuth = null, disposed = null;
30
30
  const snapshot = s => {
31
31
  const effects = s?.metadata?.effects ?? [], known = registry?.snapshot?.() ?? [];
32
32
  const rows = effects.map(p => {
@@ -76,16 +76,18 @@ export function createAppEffectRuntime({ window: host, current, observe, onChang
76
76
  if (pending?.source === s) safe(() => pending.controller.abort());
77
77
  revision++; stamp = null;
78
78
  }
79
- function dispose() {
80
- if (dead) return; dead = true; discard(source);
79
+ function dispose(restartable = false) {
80
+ if (dead) return disposed; dead = true; discard(source);
81
81
  safe(() => trial?.dispose()); safe(() => pending?.controller.abort()); safe(() => registry?.dispose?.()); safe(() => loader?.dispose?.()); safe(() => personal?.dispose()); safe(() => writer?.dispose()); safe(() => offAuth?.());
82
82
  safe(() => host?.removeEventListener?.("pagehide", dispose));
83
83
  for (const row of profiles.values()) safe(() => row.collector.dispose()); profiles.clear(); bindings.clear(); safe(() => onDispose({ error }));
84
+ disposed = Promise.all([safe(() => loader?.whenDisposed?.()), safe(() => registry?.whenDisposed?.())]).then(() => { if (restartable === true && claimed) episodes.delete(host); });
85
+ return disposed;
84
86
  }
85
87
  function fail(reason) { if (dead) return; error = reason; dispose(); safe(() => onChange({ error, rows: [], effects: [], loading: false })); }
86
88
  const unavailable = { ok: false, sync() {}, changedChat() {}, reply() {}, detachChat() {}, attachChat() { return null; }, attachTrial() { return null; }, stopTrial() {}, trialSnapshot: () => ({ rows: [] }), snapshot: () => snapshot(null), dispose };
87
89
  if (!host || typeof host !== "object" || episodes.has(host) || !identity || typeof current !== "function" || typeof observe !== "function" || typeof auth?.onSessionEnd !== "function" || typeof auth?.sessionEnded !== "function") return unavailable;
88
- episodes.add(host); // Claim before invoking current/auth callbacks: one attempt per Window episode.
90
+ episodes.add(host); claimed = true; // Claim before invoking current/auth callbacks: one attempt per Window episode.
89
91
  if (!alive()) { dispose(); return unavailable; }
90
92
  try {
91
93
  offAuth = auth.onSessionEnd(dispose);
@@ -1,3 +1,4 @@
1
+ import { chatEffectIdentity } from "./effect-display-metadata.js";
1
2
  /** #1629: one committed local Chat lease joins the reviewed host-only effect primitives. */
2
3
  import { createEffectRuntimeLoader } from "./effect-runtime-loader.js";
3
4
  import { createEffectRegistry } from "./effect-registry.js";
@@ -43,13 +44,7 @@ export function createEffectWriter(host, current) {
43
44
  }
44
45
 
45
46
  /** Frozen, server-rendered session identity only. A header-token/public/View load has no identity. */
46
- export function chatEffectIdentity(host) {
47
- try {
48
- const b = host.document.body.dataset, x = JSON.parse(host.document.documentElement.getAttribute("data-prefs") || "null");
49
- if (b.mode !== "full" || b.tier === "guest" || b.publicLink === "1" || b.webTransport === "poll" || !["person", "operator"].includes(x?.ownerScope) || x.unreadable === true || typeof x.ownerEpoch !== "string" || !/^[a-f0-9]{16}$/.test(x.ownerEpoch)) return null;
50
- return Object.freeze({ epoch: x.ownerEpoch, scope: x.ownerScope });
51
- } catch { return null; }
52
- }
47
+ export { chatEffectIdentity } from "./effect-display-metadata.js";
53
48
  /** Chat-only public/guest capability stays separate from personal preferences and management. */
54
49
  export function effectPlaybackIdentity(host) {
55
50
  try {
@@ -25,9 +25,10 @@ export function createEffectCursor({ window: host, current, readImage, onChange
25
25
  const unavailable = { ok: false, update() {}, snapshot: () => ({ status: "unavailable", id: null }), dispose() {} };
26
26
  if (!host?.document || owners.has(host) || ![current, readImage, onChange, host.getComputedStyle, host.Blob, host.URL?.createObjectURL, host.URL?.revokeObjectURL, host.AbortController, host.setTimeout, host.clearTimeout, host.performance?.now].every(x => typeof x === "function")) return unavailable;
27
27
  const token = {}; owners.set(host, token);
28
+ let finishDisposed; const disposed = new Promise(resolve => { finishDisposed = resolve; });
28
29
  const doc = host.document; let dead = false, previous = null, wanted = null, pending = null, active = null, blocked = null, generation = 0, checking = false, notifying = false, status = "off";
29
30
  const safe = fn => { try { return fn(); } catch { return null; } };
30
- const release = () => { if (dead && !pending && owners.get(host) === token) owners.delete(host); };
31
+ const release = () => { if (dead && !pending) { if (owners.get(host) === token) owners.delete(host); finishDisposed(); } };
31
32
  function alive() {
32
33
  if (dead || checking) return false;
33
34
  checking = true; const value = safe(() => current() === true && host.document === doc); checking = false;
@@ -121,5 +122,5 @@ export function createEffectCursor({ window: host, current, readImage, onChange
121
122
  }
122
123
  start(); tell();
123
124
  }
124
- return { ok: true, update, snapshot, dispose };
125
+ return { ok: true, update, snapshot, dispose, whenDisposed: () => disposed };
125
126
  }
@@ -0,0 +1,39 @@
1
+ /** #1629: closed host display metadata. Neither this object nor its token grants a trial read. */
2
+ const KEYS = ["v", "offer", "id", "title", "expiresAt"], ID = /^[0-9a-f]{32}$/;
3
+ const FORBIDDEN = /(?!\u200d)[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
4
+ const VISIBLE = /[^\p{M}\p{C}\p{Z}\u115f\u1160\u3164\uffa0\u2800]/u;
5
+ let graphemes = null;
6
+ export function checkEffectTrialOffer(value) {
7
+ try {
8
+ if (!value || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return null;
9
+ const keys = Reflect.ownKeys(value);
10
+ if (keys.length !== KEYS.length || keys.some(k => typeof k !== "string" || !KEYS.includes(k))) return null;
11
+ const x = Object.create(null);
12
+ for (const key of KEYS) {
13
+ const d = Object.getOwnPropertyDescriptor(value, key);
14
+ if (!d || !("value" in d) || !d.enumerable) return null;
15
+ x[key] = d.value;
16
+ }
17
+ if (x.v !== 1 || typeof x.offer !== "string" || !ID.test(x.offer) || typeof x.id !== "string" || !ID.test(x.id)
18
+ || typeof x.title !== "string" || x.title.length > 400 || x.title.normalize("NFC") !== x.title || x.title.trim() !== x.title
19
+ || FORBIDDEN.test(x.title) || !VISIBLE.test(x.title) || !Number.isSafeInteger(x.expiresAt) || x.expiresAt < 0) return null;
20
+ graphemes ??= new Intl.Segmenter(undefined, { granularity: "grapheme" });
21
+ let count = 0; for (const _part of graphemes.segment(x.title)) if (++count > 40) return null;
22
+ if (count < 1) return null;
23
+ return Object.freeze({ v: 1, offer: x.offer, id: x.id, title: x.title, expiresAt: x.expiresAt });
24
+ } catch { return null; }
25
+ }
26
+ /** Role and sender are host fields, never inferred from a message's text. Start must separately authorize. */
27
+ export function effectTrialMessage(message) {
28
+ if (!message || message.role !== "status" || message.sender !== "agend" || typeof message.instance !== "string"
29
+ || message.instance.length < 1 || message.instance.length > 128) return null;
30
+ return checkEffectTrialOffer(message.effectTrial);
31
+ }
32
+
33
+ export function chatEffectIdentity(host) {
34
+ try {
35
+ const b = host.document.body.dataset, x = JSON.parse(host.document.documentElement.getAttribute("data-prefs") || "null");
36
+ if (b.mode !== "full" || b.tier === "guest" || b.publicLink === "1" || b.webTransport === "poll" || !["person", "operator"].includes(x?.ownerScope) || x.unreadable === true || typeof x.ownerEpoch !== "string" || !/^[a-f0-9]{16}$/.test(x.ownerEpoch)) return null;
37
+ return Object.freeze({ epoch: x.ownerEpoch, scope: x.ownerScope });
38
+ } catch { return null; }
39
+ }
@@ -74,7 +74,14 @@ export function createOwnerEffectSource({ current, readMetadata, readResource, r
74
74
  },
75
75
  descriptors() {
76
76
  if (!alive() || !metadata || error) return [];
77
- const body = metadata, gen = generation, proof = safe(() => effectStockSnapshot(stock()));
77
+ const body = metadata, gen = generation;
78
+ // #2188: the stock snapshot walks the whole page (thousands of computed styles). With no slot holding an effect
79
+ // that could play, there is nothing for it to admit: skipped — every page change (a status, a chat switch) ran it.
80
+ if (!SLOTS.some(slot => body.slots[slot]?.status === "available" && failed.get(slot) !== body.slots[slot].id)) {
81
+ for (const slot of SLOTS) drop(slot);
82
+ return [];
83
+ }
84
+ const proof = safe(() => effectStockSnapshot(stock()));
78
85
  if (!fresh(body, gen)) return [];
79
86
  if (!proof) { clear(); return []; }
80
87
  const result = [];
@@ -77,9 +77,9 @@ export function allocateEffectFrames(descriptors, context) {
77
77
  if (!Array.isArray(descriptors) || descriptors.length > 128 || !plain(context)) return [];
78
78
  const keys = new Set(), duplicate = new Set();
79
79
  for (const d of descriptors) if (d && typeof d.key === "string") { if (keys.has(d.key)) duplicate.add(d.key); keys.add(d.key); }
80
- const result = descriptors.map(d => ({ key: d?.key, verdict: "off", reason: "unknown", queuePos: null }));
80
+ const result = descriptors.map(d => ({ key: d?.key, verdict: "off", reason: "descriptor_invalid", queuePos: null }));
81
81
  const gates = ["safe", "publicLink", "reducedMotion", "hidden", "enabled", "show", "transportReady", "constrained", "modal"];
82
- if (gates.some(k => typeof context[k] !== "boolean") || context.openInstance !== null && !instanceName(context.openInstance)) return result;
82
+ if (gates.some(k => typeof context[k] !== "boolean") || context.openInstance !== null && !instanceName(context.openInstance)) return result.map(r => ({ ...r, reason: "gates_unknown" }));
83
83
  let global = null;
84
84
  if (context.safe === true) global = "safe_mode";
85
85
  else if (context.reducedMotion === true) global = "reduced_motion";
@@ -2,7 +2,7 @@
2
2
  import { allocateEffectFrames, effectEvent, effectPlaybackReason } from "./effect-policy.js";
3
3
  import { createOpaqueEffectFrame } from "./effect-frame.js";
4
4
  import { createEffectGeometry, hostEffectRect } from "./effect-geometry.js";
5
- import { effectStockSnapshot, effectStockAllows } from "./effect-stock-snapshot.js";
5
+ import { effectStockSnapshot, effectStockAllows, effectStockRefusal } from "./effect-stock-snapshot.js";
6
6
  import { effectTrialStage, effectTrialStageIdentity, watchEffectTrialStage } from "./effect-trial-stage.js";
7
7
  import { EffectBudget } from "./effect-profiler.js";
8
8
 
@@ -42,7 +42,8 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
42
42
  try { if (!host?.document || !host.document.body || registries.has(host) || typeof load !== "function" || typeof stockSnapshot !== "function" || typeof onChange !== "function" || typeof onProfile !== "function" || typeof onMount !== "function" || typeof onRetire !== "function" || typeof clock !== "function" || !safety || ["allowed", "begin", "finish", "pause", "resume"].some(k => typeof safety[k] !== "function") || ["requestAnimationFrame", "cancelAnimationFrame", "setTimeout", "clearTimeout", "MutationObserver", "ResizeObserver", "AbortController"].some(k => typeof host[k] !== "function")) return { ok: false, reason: "registry_unsupported" }; } catch { return { ok: false, reason: "registry_unsupported" }; }
43
43
  let dead = false, blocked = null, revision = 0, last = null, lastView = null, frameSerial = 0, context = null, descriptors = [], raf = null, timer = null;
44
44
  const slots = new Map(), loads = new Set(), paused = new Map(), offs = [], observed = new Set(), failures = new Map(), results = new Map();
45
- let readingStock = false;
45
+ let finishDisposed; const disposed = new Promise(resolve => { finishDisposed = resolve; });
46
+ let readingStock = false, stockFailure = "stock_evidence_invalid", warned = null;
46
47
  let root, geometry, observer, resize, longTasks = null, longTasksSupported = false;
47
48
  const time = () => {
48
49
  let n; try { n = clock(); } catch { return null; }
@@ -68,10 +69,14 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
68
69
  const coverage = (d = null) => {
69
70
  if (dead || blocked || readingStock) return null;
70
71
  const before = revision; let proof = null; readingStock = true;
71
- try { proof = effectStockSnapshot(stockSnapshot(Object.freeze({ frameRoot: root }))); }
72
- catch { /* unknown is never permission */ }
72
+ let failure = "stock_provider_failed";
73
+ try { const raw = stockSnapshot(Object.freeze({ frameRoot: root })); proof = effectStockSnapshot(raw); failure = proof ? null : effectStockRefusal(raw); }
74
+ catch { /* unavailable stays denied, with a local diagnostic */ }
73
75
  finally { readingStock = false; }
74
76
  if (dead || blocked || before !== revision) return null;
77
+ stockFailure = failure;
78
+ if (failure !== warned) { warned = failure; if (failure) { try { host.console?.warn("[AgEnD effects] Playback blocked:", failure); } catch { /* display only */ } } }
79
+ if (dead || blocked || before !== revision) return null;
75
80
  return d === null || permits(d, proof) ? proof : null;
76
81
  };
77
82
  const position = (d, proof) => d.trialStage ? localStage(d, proof)?.rect ?? null : hostEffectRect(d.element);
@@ -150,7 +155,7 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
150
155
  const shown = why => (why === "gates_unknown" && !eligible() && gateReason()) || why;
151
156
  function view() {
152
157
  return descriptors.map(d => {
153
- const r = results.get(d.key) ?? { verdict: "off", reason: blocked ?? (!eligible() && gateReason()) ?? "unknown", queuePos: null }, s = slots.get(d.key);
158
+ const r = results.get(d.key) ?? { verdict: "off", reason: blocked ?? (eligible() ? stockFailure : gateReason()) ?? "runtime_unavailable", queuePos: null }, s = slots.get(d.key);
154
159
  // #2055 one display precedence: a global latch, then the sticky safety history, then this page's own pause/failure.
155
160
  const n = named.get(d.key), sticky = n && n.identity === signature(d) ? n.reason : null;
156
161
  return { key: d.key, id: d.id, ...r, ...(sticky && r.verdict === "queued" ? { verdict: "off", queuePos: null } : {}), phase: s?.frame ? s.ready ? "running" : "starting" : s ? "loading" : null,
@@ -173,7 +178,7 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
173
178
  };
174
179
  function observe() {
175
180
  const nodes = host.document.querySelectorAll("[data-trust]");
176
- if (nodes.length > 128) throw Error("trust coverage unavailable");
181
+ if (nodes.length > 4096) throw Error("trust coverage unavailable");
177
182
  const wanted = new Set([host.document.documentElement, ...nodes]);
178
183
  for (const d of descriptors) if (d.element?.ownerDocument === host.document && d.element.isConnected === true) wanted.add(d.element);
179
184
  for (const n of observed) if (!wanted.has(n)) { resize.unobserve(n); observed.delete(n); }
@@ -185,7 +190,14 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
185
190
  const proposal = revision;
186
191
  if (time() === null) blocked = "clock_unavailable";
187
192
  const hidden = context?.hidden === true || host.document.visibilityState !== "visible";
193
+ // #2188: nothing to place, nothing to prove — the stock walk (thousands of computed styles) is not run for an empty
194
+ // list; a frame still held is retired as superseded, exactly as an allocation of nothing would.
195
+ if (!blocked && descriptors.length === 0) {
196
+ for (const s of [...slots.values()]) { retire(s, "superseded"); if (dead || proposal !== revision) return; }
197
+ results.clear(); tell(); return;
198
+ }
188
199
  const stock = eligible() ? coverage() : null;
200
+ if (dead || proposal !== revision) return;
189
201
  if (blocked || !eligible() || !stock) {
190
202
  if (!stopAll(blocked ?? "gates_unknown")) return;
191
203
  results.clear();
@@ -234,7 +246,11 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
234
246
  if (s.frame && s.hiddenSince !== null) { s.hiddenSince = null; s.healthySince = last; if (s.budget.gates({ hidden: false, reducedMotion: false, saveData: false, show: true }).remove) retire(s, "hidden"); }
235
247
  if (dead || proposal !== revision) return;
236
248
  }
237
- try { observe(); } catch { stopAll("trust_geometry_unknown"); tell(); return; }
249
+ try { observe(); } catch {
250
+ if (dead || proposal !== revision || !stopAll("trust_geometry_unknown")) return;
251
+ for (const d of descriptors) results.set(d.key, { verdict: "off", reason: "trust_geometry_unknown", queuePos: null });
252
+ tell(); return;
253
+ }
238
254
  const max = context.constrained ? 1 : 3;
239
255
  for (const d of descriptors) {
240
256
  if (!chosen.has(d.key) || slots.has(d.key)) continue;
@@ -327,7 +343,7 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
327
343
  }).catch(() => { if (current(s)) retire(s, "resource_unavailable"); }).finally(() => {
328
344
  if (request.timer !== null) host.clearTimeout(request.timer);
329
345
  loads.delete(request); if (s.request === request) s.request = null;
330
- if (!dead) reconcile(); else if (loads.size === 0 && registries.get(host) === api) registries.delete(host);
346
+ if (!dead) reconcile(); else if (loads.size === 0) { if (registries.get(host) === api) registries.delete(host); finishDisposed(); }
331
347
  });
332
348
  }
333
349
  schedule(); tell();
@@ -431,7 +447,8 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
431
447
  } catch { return false; }
432
448
  }
433
449
  function pointer(event) {
434
- if (dead || blocked || !pointerGate() || event.isTrusted !== true) return;
450
+ // #2188: no frame to forward to — no gate to read (each read walks the page's computed styles, per pointer event).
451
+ if (dead || blocked || slots.size === 0 || !pointerGate() || event.isTrusted !== true) return;
435
452
  const kinds = { pointermove: "move", pointerdown: "down", pointerup: "up", click: "click", wheel: "wheel" }, kind = kinds[event.type];
436
453
  if (!kind || !finite(event.clientX) || !finite(event.clientY) || Math.abs(event.clientX) > 1e7 || Math.abs(event.clientY) > 1e7 || !Number.isInteger(event.buttons) || event.buttons < 0 || event.buttons > 31) return;
437
454
  try { const target = host.document.elementFromPoint(event.clientX, event.clientY); if (!target || typeof target.closest !== "function" || target.closest("[data-trust]")) return; } catch { return; }
@@ -502,7 +519,8 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
502
519
  },
503
520
  /** Host-only content-free signal API. Raw pointer publishing is refused; native pointer metadata is coalesced here. */
504
521
  publish(type, fields, instance = null) {
505
- if (dead || blocked || !globalAllowed() || context.hidden || !coverage() || !TYPES.includes(type)) return 0;
522
+ // #2188: no frame to send to — nothing to prove (the stock walk ran twice on every page change).
523
+ if (dead || blocked || slots.size === 0 || !globalAllowed() || context.hidden || !coverage() || !TYPES.includes(type)) return 0;
506
524
  const ts = time(); if (ts === null) { blocked = "clock_unavailable"; stopAll(blocked); tell(); return 0; }
507
525
  let sent = 0; const proposal = revision;
508
526
  for (const s of [...slots.values()]) {
@@ -513,11 +531,12 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
513
531
  }
514
532
  return sent;
515
533
  },
534
+ whenDisposed: () => disposed,
516
535
  dispose() {
517
536
  if (dead) return; dead = true; revision++; stopAll("disposed");
518
537
  if (raf !== null) host.cancelAnimationFrame(raf); if (timer !== null) host.clearTimeout(timer);
519
538
  observer.disconnect(); resize.disconnect(); longTasks?.disconnect(); for (const off of offs) off();
520
- geometry.dispose(); root.remove(); observed.clear(); if (loads.size === 0 && registries.get(host) === api) registries.delete(host);
539
+ geometry.dispose(); root.remove(); observed.clear(); if (loads.size === 0) { if (registries.get(host) === api) registries.delete(host); finishDisposed(); }
521
540
  },
522
541
  };
523
542
  // Read-only host geometry seam; no selector guessing among poster and live roots.
@@ -143,7 +143,8 @@ export function createEffectRuntimeLoader({ window: host, ownerEpoch, current, o
143
143
  if (!host || typeof host !== "object" || loaders.has(host) || typeof host.fetch !== "function" || typeof host.AbortController !== "function" || typeof host.setTimeout !== "function" || typeof host.clearTimeout !== "function" || typeof ownerEpoch !== "string" || !EPOCH.test(ownerEpoch) || typeof current !== "function" || typeof onRevoke !== "function") return { ok: false };
144
144
  const reservation = {}; loaders.set(host, reservation);
145
145
  let dead = false, revoked = false, previous = null; const pending = new Set();
146
- const releaseWindow = () => { if (dead && pending.size === 0 && loaders.get(host) === reservation) loaders.delete(host); };
146
+ let finishDisposed; const disposed = new Promise(resolve => { finishDisposed = resolve; });
147
+ const releaseWindow = () => { if (dead && pending.size === 0) { if (loaders.get(host) === reservation) loaders.delete(host); finishDisposed(); } };
147
148
  // Terminal state is latched before callbacks. Abort releases logical callers, never physical reservations.
148
149
  function revoke(reason) {
149
150
  if (dead || revoked) return;
@@ -215,6 +216,7 @@ export function createEffectRuntimeLoader({ window: host, ownerEpoch, current, o
215
216
  }
216
217
  const ownerRead = (signal, settled = false) => run("placements", `/ui/effects/owner?ownerEpoch=${ownerEpoch}`, checkEffectOwnerSlots, signal, settled);
217
218
  return { ok: true,
219
+ whenDisposed: () => disposed,
218
220
  owner(signal) { return ownerRead(signal); },
219
221
  placements(instance, signal) { return placementRead(instance, signal); },
220
222
  resource(input, signal) { return resourceRead(input, signal); },
@@ -32,3 +32,12 @@ export function effectStockAllows(snapshot, { layer, by } = {}) {
32
32
  const proof = effectStockSnapshot(snapshot);
33
33
  return !!proof && (layer === "behind" || layer === "front" && proof.front && (by === "human" || proof.agentFront));
34
34
  }
35
+
36
+ /** Display only. Refused provider metadata never becomes paint evidence or authority. */
37
+ export function effectStockRefusal(value) {
38
+ try {
39
+ if (!plain(value)) return "stock_evidence_invalid";
40
+ const d = Object.getOwnPropertyDescriptor(value, "reason");
41
+ return d && Object.hasOwn(d, "value") && typeof d.value === "string" && /^[a-z][a-z0-9_]{0,79}$/.test(d.value) ? d.value : "stock_evidence_invalid";
42
+ } catch { return "stock_evidence_invalid"; }
43
+ }
@@ -11,10 +11,10 @@ const SPECS = [
11
11
  ["confirmation", ".shell > .pending-stack, .shell .p-settings > .panel-body > .col > .pending-stack.inline"], ["preview", ".shell .chat-split > .pv-panel, .shell .chat-split > .pv-divider"],
12
12
  ["preview-menu", ".shell .thread details.pv-menu"], ["palette", ".shell .dock .cmd-palette"],
13
13
  ["drop", ".shell .p-chat > .drop-overlay"],
14
- ["thread-control", ".shell .chat-main > .amb-note, .shell .p-chat .jump-latest, .shell .thread .msg-tools, .shell .thread .st-more, .shell .thread .cb-head, .shell .thread .cb-more, .shell .thread .tc-head, .shell .thread .tc-more, .shell .thread .pv-head, .shell .thread .pv-note, .shell .thread .pv-banner, .shell .thread .effect-trial-offer, .shell .thread .click-chip"],
14
+ ["thread-control", ".shell .chat-main > .amb-note, .shell .p-chat .jump-latest, .shell .thread .msg-tools, .shell .thread .msg > div.msg-actions, .shell .thread .msg > button.msg-quote, .shell .thread .st-more, .shell .thread .cb-head, .shell .thread .cb-more, .shell .thread .tc-head, .shell .thread .tc-more, .shell .thread .pv-head, .shell .thread .pv-note, .shell .thread .pv-banner, .shell .thread .effect-trial-offer, .shell .thread .click-chip"],
15
15
  ["link", ".shell .thread .md a, .shell .thread .st-text > a.st-link, .shell .dock .prompts .txt > a.st-link"], ["attachment", ".shell .thread .atts"], ["media", ".shell .thread .att-media"],
16
16
  ["panel-navigation", ".shell .p-fleet > .seg, .shell .p-settings > .seg"],
17
- ["panel-content", ".shell .p-fleet > .panel-body, .shell .p-needs > .panel-body, .shell .p-settings > .panel-body, .shell .p-log > .panel-body, .shell .p-details > .panel-body, .shell .p-view > .panel-body, .shell .p-view > .v-term, .shell .p-view > .v-id, .shell .p-view > .v-card"],
17
+ ["panel-content", ".shell .p-fleet > .panel-body, .shell .p-needs > .panel-body, .shell .p-settings > .panel-body, .shell .p-log > .panel-body, .shell .p-details > .panel-body, .shell .p-view > .panel-body, .shell .p-view > .v-term, .shell .p-view > .v-id"],
18
18
  ["panel-controls", ".shell .p-log > .log-bar, .shell .p-settings > .s-pending"],
19
19
  ["session-ended", "body > .agend-session-ended[role=alert]"],
20
20
  ];
@@ -28,7 +28,7 @@ const PANELS = Object.freeze({
28
28
  settings: { required: [".panel-head", ".seg", ".panel-body"], optional: [".s-pending"] },
29
29
  log: { required: [".panel-head", ".panel-body"], optional: [".log-bar"] },
30
30
  details: { required: [".panel-head", ".panel-body"], optional: [] },
31
- view: { required: [".panel-head"], optional: [".panel-body", ".v-term", ".v-id", ".v-card"] },
31
+ view: { required: [".panel-head"], optional: [".panel-body", ".v-term", ".v-id"] },
32
32
  });
33
33
  function panelSurface(doc, chat) {
34
34
  if (chat) return { panel: chat, structural: STRUCTURAL, content: CONTENT, kind: "chat" };
@@ -37,8 +37,8 @@ function panelSurface(doc, chat) {
37
37
  const children = [...panel.children], count = selector => children.filter(el => el.matches(selector)).length;
38
38
  if (spec.required.some(selector => count(selector) !== 1) || spec.optional.some(selector => count(selector) > 1)
39
39
  || children.some(el => !el.matches([...spec.required, ...spec.optional, "dialog.dlg", "dialog.lb"].join(",")))) return null;
40
- if (kind === "view" && !(count(".panel-body") === 1 && !count(".v-term") && !count(".v-id") && !count(".v-card")
41
- || !count(".panel-body") && count(".v-term") === 1 && count(".v-card") === 1)) return null;
40
+ if (kind === "view" && !(count(".panel-body") === 1 && !count(".v-term") && !count(".v-id")
41
+ || !count(".panel-body") && count(".v-term") === 1 && count(".v-id") === 1)) return null;
42
42
  const prefix = `.p-${kind} > `;
43
43
  return { panel, kind, structural: [...STRUCTURAL.slice(0, 5), `.main > .p-${kind}`],
44
44
  content: [...CONTENT.filter(selector => !selector.startsWith(".p-chat") && !selector.startsWith(".chat-main")),
@@ -115,13 +115,36 @@ function stockBannerFill(host, el) {
115
115
  if (b.display !== "block" || el.offsetParent !== box) return null;
116
116
  return rect(box);
117
117
  }
118
+ function zeroClipMargin(host, style) {
119
+ const margin = style.overflowClipMargin ?? style.getPropertyValue?.("overflow-clip-margin");
120
+ // WebKit versions without this property still implement paint containment. An absent
121
+ // computed value is usable only when the engine explicitly reports it unsupported;
122
+ // unknown capability or a supported but unreadable/expanded margin cannot prove a box.
123
+ return margin === "0px" || [undefined, ""].includes(margin)
124
+ && host.CSS?.supports?.("overflow-clip-margin", "1px") === false;
125
+ }
118
126
  function protectedPaint(host, root, budget) {
127
+ // These two stock toolbar boxes physically clip ALL descendants, including fixed-position
128
+ // children. Their entire box is a hole; descendant ink cannot escape it. Inline, fragmented,
129
+ // expanded-clip or CSS-overridden boxes take the ordinary bounded walk instead.
130
+ const s = host.getComputedStyle(root);
131
+ if (root.matches?.(".shell .thread .msg-tools, .shell .thread .codeblock > .cb-head") && s.contain === "paint"
132
+ && s.display === "flex" && s.overflowX === "clip" && s.overflowY === "clip" && zeroClipMargin(host, s)
133
+ && none(s.filter) && none(s.backdropFilter) && s.borderImageSource === "none" && [undefined, "", "visible"].includes(s.contentVisibility) && root.getClientRects().length === 1) {
134
+ if (++budget.n > 4096) { budget.exceeded = true; return null; }
135
+ const r = rect(root), pad = outset(s);
136
+ // Containment clips descendants, not the root's own ink. Do not infer a world-space
137
+ // outset from local CSS lengths under a potentially transformed content ancestor.
138
+ if (!r || pad !== 0) return null;
139
+ return r;
140
+ }
119
141
  const nodes = [root, ...root.querySelectorAll("*")]; budget.n += nodes.length;
120
- if (budget.n > 4096) return null;
142
+ if (budget.n > 4096) { budget.exceeded = true; return null; }
121
143
  let union = null;
122
144
  for (const el of nodes) {
123
145
  if (!visible(host, el)) continue;
124
146
  const style = host.getComputedStyle(el), pad = outset(style);
147
+ if (style.borderImageSource !== undefined && style.borderImageSource !== "none" || ![undefined, "", "visible"].includes(style.contentVisibility)) return null;
125
148
  const r = none(style.filter) ? rect(el) : stockBannerFill(host, el);
126
149
  if (!r || pad === null || !none(style.backdropFilter)) return null;
127
150
  const a = { x: r.x - pad, y: r.y - pad, width: r.width + pad * 2, height: r.height + pad * 2 };
@@ -165,15 +188,23 @@ export function stockEffectTrust(host, { frameRoot = null, ownerCss = "unknown"
165
188
  if (s.position !== "relative" || s.zIndex !== "1" || !neutral(s)) return fail("stock_order_unknown");
166
189
  }
167
190
  const marked = [...doc.querySelectorAll("[data-trust]")], expected = new Set(), rects = [], budget = { n: 0 };
168
- if (marked.length > 128) return fail("stock_trust_unknown");
191
+ if (marked.length > 4096) return fail("stock_marker_limit");
169
192
  for (const { kind, selector } of STOCK_TRUST_INVENTORY) for (const el of doc.querySelectorAll(selector)) {
170
193
  if (el.ownerDocument !== doc || el.isConnected !== true || el.getAttribute("data-trust") !== kind) return fail("stock_trust_unknown");
171
194
  expected.add(el);
172
195
  }
173
196
  if (marked.some(el => !expected.has(el)) || surface.kind === "chat" && !chat.querySelector('.dock[data-trust="composer"]') || !surface.panel.querySelector('.panel-head[data-trust="header"]')) return fail("stock_trust_unknown");
174
197
  for (const el of marked) {
175
- const bounds = protectedPaint(host, el, budget); if (!bounds) return fail("stock_paint_unknown");
176
- if (bounds.width && bounds.height) rects.push(bounds);
198
+ const bounds = protectedPaint(host, el, budget); if (!bounds) return fail(budget.exceeded ? "stock_paint_limit" : "stock_paint_unknown");
199
+ // Off-screen history remains inventoried and paint-checked; it need not consume a
200
+ // viewport hole. Include the clip algorithm's extra 8px protection margin.
201
+ if (bounds.width && bounds.height && (!finite(host.innerHeight) || bounds.x + bounds.width + 8 >= 0 && bounds.y + bounds.height + 8 >= 0 && bounds.x - 8 <= host.innerWidth && bounds.y - 8 <= host.innerHeight)) rects.push(bounds);
202
+ }
203
+ // Keep the existing 128-hole transport bound. Conservative union may hide extra
204
+ // effect pixels; it can never reveal protected pixels, even for a dense viewport.
205
+ if (rects.length > 128) {
206
+ const rest = rects.splice(127), x = Math.min(...rest.map(r => r.x)), y = Math.min(...rest.map(r => r.y));
207
+ rects.push({ x, y, width: Math.max(...rest.map(r => r.x + r.width)) - x, height: Math.max(...rest.map(r => r.y + r.height)) - y });
177
208
  }
178
209
  if (doc.querySelector(".agend-session-ended")) return fail("session_ended");
179
210
  let barrier = [...doc.querySelectorAll(BARRIERS)].some(el => visible(host, el));
@@ -64,7 +64,7 @@ export function createEffectTrialSource({ window: host, current, ownerCurrent, s
64
64
  const lease = { identity, reply, stage, owner, current: x.current, onStop: x.onStop, startedAt: x.startedAt, until, dead: false, checking: false, pending: new Set(), timer: null, off: null, binding: null };
65
65
  lease.binding = Object.freeze({ kind: "trial", key: identity.key, id: identity.id, source: lease, generation: identity.generation });
66
66
  active = lease; used.add(stage.receipt);
67
- lease.off = watchEffectTrialStage(stage.receipt, () => stop(lease, "stage_ended"));
67
+ lease.off = watchEffectTrialStage(stage.receipt, reason => stop(lease, typeof reason === "string" ? reason : "stage_ended"));
68
68
  if (typeof lease.off !== "function" || constrainEffectTrialStage(stage.receipt, () => checked(lease)) !== true || !checked(lease)) { stop(lease, "stage_unavailable"); return null; }
69
69
  try { arm(lease); } catch { stop(lease, "trial_unavailable"); return null; }
70
70
  if (!checked(lease)) return null;
@@ -1,7 +1,7 @@
1
1
  /** #1629: host-issued LOCAL trial paint receipt. No authority, loader, frame factory or pool is created here. */
2
2
  import { effectTrialShadow } from "./effect-trial-shadow.js";
3
3
  import { effectHostStyle } from "./effect-host-style.js";
4
- import { effectStockSnapshot } from "./effect-stock-snapshot.js";
4
+ import { effectStockSnapshot, effectStockRefusal } from "./effect-stock-snapshot.js";
5
5
  import { STOCK_EFFECT_BARRIERS } from "./effect-stock-trust.js";
6
6
  const receipts = new WeakMap(), owners = new WeakMap();
7
7
  let serial = 0;
@@ -64,7 +64,8 @@ export function createEffectTrialStage({ window: host, panel, stage, binding: ra
64
64
  if (!own || typeof current !== "function" || typeof onStop !== "function" || !host?.document || !panel || !stage || owners.has(stage)) return null;
65
65
  const shell = effectTrialShadow(host, panel), hostSheet = effectHostStyle(host);
66
66
  let sheet; try { sheet = shell?.sheet; if (!shell || shell.stage !== stage || !hostSheet || !sheet || host.CSS?.supports("contain", "paint") !== true || host.CSS.supports("overflow", "clip") !== true) return null; } catch { return null; }
67
- const receipt = Object.freeze(Object.create(null)), frames = new Set(), listeners = new Set(); let dead = false, constraint = null;
67
+ const receipt = Object.freeze(Object.create(null)), frames = new Set(), listeners = new Set(); let dead = false, constraint = null, failure = "stage_unavailable";
68
+ const reject = reason => { failure = reason; return null; };
68
69
  const identity = Object.freeze({ key: own.key, id: own.id, instance: own.instance, generation: own.generation, serial: ++serial });
69
70
  const invalidate = reason => {
70
71
  if (dead) return; dead = true; receipts.delete(receipt); if (owners.get(stage) === receipt) owners.delete(stage);
@@ -76,45 +77,49 @@ export function createEffectTrialStage({ window: host, panel, stage, binding: ra
76
77
  };
77
78
  const blur = event => { if (event.target === host) invalidate("blur"); };
78
79
  function check(stock) {
80
+ failure = "trial_layout_unverified";
79
81
  try {
80
82
  // This callback may reenter disposal or replace the owner. Recheck identity after it returns.
81
- if (dead || current(own) !== true || constraint !== null && constraint() !== true || dead || owners.get(stage) !== receipt || dead) return null;
83
+ if (dead || current(own) !== true || constraint !== null && constraint() !== true || dead || owners.get(stage) !== receipt || dead) return reject("trial_current_changed");
82
84
  const proof = effectStockSnapshot(stock), doc = host.document;
83
- if (effectHostStyle(host) !== hostSheet || effectTrialShadow(host, panel) !== shell) return null;
85
+ if (!proof) return reject(effectStockRefusal(stock));
86
+ if (effectHostStyle(host) !== hostSheet || effectTrialShadow(host, panel) !== shell) return reject("trial_style_unavailable");
84
87
  // The own panel MUST still suppress ordinary foreground effects. Never synthesize front:true.
85
- if (!proof || proof.front !== false || doc.visibilityState !== "visible" || doc.hasFocus?.() !== true || doc.fullscreenElement || doc.pictureInPictureElement) return null;
88
+ if (doc.hasFocus?.() !== true) return reject("trial_window_unfocused");
89
+ if (doc.visibilityState !== "visible") return reject("hidden");
90
+ if (proof.front !== false || doc.fullscreenElement || doc.pictureInPictureElement) return reject("trial_overlay_unverified");
86
91
  const split = doc.querySelector(".main > .p-chat > .chat-split");
87
92
  if (!split || doc.querySelectorAll(".main > .p-chat").length !== 1 || doc.querySelectorAll(".chat-split > .pv-panel").length !== 1
88
- || panel.parentElement !== split || panel.ownerDocument !== doc || panel.isConnected !== true || panel.className !== "pv-panel effect-trial-panel" || panel.getAttribute("data-trust") !== "preview") return null;
93
+ || panel.parentElement !== split || panel.ownerDocument !== doc || panel.isConnected !== true || panel.className !== "pv-panel effect-trial-panel" || panel.getAttribute("data-trust") !== "preview") return reject("trial_panel_unavailable");
89
94
  const children = [...shell.root.children], names = ["effect-trial-style", "effect-trial-head", "effect-trial-controls", "effect-trial-body", "effect-trial-note"];
90
95
  if (panel.children.length !== 0 || children.length !== names.length || children.some((el, i) => el.className !== names[i]) || children[3].children.length !== 1 || children[3].firstElementChild !== stage
91
- || stage.className !== "effect-trial-stage" || stage.ownerDocument !== doc || stage.isConnected !== true || stage.hasAttribute("tabindex") || stage.hasAttribute("contenteditable")) return null;
96
+ || stage.className !== "effect-trial-stage" || stage.ownerDocument !== doc || stage.isConnected !== true || stage.hasAttribute("tabindex") || stage.hasAttribute("contenteditable")) return reject("trial_shadow_unverified");
92
97
  for (const control of [shell.head, shell.controls, shell.close, shell.stop, shell.note]) {
93
98
  const style = host.getComputedStyle(control);
94
- if (style.display === "none" || style.visibility !== "visible" || style.opacity !== "1" || !rect(control)) return null;
99
+ if (style.display === "none" || style.visibility !== "visible" || style.opacity !== "1" || !rect(control)) return reject("trial_controls_unavailable");
95
100
  }
96
101
  if ([...doc.querySelectorAll(STOCK_EFFECT_BARRIERS)].some(el => el !== panel && visible(host, el))
97
- || [...doc.querySelectorAll(".pv-panel")].some(el => el !== panel && visible(host, el))) return null;
102
+ || [...doc.querySelectorAll(".pv-panel")].some(el => el !== panel && visible(host, el))) return reject("trial_other_overlay");
98
103
  const active = doc.activeElement;
99
- if (active && active !== doc.body && active !== doc.documentElement && (active.matches("input,select,textarea,[contenteditable]") || active.isContentEditable)) return null;
104
+ if (active && active !== doc.body && active !== doc.documentElement && (active.matches("input,select,textarea,[contenteditable]") || active.isContentEditable)) return reject("trial_editable_focus");
100
105
  let el = stage, depth = 0;
101
- while (el) { const s = host.getComputedStyle(el); if (++depth > 128 || el.ownerDocument !== doc || !neutral(s) || s.opacity !== "1" || s.visibility !== "visible" || s.display === "none" || s.contain !== (el === stage ? "paint" : "none")) return null; if (el === doc.documentElement) break; el = el.parentElement ?? (el.getRootNode?.() === shell.root ? panel : null); }
102
- if (el !== doc.documentElement) return null;
106
+ while (el) { const s = host.getComputedStyle(el); if (++depth > 128 || el.ownerDocument !== doc || !neutral(s) || s.opacity !== "1" || s.visibility !== "visible" || s.display === "none" || s.contain !== (el === stage ? "paint" : "none")) return reject("trial_ancestor_paint"); if (el === doc.documentElement) break; el = el.parentElement ?? (el.getRootNode?.() === shell.root ? panel : null); }
107
+ if (el !== doc.documentElement) return reject("trial_ancestor_paint");
103
108
  const s = host.getComputedStyle(stage), r = rect(stage), p = rect(panel);
104
109
  if (!r || !p || s.position !== "relative" || s.zIndex !== "0" || s.overflowX !== "clip" || s.overflowY !== "clip"
105
110
  || s.paddingLeft !== "0px" || s.paddingRight !== "0px" || s.paddingTop !== "0px" || s.paddingBottom !== "0px"
106
111
  || ["borderLeftWidth", "borderRightWidth", "borderTopWidth", "borderBottomWidth"].some(k => s[k] !== "0px") || !none(s.boxShadow) || s.outlineStyle !== "none"
107
112
  || r.x < p.x || r.y < p.y || r.x + r.width > p.x + p.width || r.y + r.height > p.y + p.height
108
- || r.x < 0 || r.y < 0 || r.x + r.width > host.innerWidth || r.y + r.height > host.innerHeight) return null;
109
- if ([...stage.children].some(child => ![...frames].some(f => f.element === child))) return null;
113
+ || r.x < 0 || r.y < 0 || r.x + r.width > host.innerWidth || r.y + r.height > host.innerHeight) return reject("trial_clip_unverified");
114
+ if ([...stage.children].some(child => ![...frames].some(f => f.element === child))) return reject("trial_frame_unknown");
110
115
  const width = Math.floor(r.width), height = Math.floor(r.height);
111
- if (width < 1 || height < 1 || width > 4096 || height > 4096 || width * height > 8388608 || dead || owners.get(stage) !== receipt) return null;
112
- if (current(own) !== true || constraint !== null && constraint() !== true || dead || owners.get(stage) !== receipt || dead || stage.isConnected !== true || panel.parentElement !== split) return null;
116
+ if (width < 1 || height < 1 || width > 4096 || height > 4096 || width * height > 8388608 || dead || owners.get(stage) !== receipt) return reject("trial_size_limit");
117
+ if (current(own) !== true || constraint !== null && constraint() !== true || dead || owners.get(stage) !== receipt || dead || stage.isConnected !== true || panel.parentElement !== split) return reject("trial_current_changed");
113
118
  return { x: r.x, y: r.y, width, height };
114
- } catch { return null; }
119
+ } catch { return reject("trial_check_failed"); }
115
120
  }
116
121
  function project(stock) {
117
- const r = check(stock); if (!r) { invalidate("stage_unavailable"); return null; }
122
+ const r = check(stock); if (!r) { invalidate(failure); return null; }
118
123
  return Object.freeze({ root: stage, rect: Object.freeze(r), identity, bind });
119
124
  }
120
125
  function bind(frame, { layer } = {}, stock) {
@@ -131,7 +136,7 @@ export function createEffectTrialStage({ window: host, panel, stage, binding: ra
131
136
  };
132
137
  const handle = { ok: true, element: frame, remove, hide,
133
138
  sync(proof) {
134
- const r = check(proof); if (!r || removed) { invalidate("stage_unavailable"); return false; }
139
+ const r = check(proof); if (!r || removed) { invalidate(failure); return false; }
135
140
  try {
136
141
  const matches = visibility => {
137
142
  const s = host.getComputedStyle(frame), actual = rect(frame);
@@ -146,7 +151,7 @@ export function createEffectTrialStage({ window: host, panel, stage, binding: ra
146
151
  for (const [k, v] of Object.entries({ left: "0px", top: "0px", width: `${r.width}px`, height: `${r.height}px` })) rule.style.setProperty(k, v, "important");
147
152
  if (!matches("hidden")) throw Error("local geometry lost");
148
153
  rule.style.setProperty("visibility", "visible", "important"); shown = true; return true;
149
- } catch { invalidate("stage_unavailable"); return false; }
154
+ } catch { invalidate("trial_frame_geometry"); return false; }
150
155
  },
151
156
  };
152
157
  frames.add(handle);
@@ -154,7 +159,8 @@ export function createEffectTrialStage({ window: host, panel, stage, binding: ra
154
159
  const i = sheet.insertRule(`.${token}{}`, sheet.cssRules.length); rule = sheet.cssRules[i];
155
160
  for (const [k, v] of Object.entries({ position: "absolute", visibility: "hidden", "pointer-events": "none", "z-index": "0", opacity: layer === "front" ? "0.85" : "1", border: "0px", margin: "0px", padding: "0px", "box-sizing": "border-box", "min-width": "0px", "min-height": "0px", "max-width": "none", "max-height": "none", outline: "none", "box-shadow": "none", "background-color": "transparent", animation: "none", transition: "none" })) rule.style.setProperty(k, v, "important");
156
161
  frame.classList.add(token);
157
- if (host.getComputedStyle(frame).visibility !== "hidden" || !check(stock)) throw Error("initial local hiding lost");
162
+ if (host.getComputedStyle(frame).visibility !== "hidden") throw Error("initial local hiding lost");
163
+ if (!check(stock)) { remove(); invalidate(failure); return { ok: false }; }
158
164
  } catch { remove(); invalidate("stage_unavailable"); return { ok: false }; }
159
165
  return handle;
160
166
  }
@@ -16,7 +16,7 @@
16
16
  overflow: clip !important;
17
17
  background: #ffffff !important;
18
18
  color: #1b1b1f !important;
19
- font: 400 16px/1.4 system-ui, sans-serif !important;
19
+ font: 400 16px/1.4 system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", emoji !important;
20
20
  direction: ltr !important;
21
21
  unicode-bidi: isolate !important;
22
22
  text-align: start !important;