@songsid/agend 2.3.3-beta.1 → 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 (355) hide show
  1. package/dist/agent-cli.js +13 -112
  2. package/dist/agent-cli.js.map +1 -1
  3. package/dist/agent-endpoint.d.ts +0 -1
  4. package/dist/agent-endpoint.js +1 -9
  5. package/dist/agent-endpoint.js.map +1 -1
  6. package/dist/agent-whats-new.d.ts +3 -6
  7. package/dist/agent-whats-new.js +7 -18
  8. package/dist/agent-whats-new.js.map +1 -1
  9. package/dist/auth-api.d.ts +0 -7
  10. package/dist/auth-api.js +1 -15
  11. package/dist/auth-api.js.map +1 -1
  12. package/dist/authority/authority-state.js +1 -1
  13. package/dist/authority/authority-state.js.map +1 -1
  14. package/dist/authority/web-authority.d.ts +9 -4
  15. package/dist/authority/web-authority.js +10 -5
  16. package/dist/authority/web-authority.js.map +1 -1
  17. package/dist/backend/antigravity.js +6 -1
  18. package/dist/backend/antigravity.js.map +1 -1
  19. package/dist/backend/claude-code.d.ts +7 -0
  20. package/dist/backend/claude-code.js +34 -28
  21. package/dist/backend/claude-code.js.map +1 -1
  22. package/dist/backend/claude-transcript-errors.d.ts +18 -0
  23. package/dist/backend/claude-transcript-errors.js +19 -0
  24. package/dist/backend/claude-transcript-errors.js.map +1 -0
  25. package/dist/backend/codex-session-lookup.d.ts +16 -3
  26. package/dist/backend/codex-session-lookup.js +45 -11
  27. package/dist/backend/codex-session-lookup.js.map +1 -1
  28. package/dist/backend/codex.d.ts +16 -0
  29. package/dist/backend/codex.js +184 -35
  30. package/dist/backend/codex.js.map +1 -1
  31. package/dist/backend/grok.js +58 -12
  32. package/dist/backend/grok.js.map +1 -1
  33. package/dist/backend/kiro.js +2 -0
  34. package/dist/backend/kiro.js.map +1 -1
  35. package/dist/backend/muse.js +2 -1
  36. package/dist/backend/muse.js.map +1 -1
  37. package/dist/backend/types.d.ts +46 -0
  38. package/dist/backend/types.js.map +1 -1
  39. package/dist/bundled-skills.d.ts +4 -6
  40. package/dist/bundled-skills.js +10 -14
  41. package/dist/bundled-skills.js.map +1 -1
  42. package/dist/channel/adapters/discord.js +60 -17
  43. package/dist/channel/adapters/discord.js.map +1 -1
  44. package/dist/channel/mcp-server.js +5 -5
  45. package/dist/channel/mcp-server.js.map +1 -1
  46. package/dist/channel/mcp-tools.d.ts +1 -3
  47. package/dist/channel/mcp-tools.js +4 -58
  48. package/dist/channel/mcp-tools.js.map +1 -1
  49. package/dist/classic-channel-manager.d.ts +4 -1
  50. package/dist/classic-channel-manager.js +21 -7
  51. package/dist/classic-channel-manager.js.map +1 -1
  52. package/dist/cli.js +21 -4
  53. package/dist/cli.js.map +1 -1
  54. package/dist/config-history.d.ts +50 -0
  55. package/dist/config-history.js +263 -0
  56. package/dist/config-history.js.map +1 -0
  57. package/dist/config-validator.js +7 -7
  58. package/dist/config-validator.js.map +1 -1
  59. package/dist/config.d.ts +3 -0
  60. package/dist/config.js +11 -4
  61. package/dist/config.js.map +1 -1
  62. package/dist/daemon.d.ts +73 -3
  63. package/dist/daemon.js +334 -121
  64. package/dist/daemon.js.map +1 -1
  65. package/dist/daily-summary.d.ts +8 -1
  66. package/dist/daily-summary.js +8 -5
  67. package/dist/daily-summary.js.map +1 -1
  68. package/dist/dashboard-live.d.ts +1 -1
  69. package/dist/dashboard-live.js +3 -3
  70. package/dist/dashboard-live.js.map +1 -1
  71. package/dist/dashboard-permissions.d.ts +1 -1
  72. package/dist/dashboard-permissions.js +1 -3
  73. package/dist/dashboard-permissions.js.map +1 -1
  74. package/dist/delivery-outbox.d.ts +4 -0
  75. package/dist/delivery-outbox.js +12 -2
  76. package/dist/delivery-outbox.js.map +1 -1
  77. package/dist/doctor.d.ts +4 -0
  78. package/dist/doctor.js +16 -1
  79. package/dist/doctor.js.map +1 -1
  80. package/dist/fleet-level-config.js +1 -1
  81. package/dist/fleet-level-config.js.map +1 -1
  82. package/dist/fleet-manager.d.ts +70 -54
  83. package/dist/fleet-manager.js +257 -322
  84. package/dist/fleet-manager.js.map +1 -1
  85. package/dist/fleet-process-handlers.d.ts +5 -0
  86. package/dist/fleet-process-handlers.js +21 -0
  87. package/dist/fleet-process-handlers.js.map +1 -1
  88. package/dist/fleet-service-owner.d.ts +11 -0
  89. package/dist/fleet-service-owner.js +3 -0
  90. package/dist/fleet-service-owner.js.map +1 -0
  91. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +11 -1
  92. package/dist/general-knowledge/skills/session-management/SKILL.md +6 -0
  93. package/dist/general-knowledge/skills/web-appearance/SKILL.md +13 -204
  94. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +29 -67
  95. package/dist/instance-lifecycle.d.ts +19 -0
  96. package/dist/instance-lifecycle.js +52 -10
  97. package/dist/instance-lifecycle.js.map +1 -1
  98. package/dist/locale.js +92 -42
  99. package/dist/locale.js.map +1 -1
  100. package/dist/needs-you-hub.d.ts +1 -0
  101. package/dist/needs-you-hub.js +6 -3
  102. package/dist/needs-you-hub.js.map +1 -1
  103. package/dist/needs-you-live.d.ts +3 -1
  104. package/dist/needs-you-live.js +24 -2
  105. package/dist/needs-you-live.js.map +1 -1
  106. package/dist/needs-you.d.ts +13 -2
  107. package/dist/needs-you.js +11 -1
  108. package/dist/needs-you.js.map +1 -1
  109. package/dist/notify-socket.d.ts +10 -0
  110. package/dist/notify-socket.js +45 -0
  111. package/dist/notify-socket.js.map +1 -0
  112. package/dist/outbound-handlers.js +19 -7
  113. package/dist/outbound-handlers.js.map +1 -1
  114. package/dist/outbound-schemas.d.ts +0 -62
  115. package/dist/outbound-schemas.js +3 -42
  116. package/dist/outbound-schemas.js.map +1 -1
  117. package/dist/parked-notices.d.ts +87 -0
  118. package/dist/parked-notices.js +194 -0
  119. package/dist/parked-notices.js.map +1 -0
  120. package/dist/public-link-progress.d.ts +5 -2
  121. package/dist/public-link-progress.js +4 -3
  122. package/dist/public-link-progress.js.map +1 -1
  123. package/dist/public-web-gateway.js +0 -9
  124. package/dist/public-web-gateway.js.map +1 -1
  125. package/dist/public-web-link.d.ts +12 -0
  126. package/dist/public-web-link.js +29 -5
  127. package/dist/public-web-link.js.map +1 -1
  128. package/dist/quota-notice.d.ts +23 -0
  129. package/dist/quota-notice.js +22 -0
  130. package/dist/quota-notice.js.map +1 -0
  131. package/dist/scheduler/task-board.d.ts +0 -13
  132. package/dist/scheduler/task-board.js +0 -14
  133. package/dist/scheduler/task-board.js.map +1 -1
  134. package/dist/sd-notify.d.ts +10 -1
  135. package/dist/sd-notify.js +27 -2
  136. package/dist/sd-notify.js.map +1 -1
  137. package/dist/search/search-docs.d.ts +1 -1
  138. package/dist/search/search-docs.js +2 -2
  139. package/dist/search/search-docs.js.map +1 -1
  140. package/dist/settings-api.d.ts +16 -0
  141. package/dist/settings-api.js +55 -2
  142. package/dist/settings-api.js.map +1 -1
  143. package/dist/settings-change.js +3 -1
  144. package/dist/settings-change.js.map +1 -1
  145. package/dist/settings-confirmation.d.ts +17 -3
  146. package/dist/settings-confirmation.js +8 -5
  147. package/dist/settings-confirmation.js.map +1 -1
  148. package/dist/settings-http-confirmation.js +31 -1
  149. package/dist/settings-http-confirmation.js.map +1 -1
  150. package/dist/setup-wizard.d.ts +3 -0
  151. package/dist/setup-wizard.js +4 -2
  152. package/dist/setup-wizard.js.map +1 -1
  153. package/dist/task-board-waker.d.ts +4 -1
  154. package/dist/task-board-waker.js +13 -2
  155. package/dist/task-board-waker.js.map +1 -1
  156. package/dist/tool-permissions.js +3 -10
  157. package/dist/tool-permissions.js.map +1 -1
  158. package/dist/topic-commands.d.ts +27 -7
  159. package/dist/topic-commands.js +95 -36
  160. package/dist/topic-commands.js.map +1 -1
  161. package/dist/transcript-monitor.d.ts +7 -0
  162. package/dist/transcript-monitor.js +48 -3
  163. package/dist/transcript-monitor.js.map +1 -1
  164. package/dist/tunnel/cloudflared.d.ts +5 -0
  165. package/dist/tunnel/cloudflared.js +32 -1
  166. package/dist/tunnel/cloudflared.js.map +1 -1
  167. package/dist/tunnel/named-diagnostics.d.ts +2 -1
  168. package/dist/tunnel/named-diagnostics.js +4 -1
  169. package/dist/tunnel/named-diagnostics.js.map +1 -1
  170. package/dist/tunnel/named-link-test.d.ts +90 -0
  171. package/dist/tunnel/named-link-test.js +270 -0
  172. package/dist/tunnel/named-link-test.js.map +1 -0
  173. package/dist/tunnel/purpose-lane.d.ts +3 -1
  174. package/dist/tunnel/purpose-lane.js +2 -0
  175. package/dist/tunnel/purpose-lane.js.map +1 -1
  176. package/dist/types.d.ts +8 -6
  177. package/dist/ui/chat-ambient.js +4 -4
  178. package/dist/ui/chat-commands.js +3 -2
  179. package/dist/ui/chat-store.js +4 -1
  180. package/dist/ui/chat-strings.js +12 -46
  181. package/dist/ui/chat-thread.js +51 -59
  182. package/dist/ui/fleet-office-skin.js +37 -14
  183. package/dist/ui/fleet-office.js +31 -7
  184. package/dist/ui/html-attachment.js +22 -8
  185. package/dist/ui/panel-chat.js +21 -50
  186. package/dist/ui/panel-needs.js +11 -9
  187. package/dist/ui/panel-settings.js +5 -3
  188. package/dist/ui/preview-panel.js +12 -21
  189. package/dist/ui/preview.js +10 -3
  190. package/dist/ui/search-dialog.js +30 -14
  191. package/dist/ui/settings-appearance.js +1 -3
  192. package/dist/ui/settings-confirm.js +18 -0
  193. package/dist/ui/settings-guests.js +13 -4
  194. package/dist/ui/settings-learn.js +1 -1
  195. package/dist/ui/settings-mods.js +5 -12
  196. package/dist/ui/settings-named-test.js +144 -0
  197. package/dist/ui/settings-registry.js +0 -1
  198. package/dist/ui/settings-strings.js +14 -14
  199. package/dist/ui/settings-web-authority.js +4 -3
  200. package/dist/ui/shared/app-i18n.js +15 -4
  201. package/dist/ui/shared/app-needs.js +5 -1
  202. package/dist/ui/shared/app-prefs.js +17 -17
  203. package/dist/ui/shared/app-shell.js +47 -9
  204. package/dist/ui/shared/app-store.js +6 -2
  205. package/dist/ui/shared/app.css +33 -39
  206. package/dist/ui/shared/app.js +5 -4
  207. package/dist/ui/shared/instance-nav.js +9 -9
  208. package/dist/ui/shared/instance-switch.js +8 -2
  209. package/dist/ui/shared/panel-view.js +22 -8
  210. package/dist/ui/shared/view-strings.js +6 -0
  211. package/dist/ui/shared/web-authorize.js +35 -13
  212. package/dist/usage/usage-api.d.ts +3 -0
  213. package/dist/usage/usage-api.js +5 -1
  214. package/dist/usage/usage-api.js.map +1 -1
  215. package/dist/view-api.d.ts +2 -0
  216. package/dist/view-api.js +64 -0
  217. package/dist/view-api.js.map +1 -1
  218. package/dist/web-api.d.ts +9 -17
  219. package/dist/web-api.js +257 -371
  220. package/dist/web-api.js.map +1 -1
  221. package/dist/web-appearance-tools.d.ts +0 -2
  222. package/dist/web-appearance-tools.js +2 -5
  223. package/dist/web-appearance-tools.js.map +1 -1
  224. package/dist/web-appearance-view.d.ts +0 -6
  225. package/dist/web-appearance-view.js +0 -1
  226. package/dist/web-appearance-view.js.map +1 -1
  227. package/dist/web-appearance.d.ts +14 -7
  228. package/dist/web-appearance.js +5 -6
  229. package/dist/web-appearance.js.map +1 -1
  230. package/dist/web-asset-parts.d.ts +1 -17
  231. package/dist/web-asset-parts.js +1 -15
  232. package/dist/web-asset-parts.js.map +1 -1
  233. package/dist/web-auth.js +1 -7
  234. package/dist/web-auth.js.map +1 -1
  235. package/dist/web-chat-history.d.ts +3 -7
  236. package/dist/web-chat-history.js +10 -17
  237. package/dist/web-chat-history.js.map +1 -1
  238. package/dist/web-commands.d.ts +9 -1
  239. package/dist/web-commands.js +13 -0
  240. package/dist/web-commands.js.map +1 -1
  241. package/dist/web-experimental.d.ts +2 -11
  242. package/dist/web-experimental.js +8 -36
  243. package/dist/web-experimental.js.map +1 -1
  244. package/dist/web-guest-access.d.ts +40 -2
  245. package/dist/web-guest-access.js +50 -14
  246. package/dist/web-guest-access.js.map +1 -1
  247. package/dist/web-mod-bundle.d.ts +2 -45
  248. package/dist/web-mod-bundle.js +15 -63
  249. package/dist/web-mod-bundle.js.map +1 -1
  250. package/dist/web-mod-store.d.ts +3 -48
  251. package/dist/web-mod-store.js +30 -97
  252. package/dist/web-mod-store.js.map +1 -1
  253. package/dist/web-prefs.d.ts +13 -0
  254. package/dist/web-prefs.js +38 -0
  255. package/dist/web-prefs.js.map +1 -1
  256. package/dist/web-preview.d.ts +6 -13
  257. package/dist/web-preview.js +12 -23
  258. package/dist/web-preview.js.map +1 -1
  259. package/dist/web-session.d.ts +11 -3
  260. package/dist/web-session.js +22 -11
  261. package/dist/web-session.js.map +1 -1
  262. package/dist/web-settings-patch.d.ts +1 -0
  263. package/dist/web-settings-patch.js +6 -3
  264. package/dist/web-settings-patch.js.map +1 -1
  265. package/dist/web-settings-tools.d.ts +0 -13
  266. package/dist/web-settings-tools.js +12 -84
  267. package/dist/web-settings-tools.js.map +1 -1
  268. package/launcher/agend-install.cjs +7 -1
  269. package/launcher/fleet-service-owner.cjs +150 -0
  270. package/package.json +1 -1
  271. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +0 -376
  272. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +0 -673
  273. package/dist/task-board-summary.d.ts +0 -101
  274. package/dist/task-board-summary.js +0 -177
  275. package/dist/task-board-summary.js.map +0 -1
  276. package/dist/ui/app-effects.js +0 -251
  277. package/dist/ui/chat-effect-posters.js +0 -42
  278. package/dist/ui/chat-effects.js +0 -167
  279. package/dist/ui/effect-trial-controller.js +0 -124
  280. package/dist/ui/effect-trial-offer.js +0 -2
  281. package/dist/ui/effect-trial-panel.js +0 -40
  282. package/dist/ui/effects-waker.js +0 -2
  283. package/dist/ui/settings-effects.js +0 -202
  284. package/dist/ui/settings-owner-effects.js +0 -82
  285. package/dist/ui/shared/effect-app-runtime.js +0 -299
  286. package/dist/ui/shared/effect-baseline.js +0 -64
  287. package/dist/ui/shared/effect-chat-runtime.js +0 -162
  288. package/dist/ui/shared/effect-cursor.js +0 -126
  289. package/dist/ui/shared/effect-display-metadata.js +0 -39
  290. package/dist/ui/shared/effect-frame.js +0 -146
  291. package/dist/ui/shared/effect-geometry.js +0 -137
  292. package/dist/ui/shared/effect-host-style.js +0 -10
  293. package/dist/ui/shared/effect-owner-regions.js +0 -74
  294. package/dist/ui/shared/effect-owner-source.js +0 -122
  295. package/dist/ui/shared/effect-policy.js +0 -151
  296. package/dist/ui/shared/effect-poster-reader.js +0 -98
  297. package/dist/ui/shared/effect-posters.js +0 -117
  298. package/dist/ui/shared/effect-profiler.js +0 -184
  299. package/dist/ui/shared/effect-profiles.js +0 -65
  300. package/dist/ui/shared/effect-registry.js +0 -545
  301. package/dist/ui/shared/effect-runtime-loader.js +0 -236
  302. package/dist/ui/shared/effect-safety.js +0 -153
  303. package/dist/ui/shared/effect-stock-snapshot.js +0 -43
  304. package/dist/ui/shared/effect-stock-trust.js +0 -217
  305. package/dist/ui/shared/effect-trial-shadow.js +0 -62
  306. package/dist/ui/shared/effect-trial-source.js +0 -103
  307. package/dist/ui/shared/effect-trial-stage.js +0 -170
  308. package/dist/ui/shared/effect-trial.css +0 -40
  309. package/dist/ui/shared/feature-flags.js +0 -127
  310. package/dist/ui/shared/owner-effect-prefs.js +0 -117
  311. package/dist/web-effect-bootstrap.d.ts +0 -12
  312. package/dist/web-effect-bootstrap.js +0 -49
  313. package/dist/web-effect-bootstrap.js.map +0 -1
  314. package/dist/web-effect-bundle.d.ts +0 -28
  315. package/dist/web-effect-bundle.js +0 -171
  316. package/dist/web-effect-bundle.js.map +0 -1
  317. package/dist/web-effect-canonical.d.ts +0 -8
  318. package/dist/web-effect-canonical.js +0 -27
  319. package/dist/web-effect-canonical.js.map +0 -1
  320. package/dist/web-effect-library.d.ts +0 -114
  321. package/dist/web-effect-library.js +0 -530
  322. package/dist/web-effect-library.js.map +0 -1
  323. package/dist/web-effect-playback.d.ts +0 -30
  324. package/dist/web-effect-playback.js +0 -71
  325. package/dist/web-effect-playback.js.map +0 -1
  326. package/dist/web-effect-poster.d.ts +0 -8
  327. package/dist/web-effect-poster.js +0 -52
  328. package/dist/web-effect-poster.js.map +0 -1
  329. package/dist/web-effect-profiles.d.ts +0 -118
  330. package/dist/web-effect-profiles.js +0 -181
  331. package/dist/web-effect-profiles.js.map +0 -1
  332. package/dist/web-effect-service.d.ts +0 -93
  333. package/dist/web-effect-service.js +0 -335
  334. package/dist/web-effect-service.js.map +0 -1
  335. package/dist/web-effect-tools.d.ts +0 -48
  336. package/dist/web-effect-tools.js +0 -129
  337. package/dist/web-effect-tools.js.map +0 -1
  338. package/dist/web-effect-trials.d.ts +0 -86
  339. package/dist/web-effect-trials.js +0 -204
  340. package/dist/web-effect-trials.js.map +0 -1
  341. package/dist/web-effect-upload.d.ts +0 -27
  342. package/dist/web-effect-upload.js +0 -185
  343. package/dist/web-effect-upload.js.map +0 -1
  344. package/dist/web-effect-worker.d.ts +0 -8
  345. package/dist/web-effect-worker.js +0 -170
  346. package/dist/web-effect-worker.js.map +0 -1
  347. package/dist/web-effect.d.ts +0 -103
  348. package/dist/web-effect.js +0 -153
  349. package/dist/web-effect.js.map +0 -1
  350. package/dist/web-experimental-http.d.ts +0 -2
  351. package/dist/web-experimental-http.js +0 -12
  352. package/dist/web-experimental-http.js.map +0 -1
  353. package/dist/web-mod-agent.d.ts +0 -50
  354. package/dist/web-mod-agent.js +0 -207
  355. package/dist/web-mod-agent.js.map +0 -1
