@songsid/agend 2.3.3-beta.4 → 2.3.3-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) 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/backend/codex.d.ts +1 -0
  13. package/dist/backend/codex.js +106 -15
  14. package/dist/backend/codex.js.map +1 -1
  15. package/dist/backend/types.d.ts +17 -0
  16. package/dist/backend/types.js.map +1 -1
  17. package/dist/bundled-skills.d.ts +4 -6
  18. package/dist/bundled-skills.js +10 -14
  19. package/dist/bundled-skills.js.map +1 -1
  20. package/dist/channel/mcp-server.js +5 -5
  21. package/dist/channel/mcp-server.js.map +1 -1
  22. package/dist/channel/mcp-tools.d.ts +1 -3
  23. package/dist/channel/mcp-tools.js +4 -58
  24. package/dist/channel/mcp-tools.js.map +1 -1
  25. package/dist/cli.js +3 -1
  26. package/dist/cli.js.map +1 -1
  27. package/dist/config-validator.js +6 -3
  28. package/dist/config-validator.js.map +1 -1
  29. package/dist/daemon.d.ts +11 -3
  30. package/dist/daemon.js +59 -107
  31. package/dist/daemon.js.map +1 -1
  32. package/dist/dashboard-live.d.ts +1 -1
  33. package/dist/dashboard-live.js +3 -3
  34. package/dist/dashboard-live.js.map +1 -1
  35. package/dist/dashboard-permissions.d.ts +1 -1
  36. package/dist/dashboard-permissions.js +1 -3
  37. package/dist/dashboard-permissions.js.map +1 -1
  38. package/dist/fleet-manager.d.ts +26 -44
  39. package/dist/fleet-manager.js +70 -226
  40. package/dist/fleet-manager.js.map +1 -1
  41. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +11 -1
  42. package/dist/general-knowledge/skills/session-management/SKILL.md +6 -0
  43. package/dist/general-knowledge/skills/web-appearance/SKILL.md +13 -204
  44. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +26 -63
  45. package/dist/instance-lifecycle.js +1 -1
  46. package/dist/instance-lifecycle.js.map +1 -1
  47. package/dist/locale.js +2 -0
  48. package/dist/locale.js.map +1 -1
  49. package/dist/outbound-handlers.js +19 -7
  50. package/dist/outbound-handlers.js.map +1 -1
  51. package/dist/outbound-schemas.d.ts +0 -62
  52. package/dist/outbound-schemas.js +2 -41
  53. package/dist/outbound-schemas.js.map +1 -1
  54. package/dist/public-web-gateway.js +0 -9
  55. package/dist/public-web-gateway.js.map +1 -1
  56. package/dist/public-web-link.d.ts +2 -0
  57. package/dist/public-web-link.js +5 -0
  58. package/dist/public-web-link.js.map +1 -1
  59. package/dist/search/search-docs.d.ts +1 -1
  60. package/dist/search/search-docs.js +2 -2
  61. package/dist/search/search-docs.js.map +1 -1
  62. package/dist/settings-api.d.ts +6 -0
  63. package/dist/settings-api.js +14 -2
  64. package/dist/settings-api.js.map +1 -1
  65. package/dist/settings-change.js +3 -1
  66. package/dist/settings-change.js.map +1 -1
  67. package/dist/tool-permissions.js +3 -10
  68. package/dist/tool-permissions.js.map +1 -1
  69. package/dist/topic-commands.d.ts +6 -2
  70. package/dist/topic-commands.js +2 -0
  71. package/dist/topic-commands.js.map +1 -1
  72. package/dist/types.d.ts +2 -1
  73. package/dist/ui/chat-ambient.js +4 -4
  74. package/dist/ui/chat-commands.js +3 -2
  75. package/dist/ui/chat-store.js +4 -1
  76. package/dist/ui/chat-strings.js +6 -42
  77. package/dist/ui/chat-thread.js +6 -44
  78. package/dist/ui/panel-chat.js +21 -50
  79. package/dist/ui/preview-panel.js +3 -15
  80. package/dist/ui/search-dialog.js +30 -14
  81. package/dist/ui/settings-appearance.js +1 -3
  82. package/dist/ui/settings-guests.js +13 -4
  83. package/dist/ui/settings-learn.js +1 -1
  84. package/dist/ui/settings-mods.js +5 -12
  85. package/dist/ui/settings-registry.js +0 -1
  86. package/dist/ui/settings-strings.js +6 -6
  87. package/dist/ui/shared/app-prefs.js +17 -17
  88. package/dist/ui/shared/app-shell.js +12 -8
  89. package/dist/ui/shared/app-store.js +6 -2
  90. package/dist/ui/shared/app.css +4 -36
  91. package/dist/ui/shared/app.js +5 -4
  92. package/dist/ui/shared/instance-nav.js +9 -9
  93. package/dist/ui/shared/instance-switch.js +8 -2
  94. package/dist/ui/shared/panel-view.js +22 -8
  95. package/dist/ui/shared/view-strings.js +6 -0
  96. package/dist/usage/usage-api.d.ts +3 -0
  97. package/dist/usage/usage-api.js +5 -1
  98. package/dist/usage/usage-api.js.map +1 -1
  99. package/dist/view-api.d.ts +2 -0
  100. package/dist/view-api.js +64 -0
  101. package/dist/view-api.js.map +1 -1
  102. package/dist/web-api.d.ts +9 -17
  103. package/dist/web-api.js +255 -371
  104. package/dist/web-api.js.map +1 -1
  105. package/dist/web-appearance-tools.d.ts +0 -2
  106. package/dist/web-appearance-tools.js +2 -5
  107. package/dist/web-appearance-tools.js.map +1 -1
  108. package/dist/web-appearance-view.d.ts +0 -6
  109. package/dist/web-appearance-view.js +0 -1
  110. package/dist/web-appearance-view.js.map +1 -1
  111. package/dist/web-appearance.d.ts +14 -7
  112. package/dist/web-appearance.js +5 -6
  113. package/dist/web-appearance.js.map +1 -1
  114. package/dist/web-asset-parts.d.ts +1 -17
  115. package/dist/web-asset-parts.js +1 -15
  116. package/dist/web-asset-parts.js.map +1 -1
  117. package/dist/web-auth.js +1 -7
  118. package/dist/web-auth.js.map +1 -1
  119. package/dist/web-chat-history.d.ts +3 -7
  120. package/dist/web-chat-history.js +10 -17
  121. package/dist/web-chat-history.js.map +1 -1
  122. package/dist/web-commands.d.ts +9 -1
  123. package/dist/web-commands.js +13 -0
  124. package/dist/web-commands.js.map +1 -1
  125. package/dist/web-experimental.d.ts +2 -11
  126. package/dist/web-experimental.js +8 -36
  127. package/dist/web-experimental.js.map +1 -1
  128. package/dist/web-guest-access.d.ts +40 -2
  129. package/dist/web-guest-access.js +50 -14
  130. package/dist/web-guest-access.js.map +1 -1
  131. package/dist/web-mod-bundle.d.ts +2 -45
  132. package/dist/web-mod-bundle.js +15 -63
  133. package/dist/web-mod-bundle.js.map +1 -1
  134. package/dist/web-mod-store.d.ts +3 -48
  135. package/dist/web-mod-store.js +30 -97
  136. package/dist/web-mod-store.js.map +1 -1
  137. package/dist/web-prefs.d.ts +13 -0
  138. package/dist/web-prefs.js +38 -0
  139. package/dist/web-prefs.js.map +1 -1
  140. package/dist/web-preview.d.ts +1 -11
  141. package/dist/web-preview.js +6 -20
  142. package/dist/web-preview.js.map +1 -1
  143. package/dist/web-session.d.ts +11 -3
  144. package/dist/web-session.js +22 -11
  145. package/dist/web-session.js.map +1 -1
  146. package/dist/web-settings-patch.d.ts +1 -0
  147. package/dist/web-settings-patch.js +6 -3
  148. package/dist/web-settings-patch.js.map +1 -1
  149. package/dist/web-settings-tools.d.ts +0 -13
  150. package/dist/web-settings-tools.js +12 -84
  151. package/dist/web-settings-tools.js.map +1 -1
  152. package/package.json +1 -1
  153. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +0 -376
  154. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +0 -672
  155. package/dist/ui/app-effects.js +0 -251
  156. package/dist/ui/chat-effect-posters.js +0 -42
  157. package/dist/ui/chat-effects.js +0 -167
  158. package/dist/ui/effect-trial-controller.js +0 -124
  159. package/dist/ui/effect-trial-offer.js +0 -2
  160. package/dist/ui/effect-trial-panel.js +0 -40
  161. package/dist/ui/effects-waker.js +0 -2
  162. package/dist/ui/settings-effects.js +0 -202
  163. package/dist/ui/settings-owner-effects.js +0 -82
  164. package/dist/ui/shared/effect-app-runtime.js +0 -299
  165. package/dist/ui/shared/effect-baseline.js +0 -64
  166. package/dist/ui/shared/effect-chat-runtime.js +0 -162
  167. package/dist/ui/shared/effect-cursor.js +0 -126
  168. package/dist/ui/shared/effect-display-metadata.js +0 -39
  169. package/dist/ui/shared/effect-frame.js +0 -146
  170. package/dist/ui/shared/effect-geometry.js +0 -137
  171. package/dist/ui/shared/effect-host-style.js +0 -10
  172. package/dist/ui/shared/effect-owner-regions.js +0 -74
  173. package/dist/ui/shared/effect-owner-source.js +0 -122
  174. package/dist/ui/shared/effect-policy.js +0 -151
  175. package/dist/ui/shared/effect-poster-reader.js +0 -98
  176. package/dist/ui/shared/effect-posters.js +0 -117
  177. package/dist/ui/shared/effect-profiler.js +0 -184
  178. package/dist/ui/shared/effect-profiles.js +0 -65
  179. package/dist/ui/shared/effect-registry.js +0 -545
  180. package/dist/ui/shared/effect-runtime-loader.js +0 -236
  181. package/dist/ui/shared/effect-safety.js +0 -153
  182. package/dist/ui/shared/effect-stock-snapshot.js +0 -43
  183. package/dist/ui/shared/effect-stock-trust.js +0 -217
  184. package/dist/ui/shared/effect-trial-shadow.js +0 -62
  185. package/dist/ui/shared/effect-trial-source.js +0 -103
  186. package/dist/ui/shared/effect-trial-stage.js +0 -170
  187. package/dist/ui/shared/effect-trial.css +0 -40
  188. package/dist/ui/shared/feature-flags.js +0 -127
  189. package/dist/ui/shared/owner-effect-prefs.js +0 -117
  190. package/dist/web-effect-bootstrap.d.ts +0 -12
  191. package/dist/web-effect-bootstrap.js +0 -49
  192. package/dist/web-effect-bootstrap.js.map +0 -1
  193. package/dist/web-effect-bundle.d.ts +0 -28
  194. package/dist/web-effect-bundle.js +0 -171
  195. package/dist/web-effect-bundle.js.map +0 -1
  196. package/dist/web-effect-canonical.d.ts +0 -8
  197. package/dist/web-effect-canonical.js +0 -27
  198. package/dist/web-effect-canonical.js.map +0 -1
  199. package/dist/web-effect-library.d.ts +0 -114
  200. package/dist/web-effect-library.js +0 -530
  201. package/dist/web-effect-library.js.map +0 -1
  202. package/dist/web-effect-playback.d.ts +0 -30
  203. package/dist/web-effect-playback.js +0 -71
  204. package/dist/web-effect-playback.js.map +0 -1
  205. package/dist/web-effect-poster.d.ts +0 -8
  206. package/dist/web-effect-poster.js +0 -52
  207. package/dist/web-effect-poster.js.map +0 -1
  208. package/dist/web-effect-profiles.d.ts +0 -118
  209. package/dist/web-effect-profiles.js +0 -181
  210. package/dist/web-effect-profiles.js.map +0 -1
  211. package/dist/web-effect-service.d.ts +0 -93
  212. package/dist/web-effect-service.js +0 -335
  213. package/dist/web-effect-service.js.map +0 -1
  214. package/dist/web-effect-tools.d.ts +0 -48
  215. package/dist/web-effect-tools.js +0 -129
  216. package/dist/web-effect-tools.js.map +0 -1
  217. package/dist/web-effect-trials.d.ts +0 -86
  218. package/dist/web-effect-trials.js +0 -204
  219. package/dist/web-effect-trials.js.map +0 -1
  220. package/dist/web-effect-upload.d.ts +0 -27
  221. package/dist/web-effect-upload.js +0 -185
  222. package/dist/web-effect-upload.js.map +0 -1
  223. package/dist/web-effect-worker.d.ts +0 -8
  224. package/dist/web-effect-worker.js +0 -170
  225. package/dist/web-effect-worker.js.map +0 -1
  226. package/dist/web-effect.d.ts +0 -103
  227. package/dist/web-effect.js +0 -153
  228. package/dist/web-effect.js.map +0 -1
  229. package/dist/web-experimental-http.d.ts +0 -2
  230. package/dist/web-experimental-http.js +0 -12
  231. package/dist/web-experimental-http.js.map +0 -1
  232. package/dist/web-mod-agent.d.ts +0 -50
  233. package/dist/web-mod-agent.js +0 -207
  234. 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
- }