@@ -1,184 +0,0 @@
1
- /** #1629: host observations only. This pure module mounts nothing and accepts no frame/Worker messages. */
2
- const finite = v => typeof v === "number" && Number.isFinite(v);
3
- const plain = v => !!v && (Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
4
- const DAY = 86400000;
5
- export const EFFECT_BUDGETS = Object.freeze({
6
- standard: Object.freeze({ fps: 55, longTaskMsPerSecond: 50 }),
7
- constrained: Object.freeze({ fps: 50, longTaskMsPerSecond: 25 }),
8
- });
9
- const deviceClass = v => v === "standard" || v === "constrained";
10
- const id = v => typeof v === "string" && /^[0-9a-f]{32}$/.test(v);
11
-
12
- /** One host-owned mount. The registry must remove the frame when remove is true, never merely hide it. */
13
- export class EffectBudget {
14
- constructor({ device, baselineFps, clock = () => performance.now(), longTasksSupported = false } = {}) {
15
- if (!deviceClass(device) || baselineFps !== undefined && (!finite(baselineFps) || baselineFps <= 0 || baselineFps > 1000) || typeof clock !== "function" || typeof longTasksSupported !== "boolean") throw new TypeError("effect budget options");
16
- this.device = device;
17
- // Legacy host measurements may still be supplied by pure probes. Product playback starts
18
- // immediately and learns cadence concurrently from host rAF, never Worker timing.
19
- // Freeze before the first report: a mount's profile floor must remain coherent.
20
- this.fpsFloor = baselineFps === undefined ? null : Math.min(EFFECT_BUDGETS[device].fps, baselineFps * 0.9);
21
- this.cadence = [];
22
- this.cadenceAt = null;
23
- this.clock = clock;
24
- this.longTasksSupported = longTasksSupported;
25
- this.last = null;
26
- this.epoch = this.time();
27
- this.lastWindow = null;
28
- this.frames = [];
29
- this.tasks = [];
30
- this.overflow = false;
31
- this.hiddenAt = null;
32
- this.verdict = "ok";
33
- this.reason = null;
34
- this.badWindows = 0;
35
- this.metrics = null;
36
- this.loadMs = null;
37
- if (this.epoch === null) this.stop("clock_unavailable");
38
- }
39
- time() {
40
- let now;
41
- try { now = this.clock(); } catch { return null; }
42
- if (!finite(now) || now < 0 || this.last !== null && now < this.last) return null;
43
- this.last = now;
44
- return now;
45
- }
46
- stop(reason = "stopped") {
47
- if (this.verdict === "paused") return this.snapshot();
48
- this.verdict = "paused";
49
- this.reason = reason;
50
- this.frames = [];
51
- this.tasks = [];
52
- return this.snapshot();
53
- }
54
- /** Invoke on host-observed load, not on child-provided timing. First load only. */
55
- loaded() {
56
- const now = this.time();
57
- if (now === null) return this.stop("clock_unavailable");
58
- if (this.verdict !== "paused" && this.loadMs === null) this.loadMs = now - this.epoch;
59
- return this.snapshot();
60
- }
61
- /** Invoke from the host's rAF callback; elapsed time always comes from the host clock. */
62
- frame() {
63
- const now = this.time();
64
- if (now === null) return this.stop("clock_unavailable");
65
- if (this.verdict === "paused" || this.hiddenAt !== null) return this.snapshot();
66
- if (this.fpsFloor === null) {
67
- const interval = this.cadenceAt === null ? null : now - this.cadenceAt;
68
- this.cadenceAt = now;
69
- if (interval !== null && interval >= 1 && interval <= 1000) {
70
- if (this.cadence.length === 256) this.cadence.shift();
71
- this.cadence.push(interval);
72
- }
73
- }
74
- if (now < this.epoch + 1000) return this.snapshot();
75
- this.trim(now);
76
- if (this.frames.at(-1) !== now) {
77
- if (this.frames.length >= 2048) this.overflow = true;
78
- else this.frames.push(now);
79
- }
80
- return this.snapshot();
81
- }
82
- /** Only the host observer calls this. `attributed` means it matched THIS host-owned container. */
83
- longTask(start, duration, attributed = false) {
84
- const now = this.time();
85
- if (now === null) return this.stop("clock_unavailable");
86
- if (this.verdict === "paused" || this.hiddenAt !== null || !this.longTasksSupported) return false;
87
- if (!finite(start) || start < 0 || !finite(duration) || duration < 50 || duration > 60000 || start + duration > now || typeof attributed !== "boolean") return false;
88
- const from = Math.max(start, this.epoch + 1000, now - 2000), to = start + duration;
89
- if (from >= to) return false;
90
- this.trim(now);
91
- if (this.tasks.length >= 256) { this.overflow = true; return false; }
92
- this.tasks.push({ from, to, attributed });
93
- return true;
94
- }
95
- trim(now) {
96
- this.frames = this.frames.filter(t => t > now - 2000);
97
- this.tasks = this.tasks.filter(t => t.to > now - 2000);
98
- }
99
- /** Strict booleans: unknown page gates fail closed. No setting can revive a paused mount. */
100
- gates(raw = {}) {
101
- const now = this.time();
102
- if (now === null) return this.stop("clock_unavailable");
103
- if (!plain(raw)) return this.stop("gates_unknown");
104
- const { hidden, reducedMotion, show } = raw;
105
- if ([hidden, reducedMotion, show].some(v => typeof v !== "boolean")) return this.stop("gates_unknown");
106
- if (this.verdict === "paused") return this.snapshot();
107
- if (reducedMotion || !show) return this.stop(reducedMotion ? "reduced_motion" : "viewer_off");
108
- if (hidden && this.hiddenAt === null) this.hiddenAt = now;
109
- if (hidden && now - this.hiddenAt >= 10000) return this.stop("hidden");
110
- if (!hidden && this.hiddenAt !== null) {
111
- // A delayed visibility callback must not revive a frame whose removal deadline already passed.
112
- if (now - this.hiddenAt >= 10000) return this.stop("hidden");
113
- this.hiddenAt = null;
114
- this.epoch = now;
115
- this.lastWindow = null;
116
- this.frames = [];
117
- this.tasks = [];
118
- this.overflow = false;
119
- this.badWindows = 0;
120
- this.metrics = null;
121
- this.cadence = []; this.cadenceAt = null;
122
- }
123
- return this.snapshot();
124
- }
125
- /** Poll no faster than once per second; a delayed callback never fabricates missed windows. */
126
- poll() {
127
- const now = this.time();
128
- if (now === null) return this.stop("clock_unavailable");
129
- if (this.verdict === "paused") return this.snapshot();
130
- if (this.hiddenAt !== null) return now - this.hiddenAt >= 10000 ? this.stop("hidden") : this.snapshot();
131
- if (now < this.epoch + 3000 || this.lastWindow !== null && now - this.lastWindow < 1000) return this.snapshot();
132
- this.lastWindow = now;
133
- this.trim(now);
134
- const sum = attributed => this.tasks.filter(t => attributed === null || t.attributed === attributed)
135
- .reduce((n, t) => n + Math.max(0, t.to - Math.max(t.from, now - 2000)), 0) / 2;
136
- const fps = this.frames.length / 2;
137
- const hostMs = this.longTasksSupported ? sum(null) : null;
138
- const ownMs = this.longTasksSupported && this.tasks.some(t => t.attributed) ? sum(true) : null;
139
- const limits = EFFECT_BUDGETS[this.device];
140
- if (this.fpsFloor === null && this.cadence.length >= 3) {
141
- // Faster observed intervals distinguish intermittent jank from a genuinely slower
142
- // display. This is a live reference, not an empty-page health certification.
143
- const sorted = [...this.cadence].sort((a, b) => a - b);
144
- const interval = sorted[Math.ceil(sorted.length * (sorted.length < 8 ? 0.5 : 0.2)) - 1];
145
- this.fpsFloor = Math.min(limits.fps, 900 / interval);
146
- this.cadence = []; this.cadenceAt = null;
147
- }
148
- const bad = this.overflow || this.fpsFloor === null || fps < this.fpsFloor || hostMs !== null && hostMs > limits.longTaskMsPerSecond;
149
- this.metrics = this.fpsFloor === null ? null : { at: now, hostFps: fps, hostLongTaskMsPerSecond: hostMs, attributedLongTaskMsPerSecond: ownMs,
150
- attribution: ownMs === null ? "unknown" : "observed", fpsFloor: this.fpsFloor, windowMs: 2000 };
151
- this.overflow = false;
152
- if (bad) {
153
- this.badWindows++;
154
- this.verdict = "degraded";
155
- this.reason = "host_budget";
156
- if (this.badWindows >= 3) return this.stop("host_budget");
157
- } else this.badWindows = 0;
158
- return this.snapshot();
159
- }
160
- snapshot() {
161
- const remove = this.verdict === "paused";
162
- return { verdict: this.verdict, reason: this.reason, remove, forward: !remove && this.hiddenAt === null,
163
- quality: this.verdict === "ok" ? "normal" : "low", pointerHz: this.verdict === "ok" ? 60 : 30,
164
- badWindows: this.badWindows, loadMs: this.loadMs, metrics: this.metrics ? { ...this.metrics } : null };
165
- }
166
- }
167
-
168
- /** Persisted calendar policy is separate from monotonic measurement. No storage is opened by this module. */
169
- export function newEffectPauseHistory(effectId, device, wall) {
170
- if (!id(effectId) || !deviceClass(device) || !finite(wall) || wall < 0) return null;
171
- return { v: 1, id: effectId, device, pauses: [], off: false, lastWall: wall };
172
- }
173
- export function recordEffectPause(history, wall) {
174
- if (!plain(history) || Object.keys(history).sort().join(",") !== "device,id,lastWall,off,pauses,v" || history.v !== 1 || !id(history.id) || !deviceClass(history.device) || typeof history.off !== "boolean" || !finite(history.lastWall) || history.lastWall < 0 || !finite(wall) || wall < 0 || !Array.isArray(history.pauses) || history.pauses.length > 3) return { ok: false, error: "pause_history_unknown" };
175
- let previous = -1;
176
- for (const at of history.pauses) {
177
- if (!finite(at) || at < 0 || at < previous || at > history.lastWall) return { ok: false, error: "pause_history_unknown" };
178
- previous = at;
179
- }
180
- // A wall-clock rollback cannot age out pauses. A forward jump can; off remains sticky for this content id.
181
- const now = Math.max(wall, history.lastWall);
182
- const pauses = [...history.pauses.filter(t => t > now - DAY), now].slice(-3);
183
- return { ok: true, history: { ...history, pauses, lastWall: now, off: history.off || pauses.length >= 3 } };
184
- }
@@ -1,65 +0,0 @@
1
- /** #1629: bounded host-window quantiles; not a frame message handler or admission verdict. */
2
- const plain = o => !!o && (Object.getPrototypeOf(o) === Object.prototype || Object.getPrototypeOf(o) === null);
3
- const finite = x => typeof x === "number" && Number.isFinite(x);
4
- const bounded = (x, max) => finite(x) && x >= 0 && x <= max;
5
- const reasons = [null, "host_budget", "clock_unavailable", "gates_unknown", "hidden", "reduced_motion", "save_data", "viewer_off"];
6
- const keys = ["key", "id", "device", "verdict", "reason", "remove", "forward", "quality", "pointerHz", "badWindows", "loadMs", "metrics"];
7
- const metricKeys = ["at", "hostFps", "hostLongTaskMsPerSecond", "attributedLongTaskMsPerSecond", "attribution", "fpsFloor", "windowMs"];
8
- const exact = (o, allowed) => plain(o) && Object.keys(o).sort().join(",") === [...allowed].sort().join(",");
9
- const quantile = (values, q) => { if (!values.length) return null; const a = [...values].sort((x, y) => x - y); return a[Math.max(0, Math.ceil(q * a.length) - 1)]; };
10
-
11
- /** A new collector belongs to one exact registry key/id/class mount. It never reads message content or child data. */
12
- export function createEffectProfileCollector(options = {}) {
13
- let key, id, device, clock;
14
- try { if (!exact(options, ["key", "id", "device", "clock"])) return { ok: false }; ({ key, id, device, clock } = options); } catch { return { ok: false }; }
15
- if (typeof key !== "string" || key.length < 1 || key.length > 256 || typeof id !== "string" || !/^[a-f0-9]{32}$/.test(id) || !["standard", "constrained"].includes(device) || typeof clock !== "function") return { ok: false };
16
- let dead = false, previous = null, lastSample = null, floor = null, last = null;
17
- const samples = [];
18
- const time = () => {
19
- let n; try { n = clock(); } catch { dead = true; return null; }
20
- if (!finite(n) || n < 0 || previous !== null && n < previous) { dead = true; return null; }
21
- previous = n; return n;
22
- };
23
- if (time() === null) return { ok: false };
24
- return { ok: true,
25
- add(raw) {
26
- if (dead) return false;
27
- try {
28
- // Reject unknown keys without reading their values or accessors.
29
- if (!exact(raw, keys) || raw.key !== key || raw.id !== id || raw.device !== device || !["ok", "degraded", "paused"].includes(raw.verdict) || !reasons.includes(raw.reason)
30
- || typeof raw.remove !== "boolean" || typeof raw.forward !== "boolean" || raw.remove !== (raw.verdict === "paused") || raw.remove && raw.forward
31
- || raw.quality !== (raw.verdict === "ok" ? "normal" : "low") || raw.pointerHz !== (raw.verdict === "ok" ? 60 : 30)
32
- || !Number.isInteger(raw.badWindows) || raw.badWindows < 0 || raw.badWindows > 3 || raw.loadMs !== null && !bounded(raw.loadMs, 600000)) { dead = true; return false; }
33
- const n = time(); if (n === null) return false;
34
- // Warmup is not an observed window and never turns missing measurements into zero cost.
35
- if (raw.metrics === null) return false;
36
- const m = raw.metrics;
37
- if (!exact(m, metricKeys) || !finite(m.at) || m.at < 0 || m.at > n || !bounded(m.hostFps, 1000) || !finite(m.fpsFloor) || m.fpsFloor <= 0 || m.fpsFloor > 1000 || m.windowMs !== 2000
38
- || m.hostLongTaskMsPerSecond !== null && !bounded(m.hostLongTaskMsPerSecond, 256000)
39
- || m.attributedLongTaskMsPerSecond !== null && (!bounded(m.attributedLongTaskMsPerSecond, 256000) || m.hostLongTaskMsPerSecond === null || m.attributedLongTaskMsPerSecond > m.hostLongTaskMsPerSecond)
40
- || m.attribution !== (m.attributedLongTaskMsPerSecond === null ? "unknown" : "observed") || floor !== null && m.fpsFloor !== floor) { dead = true; return false; }
41
- // Only poll() creates a window. rAF/gates/load/stop snapshots retain its immutable host timestamp.
42
- // A paused duplicate may describe the last verdict, but cannot renew the observation or add a sample.
43
- if (lastSample !== null && m.at === lastSample && last) last = { verdict: raw.verdict, reason: raw.reason, loadMs: raw.loadMs };
44
- if (n - m.at > 5000 || lastSample !== null && m.at - lastSample < 1000) return false;
45
- floor = m.fpsFloor; lastSample = m.at;
46
- samples.push({ fps: m.hostFps, task: m.hostLongTaskMsPerSecond, own: m.attributedLongTaskMsPerSecond });
47
- if (samples.length > 120) samples.shift();
48
- last = { verdict: raw.verdict, reason: raw.reason, loadMs: raw.loadMs };
49
- return true;
50
- } catch { dead = true; return false; }
51
- },
52
- report(options = {}) {
53
- let off;
54
- try { if (!plain(options) || Object.keys(options).some(k => k !== "off")) return null; off = options.off ?? false; } catch { dead = true; return null; }
55
- if (dead || typeof off !== "boolean" || lastSample === null || !last) return null;
56
- const n = time(); if (n === null || n - lastSample > 5000) return null;
57
- const host = samples.filter(s => s.task !== null).map(s => s.task), own = samples.filter(s => s.own !== null).map(s => s.own), fps = samples.map(s => s.fps);
58
- return { id, profile: { v: 1, device, verdict: off ? "off" : last.verdict, reason: last.reason, samples: samples.length,
59
- fps_p50: quantile(fps, 0.5), fps_p10: quantile(fps, 0.1), fps_floor: floor,
60
- long_task_p95: quantile(host, 0.95), long_task_samples: host.length,
61
- attributed_long_task_p95: quantile(own, 0.95), attributed_samples: own.length, attribution: own.length ? "observed" : "unknown", load_ms: last.loadMs } };
62
- },
63
- dispose() { dead = true; samples.length = 0; last = null; },
64
- };
65
- }