@songsid/agend 2.2.0-beta.9 → 2.3.0-beta.1
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.
- package/README.md +40 -24
- package/README.zh-TW.md +40 -24
- package/dist/agent-cli.js +248 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +2 -0
- package/dist/agent-endpoint.js +28 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.d.ts +30 -0
- package/dist/agent-file-read.js +129 -0
- package/dist/agent-file-read.js.map +1 -0
- package/dist/agent-whats-new.js +20 -1
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/atomic-write.js +9 -1
- package/dist/atomic-write.js.map +1 -1
- package/dist/auth-api.d.ts +3 -1
- package/dist/auth-api.js +32 -1
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/antigravity.d.ts +33 -0
- package/dist/backend/antigravity.js +129 -21
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +3 -0
- package/dist/backend/claude-code.js +9 -0
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +33 -0
- package/dist/backend/codex-metadata.js +122 -18
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex.d.ts +3 -0
- package/dist/backend/codex.js +17 -1
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/effort-metadata.d.ts +37 -1
- package/dist/backend/effort-metadata.js +86 -15
- package/dist/backend/effort-metadata.js.map +1 -1
- package/dist/backend/grok.d.ts +3 -0
- package/dist/backend/grok.js +9 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +3 -1
- package/dist/backend/kiro.js +7 -3
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/launch-effort.d.ts +61 -0
- package/dist/backend/launch-effort.js +170 -0
- package/dist/backend/launch-effort.js.map +1 -0
- package/dist/backend/muse.js +10 -2
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +24 -0
- package/dist/backend/types.js +12 -1
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-command.d.ts +91 -0
- package/dist/backend-command.js +122 -0
- package/dist/backend-command.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +14 -0
- package/dist/channel/adapters/discord.js +66 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +26 -1
- package/dist/channel/adapters/telegram.js +98 -7
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +36 -0
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/tool-router.d.ts +2 -0
- package/dist/channel/tool-router.js +1 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/channel/types.d.ts +31 -0
- package/dist/cli.js +124 -24
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +2 -2
- package/dist/command-table.js +5 -2
- package/dist/command-table.js.map +1 -1
- package/dist/compact-watch.d.ts +86 -0
- package/dist/compact-watch.js +288 -0
- package/dist/compact-watch.js.map +1 -0
- package/dist/config-validator.js +55 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +9 -0
- package/dist/daemon.js +394 -29
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +8 -1
- package/dist/delivery-outbox.js +6 -2
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/doctor.js +7 -0
- package/dist/doctor.js.map +1 -1
- package/dist/fleet-context.d.ts +12 -0
- package/dist/fleet-manager.d.ts +247 -9
- package/dist/fleet-manager.js +1227 -142
- package/dist/fleet-manager.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +4 -3
- package/dist/forged-envelope-scan.js +4 -3
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +4 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +258 -0
- package/dist/install-lock.d.ts +18 -1
- package/dist/install-lock.js +30 -3
- package/dist/install-lock.js.map +1 -1
- package/dist/instance-avatar.d.ts +5 -4
- package/dist/instance-avatar.js +15 -8
- package/dist/instance-avatar.js.map +1 -1
- package/dist/instance-config-impact.js +3 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.js +9 -4
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.js +2 -2
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-compact-pane.d.ts +38 -0
- package/dist/kiro-compact-pane.js +57 -0
- package/dist/kiro-compact-pane.js.map +1 -0
- package/dist/launchd-handoff.d.ts +43 -0
- package/dist/launchd-handoff.js +56 -0
- package/dist/launchd-handoff.js.map +1 -0
- package/dist/locale.js +202 -30
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +10 -2
- package/dist/log-service.js.map +1 -1
- package/dist/login-shell.d.ts +21 -0
- package/dist/login-shell.js +98 -0
- package/dist/login-shell.js.map +1 -0
- package/dist/needs-you-hub.d.ts +4 -0
- package/dist/needs-you-hub.js +31 -6
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +1 -13
- package/dist/needs-you.js +3 -37
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +32 -0
- package/dist/outbound-handlers.js +150 -45
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +76 -0
- package/dist/outbound-schemas.js +65 -4
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/provider-probe.d.ts +29 -0
- package/dist/provider-probe.js +198 -2
- package/dist/provider-probe.js.map +1 -1
- package/dist/public-web-gateway.d.ts +2 -0
- package/dist/public-web-gateway.js +25 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart-api.d.ts +1 -1
- package/dist/quickstart-api.js +8 -6
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +12 -0
- package/dist/quickstart.js +36 -6
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-buttons-controller.d.ts +86 -5
- package/dist/reply-buttons-controller.js +271 -7
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/reply-buttons.d.ts +48 -3
- package/dist/reply-buttons.js +105 -10
- package/dist/reply-buttons.js.map +1 -1
- package/dist/reply-polls.d.ts +85 -0
- package/dist/reply-polls.js +154 -0
- package/dist/reply-polls.js.map +1 -0
- package/dist/repo-worktree-guard.d.ts +36 -0
- package/dist/repo-worktree-guard.js +143 -0
- package/dist/repo-worktree-guard.js.map +1 -0
- package/dist/restart-guard.d.ts +6 -3
- package/dist/restart-guard.js +6 -3
- package/dist/restart-guard.js.map +1 -1
- package/dist/restart-progress.d.ts +0 -2
- package/dist/restart-progress.js +0 -2
- package/dist/restart-progress.js.map +1 -1
- package/dist/scheduler/scheduler.d.ts +58 -1
- package/dist/scheduler/scheduler.js +176 -10
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/sd-notify.d.ts +22 -1
- package/dist/sd-notify.js +63 -10
- package/dist/sd-notify.js.map +1 -1
- package/dist/service-activation.d.ts +15 -7
- package/dist/service-activation.js +42 -26
- package/dist/service-activation.js.map +1 -1
- package/dist/service-installer.d.ts +24 -0
- package/dist/service-installer.js +49 -1
- package/dist/service-installer.js.map +1 -1
- package/dist/service-plan.d.ts +11 -0
- package/dist/service-plan.js +23 -0
- package/dist/service-plan.js.map +1 -1
- package/dist/settings-api.js +74 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +8 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +16 -2
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.js +5 -0
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/systemd-peer-bus.d.ts +95 -0
- package/dist/systemd-peer-bus.js +430 -0
- package/dist/systemd-peer-bus.js.map +1 -0
- package/dist/systemd-runtime.d.ts +27 -1
- package/dist/systemd-runtime.js +69 -7
- package/dist/systemd-runtime.js.map +1 -1
- package/dist/tool-permissions.js +53 -3
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +72 -2
- package/dist/topic-commands.js +156 -38
- package/dist/topic-commands.js.map +1 -1
- package/dist/topic-link.d.ts +128 -0
- package/dist/topic-link.js +269 -0
- package/dist/topic-link.js.map +1 -0
- package/dist/transcript-jsonl.d.ts +7 -2
- package/dist/transcript-jsonl.js +13 -7
- package/dist/transcript-jsonl.js.map +1 -1
- package/dist/transcript-sources.js +6 -1
- package/dist/transcript-sources.js.map +1 -1
- package/dist/types.d.ts +21 -0
- package/dist/ui/app-effects.js +187 -0
- package/dist/ui/chat-commands.js +1 -0
- package/dist/ui/chat-effect-posters.js +42 -0
- package/dist/ui/chat-effects.js +72 -0
- package/dist/ui/chat-live-replies.js +58 -0
- package/dist/ui/chat-render.js +59 -14
- package/dist/ui/chat-store.js +78 -8
- package/dist/ui/chat-strings.js +43 -16
- package/dist/ui/chat-thread.js +175 -31
- package/dist/ui/chat-tour.js +18 -15
- package/dist/ui/effect-trial-controller.js +119 -0
- package/dist/ui/effect-trial-offer.js +31 -0
- package/dist/ui/effect-trial-panel.js +37 -0
- package/dist/ui/image-lightbox.js +1 -1
- package/dist/ui/panel-chat.js +101 -27
- package/dist/ui/panel-details.js +18 -5
- package/dist/ui/panel-fleet.js +18 -5
- package/dist/ui/panel-log.js +10 -10
- package/dist/ui/panel-needs.js +13 -10
- package/dist/ui/panel-settings.js +66 -12
- package/dist/ui/preview-panel.js +25 -9
- package/dist/ui/settings-appearance.js +325 -0
- package/dist/ui/settings-dialogs.js +11 -6
- package/dist/ui/settings-effects.js +201 -0
- package/dist/ui/settings-model.js +3 -1
- package/dist/ui/settings-mods.js +257 -0
- package/dist/ui/settings-owner-effects.js +80 -0
- package/dist/ui/settings-strings.js +269 -10
- package/dist/ui/settings-token.js +7 -0
- package/dist/ui/settings-wizard.js +5 -3
- package/dist/ui/shared/agend-auth.js +27 -3
- package/dist/ui/shared/agent-widget.js +248 -0
- package/dist/ui/shared/app-i18n.js +3 -1
- package/dist/ui/shared/app-prefs.js +30 -10
- package/dist/ui/shared/app-route.js +23 -1
- package/dist/ui/shared/app-session.js +1 -1
- package/dist/ui/shared/app-shell.js +29 -16
- package/dist/ui/shared/app-store.js +2 -0
- package/dist/ui/shared/app-stream.js +15 -7
- package/dist/ui/shared/app-themes.js +188 -0
- package/dist/ui/shared/app.css +266 -11
- package/dist/ui/shared/app.js +6 -0
- package/dist/ui/shared/card-strings.js +28 -0
- package/dist/ui/shared/effect-app-runtime.js +248 -0
- package/dist/ui/shared/effect-baseline.js +64 -0
- package/dist/ui/shared/effect-chat-runtime.js +154 -0
- package/dist/ui/shared/effect-cursor.js +125 -0
- package/dist/ui/shared/effect-frame.js +127 -0
- package/dist/ui/shared/effect-geometry.js +122 -0
- package/dist/ui/shared/effect-host-style.js +10 -0
- package/dist/ui/shared/effect-owner-regions.js +74 -0
- package/dist/ui/shared/effect-owner-source.js +115 -0
- package/dist/ui/shared/effect-policy.js +137 -0
- package/dist/ui/shared/effect-poster-reader.js +98 -0
- package/dist/ui/shared/effect-posters.js +117 -0
- package/dist/ui/shared/effect-profiler.js +162 -0
- package/dist/ui/shared/effect-profiles.js +65 -0
- package/dist/ui/shared/effect-registry.js +496 -0
- package/dist/ui/shared/effect-runtime-loader.js +234 -0
- package/dist/ui/shared/effect-safety.js +153 -0
- package/dist/ui/shared/effect-stock-snapshot.js +34 -0
- package/dist/ui/shared/effect-stock-trust.js +165 -0
- package/dist/ui/shared/effect-trial-source.js +103 -0
- package/dist/ui/shared/effect-trial-stage.js +147 -0
- package/dist/ui/shared/header-tools.js +35 -15
- package/dist/ui/shared/identity-card.js +202 -0
- package/dist/ui/shared/identity-color.js +261 -0
- package/dist/ui/shared/instance-nav.js +22 -14
- package/dist/ui/shared/instance-switch.js +5 -2
- package/dist/ui/shared/owner-css.js +221 -0
- package/dist/ui/shared/owner-effect-prefs.js +117 -0
- package/dist/ui/shared/panel-view.js +96 -12
- package/dist/ui/shared/signin.js +17 -9
- package/dist/ui/shared/ui-dialog.js +1 -1
- package/dist/ui/shared/ui-icons.js +3 -0
- package/dist/ui/shared/ui-menu.js +1 -1
- package/dist/ui/shared/ui-toast.js +1 -1
- package/dist/ui/shared/view-strings.js +40 -2
- package/dist/ui/signin.html +9 -3
- package/dist/update-check.d.ts +31 -0
- package/dist/update-check.js +47 -0
- package/dist/update-check.js.map +1 -1
- package/dist/update-launch.d.ts +48 -1
- package/dist/update-launch.js +159 -5
- package/dist/update-launch.js.map +1 -1
- package/dist/usage/providers.d.ts +28 -8
- package/dist/usage/providers.js +96 -41
- package/dist/usage/providers.js.map +1 -1
- package/dist/view-api.d.ts +29 -0
- package/dist/view-api.js +214 -17
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +86 -2
- package/dist/web-api.js +1160 -92
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-limits.d.ts +82 -0
- package/dist/web-appearance-limits.js +83 -0
- package/dist/web-appearance-limits.js.map +1 -0
- package/dist/web-appearance-policy.d.ts +66 -0
- package/dist/web-appearance-policy.js +94 -0
- package/dist/web-appearance-policy.js.map +1 -0
- package/dist/web-appearance-tools.d.ts +50 -0
- package/dist/web-appearance-tools.js +105 -0
- package/dist/web-appearance-tools.js.map +1 -0
- package/dist/web-appearance-view.d.ts +99 -0
- package/dist/web-appearance-view.js +163 -0
- package/dist/web-appearance-view.js.map +1 -0
- package/dist/web-appearance.d.ts +79 -0
- package/dist/web-appearance.js +298 -0
- package/dist/web-appearance.js.map +1 -0
- package/dist/web-asset-parts.d.ts +98 -0
- package/dist/web-asset-parts.js +133 -0
- package/dist/web-asset-parts.js.map +1 -0
- package/dist/web-auth.js +17 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-card.d.ts +96 -0
- package/dist/web-card.js +232 -0
- package/dist/web-card.js.map +1 -0
- package/dist/web-chat-history.d.ts +39 -1
- package/dist/web-chat-history.js +69 -9
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +39 -3
- package/dist/web-commands.js +22 -5
- package/dist/web-commands.js.map +1 -1
- package/dist/web-effect-bundle.d.ts +28 -0
- package/dist/web-effect-bundle.js +126 -0
- package/dist/web-effect-bundle.js.map +1 -0
- package/dist/web-effect-canonical.d.ts +8 -0
- package/dist/web-effect-canonical.js +27 -0
- package/dist/web-effect-canonical.js.map +1 -0
- package/dist/web-effect-library.d.ts +114 -0
- package/dist/web-effect-library.js +530 -0
- package/dist/web-effect-library.js.map +1 -0
- package/dist/web-effect-poster.d.ts +8 -0
- package/dist/web-effect-poster.js +52 -0
- package/dist/web-effect-poster.js.map +1 -0
- package/dist/web-effect-profiles.d.ts +118 -0
- package/dist/web-effect-profiles.js +180 -0
- package/dist/web-effect-profiles.js.map +1 -0
- package/dist/web-effect-service.d.ts +86 -0
- package/dist/web-effect-service.js +312 -0
- package/dist/web-effect-service.js.map +1 -0
- package/dist/web-effect-tools.d.ts +47 -0
- package/dist/web-effect-tools.js +126 -0
- package/dist/web-effect-tools.js.map +1 -0
- package/dist/web-effect-trials.d.ts +86 -0
- package/dist/web-effect-trials.js +204 -0
- package/dist/web-effect-trials.js.map +1 -0
- package/dist/web-effect-upload.d.ts +29 -0
- package/dist/web-effect-upload.js +190 -0
- package/dist/web-effect-upload.js.map +1 -0
- package/dist/web-effect-worker.d.ts +8 -0
- package/dist/web-effect-worker.js +170 -0
- package/dist/web-effect-worker.js.map +1 -0
- package/dist/web-effect.d.ts +89 -0
- package/dist/web-effect.js +132 -0
- package/dist/web-effect.js.map +1 -0
- package/dist/web-identity-color.d.ts +87 -0
- package/dist/web-identity-color.js +209 -0
- package/dist/web-identity-color.js.map +1 -0
- package/dist/web-identity-palette.d.ts +113 -0
- package/dist/web-identity-palette.js +84 -0
- package/dist/web-identity-palette.js.map +1 -0
- package/dist/web-image-meta.d.ts +25 -0
- package/dist/web-image-meta.js +200 -0
- package/dist/web-image-meta.js.map +1 -0
- package/dist/web-login.d.ts +14 -0
- package/dist/web-login.js +4 -2
- package/dist/web-login.js.map +1 -1
- package/dist/web-mod-agent.d.ts +50 -0
- package/dist/web-mod-agent.js +203 -0
- package/dist/web-mod-agent.js.map +1 -0
- package/dist/web-mod-bundle.d.ts +144 -0
- package/dist/web-mod-bundle.js +464 -0
- package/dist/web-mod-bundle.js.map +1 -0
- package/dist/web-mod-export.d.ts +59 -0
- package/dist/web-mod-export.js +79 -0
- package/dist/web-mod-export.js.map +1 -0
- package/dist/web-mod-store.d.ts +283 -0
- package/dist/web-mod-store.js +624 -0
- package/dist/web-mod-store.js.map +1 -0
- package/dist/web-org.d.ts +3 -3
- package/dist/web-org.js +11 -17
- package/dist/web-org.js.map +1 -1
- package/dist/web-owner-css-store.d.ts +180 -0
- package/dist/web-owner-css-store.js +384 -0
- package/dist/web-owner-css-store.js.map +1 -0
- package/dist/web-owner-css.d.ts +58 -0
- package/dist/web-owner-css.js +552 -0
- package/dist/web-owner-css.js.map +1 -0
- package/dist/web-prefs.d.ts +66 -0
- package/dist/web-prefs.js +243 -35
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +9 -1
- package/dist/web-preview.js +24 -7
- package/dist/web-preview.js.map +1 -1
- package/dist/web-profile.d.ts +32 -0
- package/dist/web-profile.js +132 -0
- package/dist/web-profile.js.map +1 -0
- package/dist/web-session.d.ts +14 -0
- package/dist/web-session.js +10 -0
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +18 -0
- package/dist/web-settings-patch.js +51 -0
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +1 -1
- package/dist/web-shell-routes.js +1 -1
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-theme-store.d.ts +218 -0
- package/dist/web-theme-store.js +516 -0
- package/dist/web-theme-store.js.map +1 -0
- package/dist/web-theme.d.ts +121 -0
- package/dist/web-theme.js +407 -0
- package/dist/web-theme.js.map +1 -0
- package/dist/web-upload.d.ts +119 -4
- package/dist/web-upload.js +252 -39
- package/dist/web-upload.js.map +1 -1
- package/dist/web-widget.d.ts +72 -0
- package/dist/web-widget.js +245 -0
- package/dist/web-widget.js.map +1 -0
- package/launcher/install-admission.cjs +61 -6
- package/package.json +3 -3
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
/** #1629 B2: one host-owned Canvas Worker pool. Product adapters are deliberately separate. */
|
|
2
|
+
import { allocateEffectFrames, effectEvent } from "./effect-policy.js";
|
|
3
|
+
import { captureEffectBaseline } from "./effect-baseline.js";
|
|
4
|
+
import { createEffectFrame } from "./effect-frame.js";
|
|
5
|
+
import { createEffectGeometry, hostEffectRect } from "./effect-geometry.js";
|
|
6
|
+
import { effectStockSnapshot, effectStockAllows } from "./effect-stock-snapshot.js";
|
|
7
|
+
import { effectTrialStage, effectTrialStageIdentity, watchEffectTrialStage } from "./effect-trial-stage.js";
|
|
8
|
+
import { EffectBudget } from "./effect-profiler.js";
|
|
9
|
+
|
|
10
|
+
const registries = new WeakMap();
|
|
11
|
+
const plain = o => !!o && (Object.getPrototypeOf(o) === Object.prototype || Object.getPrototypeOf(o) === null);
|
|
12
|
+
const finite = v => typeof v === "number" && Number.isFinite(v);
|
|
13
|
+
const FLAGS = ["safe", "publicLink", "reducedMotion", "saveData", "hidden", "enabled", "show", "previewReady", "optIn", "constrained", "modal"];
|
|
14
|
+
const TYPES = ["state", "reply", "theme"];
|
|
15
|
+
function unsafeSnapshotDescriptor(d) {
|
|
16
|
+
if (!plain(d) || !plain(d.params ?? {})) return null;
|
|
17
|
+
const params = Object.create(null), keys = Object.keys(d.params ?? {}).sort();
|
|
18
|
+
if (keys.length > 16) return null;
|
|
19
|
+
for (const k of keys) {
|
|
20
|
+
const v = d.params[k];
|
|
21
|
+
if (!/^[a-z][a-z0-9_]{0,31}$/.test(k) || !(typeof v === "boolean" || finite(v) || typeof v === "string" && v.length <= 128)) return null;
|
|
22
|
+
params[k] = v;
|
|
23
|
+
}
|
|
24
|
+
const trialIdentity = d.trialStage == null ? null : effectTrialStageIdentity(d.trialStage);
|
|
25
|
+
if (d.trialStage != null && (!trialIdentity || d.region !== "chat" || trialIdentity.key !== d.key || trialIdentity.id !== d.id || trialIdentity.instance !== d.instance || trialIdentity.generation !== d.generation)) return null;
|
|
26
|
+
const out = { trialStage: d.trialStage ?? null, generation: trialIdentity?.generation ?? null, key: d.key, id: d.id, region: d.region, layer: d.layer, by: !trialIdentity && d.by === "human" ? "human" : "agent", order: d.order,
|
|
27
|
+
paused: d.paused, visible: d.visible, instance: d.region === "chat" ? d.instance : null, params, element: d.element };
|
|
28
|
+
const identity = [out.id, out.region, out.layer, out.by, out.instance, params];
|
|
29
|
+
if (trialIdentity) identity.push([trialIdentity.serial, trialIdentity.generation]);
|
|
30
|
+
out.identity = JSON.stringify(identity);
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function snapshotDescriptor(d) { try { return unsafeSnapshotDescriptor(d); } catch { return null; } }
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* `load` is an authenticated, bounded host loader, never a Worker callback. It returns {id,code,params,assets,wants}.
|
|
38
|
+
* Safety is mandatory and synchronous: allowed(id,device), begin({key,id,device}), finish(token,reason), pause(record), resume(id,device). Pause persists a soft latch and history; human resume never clears sticky off.
|
|
39
|
+
* stockSnapshot({frameRoot}) supplies current closed stock paint evidence synchronously; it must not reenter a mutation API.
|
|
40
|
+
* Unknown receipts, roots, trust coverage or gates mount nothing. No storage, network, content or product imports here.
|
|
41
|
+
*/
|
|
42
|
+
export function createEffectRegistry({ window: host, origin, boot, load, safety, stockSnapshot, onChange = () => {}, onProfile = () => {}, onMount = () => {}, onRetire = () => {}, clock = () => host.performance.now() } = {}) {
|
|
43
|
+
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" }; }
|
|
44
|
+
let dead = false, blocked = null, revision = 0, last = null, lastView = null, frameSerial = 0, context = null, descriptors = [], calibration = null, baseline = null, baselineDevice = null, serial = 0, raf = null, timer = null;
|
|
45
|
+
const slots = new Map(), loads = new Set(), paused = new Map(), offs = [], observed = new Set(), failures = new Map(), results = new Map();
|
|
46
|
+
let readingStock = false;
|
|
47
|
+
let root, geometry, observer, resize, longTasks = null, longTasksSupported = false;
|
|
48
|
+
const time = () => {
|
|
49
|
+
let n; try { n = clock(); } catch { return null; }
|
|
50
|
+
if (!finite(n) || n < 0 || last !== null && n < last) return null;
|
|
51
|
+
last = n; return n;
|
|
52
|
+
};
|
|
53
|
+
const nativeClock = () => { const n = time(); if (n === null) throw Error("clock unavailable"); return n; };
|
|
54
|
+
const device = () => context?.constrained === true ? "constrained" : "standard";
|
|
55
|
+
const dpr = device => Math.min(device === "constrained" ? 1.5 : 3, Math.max(0.5, host.devicePixelRatio || 1));
|
|
56
|
+
// The provider is synchronous and observational. Reentrant mutation revokes this pool, rather than
|
|
57
|
+
// allowing an old admission to act on newer descriptors or scheduling unbounded callback retries.
|
|
58
|
+
const readingStages = new Set();
|
|
59
|
+
// A local receipt may synchronously invalidate and notify its owner. Fence its result by revision;
|
|
60
|
+
// recursion on the same receipt is unknown, while an independently issued replacement may proceed.
|
|
61
|
+
const localStage = (d, proof) => {
|
|
62
|
+
if (!d?.trialStage || dead || blocked || readingStages.has(d.trialStage)) return null;
|
|
63
|
+
const before = revision; let stage = null; readingStages.add(d.trialStage);
|
|
64
|
+
try { stage = effectTrialStage(d.trialStage, d, proof); } catch { /* unknown is never permission */ }
|
|
65
|
+
finally { readingStages.delete(d.trialStage); }
|
|
66
|
+
return !dead && !blocked && revision === before && stage?.root === d.element ? stage : null;
|
|
67
|
+
};
|
|
68
|
+
const permits = (d, proof) => d.trialStage ? !!localStage(d, proof) : effectStockAllows(proof, d);
|
|
69
|
+
const coverage = (d = null) => {
|
|
70
|
+
if (dead || blocked || readingStock) return null;
|
|
71
|
+
const before = revision; let proof = null; readingStock = true;
|
|
72
|
+
try { proof = effectStockSnapshot(stockSnapshot(Object.freeze({ frameRoot: root }))); }
|
|
73
|
+
catch { /* unknown is never permission */ }
|
|
74
|
+
finally { readingStock = false; }
|
|
75
|
+
if (dead || blocked || before !== revision) return null;
|
|
76
|
+
return d === null || permits(d, proof) ? proof : null;
|
|
77
|
+
};
|
|
78
|
+
const position = (d, proof) => d.trialStage ? localStage(d, proof)?.rect ?? null : hostEffectRect(d.element);
|
|
79
|
+
const syncGeometry = (s, proof) => {
|
|
80
|
+
const before = revision, rect = position(s.d, proof);
|
|
81
|
+
if (!rect || !current(s) || before !== revision) return null;
|
|
82
|
+
const ok = s.d.trialStage ? s.geometry.sync(proof) : s.geometry.sync(rect, proof);
|
|
83
|
+
return ok && current(s) && before === revision ? rect : null;
|
|
84
|
+
};
|
|
85
|
+
const hideGeometry = () => { geometry?.hide(); for (const s of slots.values()) if (s.d.trialStage) s.geometry?.hide(); };
|
|
86
|
+
function reentrantStock() {
|
|
87
|
+
if (!readingStock) return false;
|
|
88
|
+
if (blocked) return true;
|
|
89
|
+
revision++; blocked = "stock_reentrant"; hideGeometry(); stopAll(blocked); tell(); return true;
|
|
90
|
+
}
|
|
91
|
+
const current = s => !dead && !blocked && slots.get(s.d.key) === s && s.live;
|
|
92
|
+
const tell = () => { if (dead) return; const state = view(), stamp = JSON.stringify(state); if (stamp === lastView) return; lastView = stamp; try { onChange(state); } catch { /* a display callback cannot admit code */ } };
|
|
93
|
+
const receipt = (fn, ...args) => { try { return Reflect.apply(fn, safety, args); } catch { return null; } };
|
|
94
|
+
const clearMarker = (s, why) => {
|
|
95
|
+
if (!s.token) return true;
|
|
96
|
+
const token = s.token; s.token = null;
|
|
97
|
+
if (receipt(safety.finish, token, why) === true) return true;
|
|
98
|
+
blocked = "safety_unknown"; return false;
|
|
99
|
+
};
|
|
100
|
+
function retire(s, why, count = false) {
|
|
101
|
+
if (!s.live) return;
|
|
102
|
+
s.live = false;
|
|
103
|
+
if (slots.get(s.d.key) === s) slots.delete(s.d.key);
|
|
104
|
+
if (s.request) { s.request.controller.abort(); if (s.request.timer !== null) host.clearTimeout(s.request.timer); }
|
|
105
|
+
if (!["disposed", "superseded", "hidden", "human_resume", "calibrating", "geometry_changed"].includes(why)) failures.set(s.d.key, { identity: signature(s.d), reason: why });
|
|
106
|
+
s.stageOff?.(); s.stageOff = null;
|
|
107
|
+
s.frame?.remove(why); s.geometry?.remove();
|
|
108
|
+
if (s.loadOff) s.loadOff();
|
|
109
|
+
if (count) {
|
|
110
|
+
paused.set(s.d.key, signature(s.d));
|
|
111
|
+
if (receipt(safety.pause, { id: s.d.id, device: s.device, reason: why, metrics: s.budget?.snapshot().metrics ?? null }) !== true) blocked = "safety_unknown";
|
|
112
|
+
}
|
|
113
|
+
clearMarker(s, why);
|
|
114
|
+
if (s.owner) { try { onRetire(s.owner, why); } catch { /* an observation cannot prevent physical cleanup */ } }
|
|
115
|
+
if (blocked) for (const other of [...slots.values()]) retire(other, blocked);
|
|
116
|
+
}
|
|
117
|
+
function stopAll(why) {
|
|
118
|
+
const proposed = revision, wasDead = dead;
|
|
119
|
+
for (const s of [...slots.values()]) {
|
|
120
|
+
retire(s, why);
|
|
121
|
+
if (revision !== proposed || dead !== wasDead) return false;
|
|
122
|
+
}
|
|
123
|
+
if (calibration) { calibration.cancel(); calibration = null; }
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
function gatesKnown() { return context && FLAGS.every(k => typeof context[k] === "boolean") && (context.openInstance === null || typeof context.openInstance === "string" && context.openInstance.length >= 1 && context.openInstance.length <= 128); }
|
|
127
|
+
function eligible() { return gatesKnown() && !context.safe && !context.publicLink && !context.reducedMotion && !context.saveData && context.enabled && context.show && context.previewReady && context.optIn; }
|
|
128
|
+
const globalAllowed = () => eligible() && host.document.visibilityState === "visible";
|
|
129
|
+
const signature = d => d.identity;
|
|
130
|
+
function view() {
|
|
131
|
+
return descriptors.map(d => {
|
|
132
|
+
const r = results.get(d.key) ?? { verdict: "off", reason: blocked ?? "unknown", queuePos: null }, s = slots.get(d.key);
|
|
133
|
+
return { key: d.key, id: d.id, ...r, phase: s?.frame ? s.ready ? "running" : "starting" : s ? "loading" : null,
|
|
134
|
+
quality: s?.budget?.snapshot().quality ?? null, reason: blocked ?? ((paused.get(d.key) === signature(d)) ? "paused" : failures.get(d.key)?.identity === signature(d) ? failures.get(d.key).reason : s && context?.hidden ? "hidden" : r.reason) };
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function schedule() {
|
|
138
|
+
if (dead || blocked || !slots.size) return;
|
|
139
|
+
if (raf === null && host.document.visibilityState === "visible" && context?.hidden === false) raf = host.requestAnimationFrame(tick);
|
|
140
|
+
if (timer === null) {
|
|
141
|
+
const waits = [...slots.values()].filter(s => s.hiddenSince !== null).map(s => Math.max(1, 10000 - (last - s.hiddenSince)));
|
|
142
|
+
timer = host.setTimeout(heartbeat, Math.min(1000, ...waits));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const invalidate = () => {
|
|
146
|
+
if (dead || reentrantStock()) return;
|
|
147
|
+
hideGeometry(); for (const s of slots.values()) s.pointer = null;
|
|
148
|
+
if (time() === null) { blocked = "clock_unavailable"; stopAll(blocked); tell(); return; }
|
|
149
|
+
reconcile();
|
|
150
|
+
};
|
|
151
|
+
function observe() {
|
|
152
|
+
const nodes = host.document.querySelectorAll("[data-trust]");
|
|
153
|
+
if (nodes.length > 128) throw Error("trust coverage unavailable");
|
|
154
|
+
const wanted = new Set([host.document.documentElement, ...nodes]);
|
|
155
|
+
for (const d of descriptors) if (d.element?.ownerDocument === host.document && d.element.isConnected === true) wanted.add(d.element);
|
|
156
|
+
for (const n of observed) if (!wanted.has(n)) { resize.unobserve(n); observed.delete(n); }
|
|
157
|
+
for (const n of wanted) if (!observed.has(n)) { resize.observe(n); observed.add(n); }
|
|
158
|
+
|
|
159
|
+
}
|
|
160
|
+
function reconcile() {
|
|
161
|
+
if (dead || reentrantStock()) return;
|
|
162
|
+
const proposal = revision;
|
|
163
|
+
if (time() === null) blocked = "clock_unavailable";
|
|
164
|
+
const hidden = context?.hidden === true || host.document.visibilityState !== "visible";
|
|
165
|
+
const stock = eligible() ? coverage() : null;
|
|
166
|
+
if (blocked || !eligible() || !stock) {
|
|
167
|
+
if (!stopAll(blocked ?? "gates_unknown")) return;
|
|
168
|
+
results.clear(); tell(); return;
|
|
169
|
+
}
|
|
170
|
+
// Hidden frames already owned may survive for <=10 s, but no new frame or load is admitted while hidden.
|
|
171
|
+
const ctx = { ...context, hidden: false };
|
|
172
|
+
const ds = [];
|
|
173
|
+
for (const d of descriptors) {
|
|
174
|
+
if (dead || proposal !== revision) return;
|
|
175
|
+
const allowed = permits(d, stock);
|
|
176
|
+
if (dead || proposal !== revision) return;
|
|
177
|
+
ds.push({ ...d, paused: !allowed || d.paused === true || paused.get(d.key) === signature(d) || failures.get(d.key)?.identity === signature(d) });
|
|
178
|
+
}
|
|
179
|
+
const allocation = allocateEffectFrames(ds, ctx); results.clear();
|
|
180
|
+
for (const r of allocation) {
|
|
181
|
+
const d = descriptors.find(d => d.key === r.key);
|
|
182
|
+
if (r.reason === "paused" && d && d.paused !== true && paused.get(d.key) !== signature(d) && failures.get(d.key)?.identity !== signature(d)) {
|
|
183
|
+
const allowed = permits(d, stock);
|
|
184
|
+
if (dead || proposal !== revision) return;
|
|
185
|
+
if (!allowed) r.reason = d.trialStage ? "trial_ended" : stock.front ? "owner_css" : "stock_overlay";
|
|
186
|
+
}
|
|
187
|
+
results.set(r.key, r);
|
|
188
|
+
}
|
|
189
|
+
if (dead || proposal !== revision) return;
|
|
190
|
+
const chosen = new Set(allocation.filter(r => r.verdict === "active").map(r => r.key));
|
|
191
|
+
for (const s of [...slots.values()]) {
|
|
192
|
+
const d = descriptors.find(x => x.key === s.d.key);
|
|
193
|
+
if (!chosen.has(s.d.key) || !d || signature(d) !== signature(s.d) || d.element !== s.d.element || s.device !== device()) retire(s, "superseded");
|
|
194
|
+
if (dead || proposal !== revision) return;
|
|
195
|
+
}
|
|
196
|
+
if (chosen.size === 0) { if (calibration) { calibration.cancel(); calibration = null; } baseline = null; baselineDevice = null; tell(); return; }
|
|
197
|
+
if (hidden) {
|
|
198
|
+
hideGeometry();
|
|
199
|
+
if (calibration) { calibration.cancel(); calibration = null; }
|
|
200
|
+
for (const s of [...slots.values()]) {
|
|
201
|
+
if (!s.frame) retire(s, "hidden");
|
|
202
|
+
else { if (s.hiddenSince === null) { s.hiddenSince = last; s.healthySince = null; } if (s.budget.gates({ hidden: true, reducedMotion: false, saveData: false, show: true }).remove) retire(s, "hidden"); }
|
|
203
|
+
if (dead || proposal !== revision) return;
|
|
204
|
+
}
|
|
205
|
+
schedule(); tell(); return;
|
|
206
|
+
}
|
|
207
|
+
if (!globalAllowed()) { stopAll("gates_unknown"); tell(); return; }
|
|
208
|
+
for (const s of [...slots.values()]) {
|
|
209
|
+
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"); }
|
|
210
|
+
if (dead || proposal !== revision) return;
|
|
211
|
+
}
|
|
212
|
+
try { observe(); } catch { stopAll("trust_geometry_unknown"); tell(); return; }
|
|
213
|
+
if (baseline === null || baselineDevice !== device()) {
|
|
214
|
+
if (calibration && baselineDevice === device()) { tell(); return; }
|
|
215
|
+
if (!stopAll("calibrating") || dead || proposal !== revision) return;
|
|
216
|
+
const epoch = ++serial;
|
|
217
|
+
const job = captureEffectBaseline({ window: host, empty: () => !dead && slots.size === 0 && host.document.querySelectorAll("iframe.agend-effect-frame").length === 0 && globalAllowed() && !context.hidden && !!coverage(), clock: nativeClock });
|
|
218
|
+
calibration = job; baselineDevice = device();
|
|
219
|
+
job.promise.then(r => {
|
|
220
|
+
if (dead || calibration !== job || epoch !== serial) return;
|
|
221
|
+
calibration = null;
|
|
222
|
+
if (!r.ok) { blocked = r.reason; tell(); return; }
|
|
223
|
+
baseline = r.baselineFps; reconcile();
|
|
224
|
+
});
|
|
225
|
+
tell(); return;
|
|
226
|
+
}
|
|
227
|
+
const max = context.constrained ? 1 : 3;
|
|
228
|
+
for (const d of descriptors) {
|
|
229
|
+
if (!chosen.has(d.key) || slots.has(d.key)) continue;
|
|
230
|
+
if (slots.size >= max || loads.size >= max) break;
|
|
231
|
+
const permitted = receipt(safety.allowed, d.id, device());
|
|
232
|
+
if (proposal !== revision) return;
|
|
233
|
+
if (permitted !== true) { results.set(d.key, { verdict: "off", reason: "safety_unknown", queuePos: null }); continue; }
|
|
234
|
+
if (slots.has(d.key) || slots.size >= max || loads.size >= max || !globalAllowed() || context.hidden || !coverage(d) || proposal !== revision || !descriptors.some(x => x.key === d.key && signature(x) === signature(d) && x.element === d.element)) break;
|
|
235
|
+
const rect = position(d, coverage(d));
|
|
236
|
+
if (dead || proposal !== revision) return;
|
|
237
|
+
if (!rect || d.element.ownerDocument !== host.document) { results.set(d.key, { verdict: "off", reason: "geometry_unknown", queuePos: null }); continue; }
|
|
238
|
+
const s = { d, device: device(), owner: null, live: true, stageOff: null, ready: false, readyAt: null, frame: null, geometry: null, budget: null, token: null, request: null, loadOff: null, rect: null, pointer: null, lastPointer: null, hiddenSince: null, healthySince: null };
|
|
239
|
+
slots.set(d.key, s);
|
|
240
|
+
if (d.trialStage) {
|
|
241
|
+
s.stageOff = watchEffectTrialStage(d.trialStage, () => {
|
|
242
|
+
if (!current(s)) return;
|
|
243
|
+
const before = revision; retire(s, "trial_ended");
|
|
244
|
+
if (!dead && before === revision) { reconcile(); tell(); }
|
|
245
|
+
});
|
|
246
|
+
if (!s.stageOff || !current(s)) { retire(s, "trial_ended"); continue; }
|
|
247
|
+
}
|
|
248
|
+
const request = { controller: new host.AbortController(), slot: s, timer: null, began: time() }; s.request = request; loads.add(request);
|
|
249
|
+
const withinDeadline = () => {
|
|
250
|
+
const n = time();
|
|
251
|
+
if (n === null || request.began === null || n - request.began >= 10000) { retire(s, n === null || request.began === null ? "clock_unavailable" : "resource_timeout"); return false; }
|
|
252
|
+
return true;
|
|
253
|
+
};
|
|
254
|
+
const acceptCompletion = () => {
|
|
255
|
+
if (!current(s)) { clearMarker(s, "superseded"); return false; }
|
|
256
|
+
if (!withinDeadline()) return false;
|
|
257
|
+
if (request.controller.signal.aborted || !globalAllowed() || context.hidden || !coverage(d)) {
|
|
258
|
+
if (current(s)) retire(s, "admission_revoked"); else clearMarker(s, "superseded");
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
return withinDeadline();
|
|
262
|
+
};
|
|
263
|
+
const deadline = () => {
|
|
264
|
+
if (!current(s)) return;
|
|
265
|
+
const n = time();
|
|
266
|
+
if (n === null || n - request.began >= 10000) { retire(s, n === null ? "clock_unavailable" : "resource_timeout"); tell(); return; }
|
|
267
|
+
request.timer = host.setTimeout(deadline, Math.max(1, 10000 - (n - request.began)));
|
|
268
|
+
};
|
|
269
|
+
request.timer = host.setTimeout(deadline, 10000);
|
|
270
|
+
// Keep a physical read reservation until its promise settles, including after abort/revocation.
|
|
271
|
+
Promise.resolve().then(() => {
|
|
272
|
+
if (!current(s) || request.controller.signal.aborted) return null;
|
|
273
|
+
return load({ key: d.key, id: d.id, params: { ...d.params } }, request.controller.signal);
|
|
274
|
+
}).then(resource => {
|
|
275
|
+
if (!acceptCompletion()) return;
|
|
276
|
+
if (!plain(resource) || resource.id !== d.id || !plain(resource.params) || Object.keys(d.params).some(k => resource.params[k] !== d.params[k])) { retire(s, "resource_unknown"); return; }
|
|
277
|
+
let fresh = position(d, coverage(d));
|
|
278
|
+
if (!fresh || receipt(safety.allowed, d.id, s.device) !== true) { retire(s, "safety_unknown"); return; }
|
|
279
|
+
if (!acceptCompletion()) return;
|
|
280
|
+
const token = receipt(safety.begin, { key: d.key, id: d.id, device: s.device });
|
|
281
|
+
if (typeof token !== "string" || token.length < 1 || token.length > 128) { retire(s, "safety_unknown"); return; }
|
|
282
|
+
s.token = token;
|
|
283
|
+
if (!acceptCompletion()) return;
|
|
284
|
+
// Obtain local geometry BEFORE the factory appends its temporarily unknown iframe. bind() is
|
|
285
|
+
// the very next local-stage operation and registers that frame before checking its topology.
|
|
286
|
+
const local = d.trialStage ? localStage(d, coverage(d)) : null;
|
|
287
|
+
if (d.trialStage && !local || !current(s)) { if (current(s)) retire(s, "admission_revoked"); return; }
|
|
288
|
+
if (local) fresh = local.rect;
|
|
289
|
+
s.rect = fresh;
|
|
290
|
+
s.budget = new EffectBudget({ device: s.device, baselineFps: baseline, clock: nativeClock, longTasksSupported });
|
|
291
|
+
const frame = createEffectFrame({ window: host, root: local?.root ?? root, origin, boot, clock: nativeClock,
|
|
292
|
+
render: { code: resource.code, params: resource.params, assets: resource.assets, wants: resource.wants, instance: d.instance, width: fresh.width, height: fresh.height, dpr: dpr(s.device) },
|
|
293
|
+
onReady() { if (!current(s)) return; if (!globalAllowed() || context.hidden || !coverage(d)) { retire(s, "hidden"); tell(); return; } const n = time(); if (n === null) { blocked = "clock_unavailable"; stopAll(blocked); tell(); return; } s.ready = true; s.readyAt = n; s.healthySince = n; publishEnv(s); schedule(); tell(); },
|
|
294
|
+
onRemove(why) { if (current(s)) { retire(s, why); tell(); } },
|
|
295
|
+
});
|
|
296
|
+
s.frame = frame;
|
|
297
|
+
if (!current(s) || !frame.ok || frame.state().removed) { frame.remove?.("stale_mount"); retire(s, "mount_failed"); return; }
|
|
298
|
+
frame.element.id = `agend-effect-${boot}-${++frameSerial}`;
|
|
299
|
+
s.geometry = local ? local.bind(frame.element, { layer: d.layer }, coverage()) : geometry.bind(frame.element, { layer: d.layer, by: d.by });
|
|
300
|
+
if (!s.geometry.ok) { retire(s, "geometry_unknown"); return; }
|
|
301
|
+
const loaded = () => { if (current(s)) s.budget.loaded(); };
|
|
302
|
+
frame.element.addEventListener("load", loaded); s.loadOff = () => frame.element.removeEventListener("load", loaded);
|
|
303
|
+
const paint = coverage(d);
|
|
304
|
+
if (!current(s) || !paint || !syncGeometry(s, paint)) { retire(s, "geometry_unknown"); return; }
|
|
305
|
+
// One non-serializable host receipt per actual admitted frame. Never append it to a Worker event.
|
|
306
|
+
const owner = Object.freeze({ key: d.key, id: d.id, device: s.device, current: () => current(s) && s.owner === owner });
|
|
307
|
+
s.owner = owner;
|
|
308
|
+
try { onMount(owner); } catch { /* diagnostics/display failure cannot authorize or mutate a mount */ }
|
|
309
|
+
schedule();
|
|
310
|
+
}).catch(() => { if (current(s)) retire(s, "resource_unavailable"); }).finally(() => {
|
|
311
|
+
if (request.timer !== null) host.clearTimeout(request.timer);
|
|
312
|
+
loads.delete(request); if (s.request === request) s.request = null;
|
|
313
|
+
if (!dead) reconcile(); else if (loads.size === 0 && registries.get(host) === api) registries.delete(host);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
schedule(); tell();
|
|
317
|
+
}
|
|
318
|
+
function publishEnv(s, proof = coverage(s.d)) {
|
|
319
|
+
if (!s.ready || !current(s) || context.hidden || !globalAllowed() || !permits(s.d, proof)) return;
|
|
320
|
+
const e = effectEvent("env", { width: s.rect.width, height: s.rect.height, dpr: dpr(s.device), quality: s.budget.snapshot().quality }, null, time());
|
|
321
|
+
if (e) s.frame.send(e);
|
|
322
|
+
}
|
|
323
|
+
function tick() {
|
|
324
|
+
raf = null;
|
|
325
|
+
if (dead) return;
|
|
326
|
+
const paint = coverage();
|
|
327
|
+
if (!globalAllowed() || context.hidden || !paint) { invalidate(); return; }
|
|
328
|
+
const proposal = revision; let policyChanged = false;
|
|
329
|
+
for (const s of [...slots.values()]) {
|
|
330
|
+
if (dead || proposal !== revision) return;
|
|
331
|
+
if (!s.frame) continue;
|
|
332
|
+
if (!permits(s.d, paint)) { retire(s, "superseded"); policyChanged = true; continue; }
|
|
333
|
+
if (dead || proposal !== revision) return;
|
|
334
|
+
const rect = syncGeometry(s, paint);
|
|
335
|
+
if (!current(s)) continue;
|
|
336
|
+
if (!rect) { retire(s, "geometry_unknown"); continue; }
|
|
337
|
+
// The host owns the CSS viewport. A bounded env signal lets Worker code redraw its own bitmap if desired.
|
|
338
|
+
const changed = rect.width !== s.rect.width || rect.height !== s.rect.height; s.rect = rect;
|
|
339
|
+
if (changed) publishEnv(s, paint);
|
|
340
|
+
if (s.ready) s.budget.frame();
|
|
341
|
+
if (s.pointer) {
|
|
342
|
+
const packet = s.pointer; s.pointer = null;
|
|
343
|
+
const n = time(), b = s.budget.snapshot();
|
|
344
|
+
if (n !== null && n - packet.at <= 100 && permits(s.d, paint) && pointerGate(paint) && current(s) && b.forward && (s.lastPointer === null || n - s.lastPointer >= 1000 / b.pointerHz)) {
|
|
345
|
+
const event = effectEvent("pointer", packet.fields, s.d.instance, packet.at);
|
|
346
|
+
if (event && s.frame.send(event)) s.lastPointer = n;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (dead || proposal !== revision) return;
|
|
351
|
+
if (policyChanged) reconcile(); else schedule();
|
|
352
|
+
}
|
|
353
|
+
function heartbeat() {
|
|
354
|
+
timer = null;
|
|
355
|
+
if (dead) return;
|
|
356
|
+
if (time() === null) { blocked = "clock_unavailable"; stopAll(blocked); tell(); return; }
|
|
357
|
+
const proposal = revision, activeBeforeSafety = slots.size;
|
|
358
|
+
if (!checkSafety()) { tell(); return; }
|
|
359
|
+
if (slots.size !== activeBeforeSafety) reconcile();
|
|
360
|
+
if (dead || proposal !== revision) return;
|
|
361
|
+
if (!globalAllowed() || context.hidden || !coverage()) { invalidate(); return; }
|
|
362
|
+
const budgetPauses = new Set();
|
|
363
|
+
for (const s of [...slots.values()]) {
|
|
364
|
+
if (dead || proposal !== revision) return;
|
|
365
|
+
if (!current(s) || !s.frame || !s.ready) continue;
|
|
366
|
+
if (s.d.trialStage && !coverage(s.d)) { if (dead || proposal !== revision) return; if (current(s)) retire(s, "trial_ended"); continue; }
|
|
367
|
+
if (dead || proposal !== revision) return;
|
|
368
|
+
const r = s.budget.gates({ hidden: false, reducedMotion: context.reducedMotion, saveData: context.saveData, show: context.show });
|
|
369
|
+
const state = r.remove ? r : s.readyAt !== null && last - s.readyAt >= 3000 ? s.budget.poll() : r;
|
|
370
|
+
try { onProfile({ key: s.d.key, id: s.d.id, device: s.device, ...state }, s.owner); } catch { /* metrics never authorize a mount */ }
|
|
371
|
+
if (dead || proposal !== revision) return;
|
|
372
|
+
if (!current(s)) continue;
|
|
373
|
+
if (s.d.trialStage && !coverage(s.d)) { if (dead || proposal !== revision) return; if (current(s)) retire(s, "trial_ended"); continue; }
|
|
374
|
+
if (dead || proposal !== revision) return;
|
|
375
|
+
if (state.remove) { const key = s.d.id + ":" + s.device; const count = state.reason === "host_budget" && !budgetPauses.has(key); if (count) budgetPauses.add(key); retire(s, state.reason, count); continue; }
|
|
376
|
+
if (state.badWindows > 0) s.healthySince = null; else if (s.healthySince === null) s.healthySince = last;
|
|
377
|
+
if (s.token && s.healthySince !== null && last - s.healthySince >= 5000 && state.badWindows === 0 && state.metrics !== null && !clearMarker(s, "healthy")) { stopAll("safety_unknown"); break; }
|
|
378
|
+
publishEnv(s);
|
|
379
|
+
}
|
|
380
|
+
if (dead || proposal !== revision) return;
|
|
381
|
+
schedule(); tell();
|
|
382
|
+
}
|
|
383
|
+
function checkSafety() {
|
|
384
|
+
if (dead || blocked) return false;
|
|
385
|
+
const proposed = revision;
|
|
386
|
+
for (const s of [...slots.values()]) {
|
|
387
|
+
if (!current(s)) continue;
|
|
388
|
+
const allowed = receipt(safety.allowed, s.d.id, s.device);
|
|
389
|
+
if (dead || proposed !== revision) return false;
|
|
390
|
+
if (current(s) && allowed !== true) retire(s, "safety_revoked");
|
|
391
|
+
if (dead || blocked || proposed !== revision) return false;
|
|
392
|
+
}
|
|
393
|
+
return !dead && !blocked;
|
|
394
|
+
}
|
|
395
|
+
function revalidateSafety() {
|
|
396
|
+
if (dead || reentrantStock()) return view();
|
|
397
|
+
if (checkSafety()) reconcile(); else tell();
|
|
398
|
+
return view();
|
|
399
|
+
}
|
|
400
|
+
function pointerGate(proof = coverage()) {
|
|
401
|
+
if (!globalAllowed() || context.hidden || context.modal || !proof || proof.front !== true) return false;
|
|
402
|
+
try {
|
|
403
|
+
const focused = host.document.activeElement;
|
|
404
|
+
return host.document.designMode !== "on" && !!focused && ["BODY", "BUTTON", "A"].includes(focused.tagName) && focused.isContentEditable === false && typeof focused.matches === "function" && !focused.matches("input,textarea,select,[contenteditable]:not([contenteditable='false'])");
|
|
405
|
+
} catch { return false; }
|
|
406
|
+
}
|
|
407
|
+
function pointer(event) {
|
|
408
|
+
if (dead || blocked || !pointerGate() || event.isTrusted !== true) return;
|
|
409
|
+
const kinds = { pointermove: "move", pointerdown: "down", pointerup: "up", click: "click", wheel: "wheel" }, kind = kinds[event.type];
|
|
410
|
+
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;
|
|
411
|
+
try { const target = host.document.elementFromPoint(event.clientX, event.clientY); if (!target || typeof target.closest !== "function" || target.closest("[data-trust]")) return; } catch { return; }
|
|
412
|
+
const at = time(); if (at === null) { blocked = "clock_unavailable"; stopAll(blocked); tell(); return; }
|
|
413
|
+
for (const s of slots.values()) {
|
|
414
|
+
if (!s.ready || !s.frame || !s.budget.snapshot().forward || !coverage(s.d) || !current(s)) continue;
|
|
415
|
+
const r = hostEffectRect(s.d.element); if (!r) continue;
|
|
416
|
+
const fields = { kind, x: event.clientX - r.x, y: event.clientY - r.y, buttons: event.buttons };
|
|
417
|
+
if (fields.x < 0 || fields.y < 0 || fields.x > r.width || fields.y > r.height) continue;
|
|
418
|
+
if (kind === "wheel") { fields.dx = event.deltaX; fields.dy = event.deltaY; }
|
|
419
|
+
if (effectEvent("pointer", fields, s.d.instance, at)) s.pointer = { fields, at };
|
|
420
|
+
}
|
|
421
|
+
schedule();
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
if (time() === null) throw Error("clock unavailable");
|
|
425
|
+
root = host.document.createElement("div"); root.className = "agend-effect-layer"; host.document.body.append(root);
|
|
426
|
+
geometry = createEffectGeometry({ window: host }); if (!geometry.ok) throw Error("geometry unsupported");
|
|
427
|
+
observer = new host.MutationObserver(invalidate); observer.observe(host.document.documentElement, { childList: true, subtree: true, attributes: true, characterData: true });
|
|
428
|
+
resize = new host.ResizeObserver(invalidate);
|
|
429
|
+
for (const type of ["scroll", "resize", "orientationchange", "focusin", "focusout"]) { host.addEventListener(type, invalidate, true); offs.push(() => host.removeEventListener(type, invalidate, true)); }
|
|
430
|
+
for (const type of ["pointermove", "pointerdown", "pointerup", "click", "wheel"]) { host.addEventListener(type, pointer, { passive: true }); offs.push(() => host.removeEventListener(type, pointer)); }
|
|
431
|
+
host.addEventListener("storage", revalidateSafety); offs.push(() => host.removeEventListener("storage", revalidateSafety));
|
|
432
|
+
const visibility = () => { revalidateSafety(); invalidate(); };
|
|
433
|
+
host.document.addEventListener("visibilitychange", visibility); offs.push(() => host.document.removeEventListener("visibilitychange", visibility));
|
|
434
|
+
if (typeof host.PerformanceObserver === "function" && host.PerformanceObserver.supportedEntryTypes?.includes("longtask")) {
|
|
435
|
+
try {
|
|
436
|
+
longTasks = new host.PerformanceObserver(list => {
|
|
437
|
+
for (const entry of list.getEntries()) for (const s of slots.values()) if (s.ready && s.budget) {
|
|
438
|
+
// No URL, container name, content or private Worker timing is read. Missing attribution stays unknown.
|
|
439
|
+
const attributed = Array.isArray(entry.attribution) && entry.attribution.some(a => a.containerId === s.frame.element.id && typeof a.containerId === "string" && a.containerId.length > 0);
|
|
440
|
+
s.budget.longTask(entry.startTime, entry.duration, attributed);
|
|
441
|
+
}
|
|
442
|
+
}); longTasks.observe({ type: "longtask", buffered: false }); longTasksSupported = true;
|
|
443
|
+
} catch { longTasks?.disconnect(); longTasks = null; }
|
|
444
|
+
}
|
|
445
|
+
} catch {
|
|
446
|
+
dead = true;
|
|
447
|
+
for (const release of [() => observer?.disconnect(), () => resize?.disconnect(), () => longTasks?.disconnect(), ...offs, () => geometry?.dispose(), () => root?.remove()]) { try { release(); } catch { /* continue releasing other host resources */ } }
|
|
448
|
+
return { ok: false, reason: "registry_unsupported" };
|
|
449
|
+
}
|
|
450
|
+
const api = { ok: true,
|
|
451
|
+
update(ds, ctx) {
|
|
452
|
+
if (dead || reentrantStock()) return view();
|
|
453
|
+
hideGeometry();
|
|
454
|
+
revision++;
|
|
455
|
+
if (!Array.isArray(ds) || ds.length > 128 || !plain(ctx)) { descriptors = []; context = null; results.clear(); stopAll("gates_unknown"); return []; }
|
|
456
|
+
descriptors = ds.map(snapshotDescriptor).filter(Boolean);
|
|
457
|
+
for (const [key, identity] of paused) if (!descriptors.some(d => d.key === key && signature(d) === identity)) paused.delete(key);
|
|
458
|
+
for (const [key, f] of failures) if (!descriptors.some(d => d.key === key && signature(d) === f.identity)) failures.delete(key);
|
|
459
|
+
context = Object.fromEntries([...FLAGS, "openInstance"].map(k => [k, ctx[k]]));
|
|
460
|
+
reconcile(); return view();
|
|
461
|
+
},
|
|
462
|
+
snapshot: view,
|
|
463
|
+
/** Host storage/foreground observation only, never called from a frame message. */
|
|
464
|
+
revalidateSafety,
|
|
465
|
+
/** Called only by the host's explicit human Resume UI. A descriptor update never clears this latch. */
|
|
466
|
+
resume(key) {
|
|
467
|
+
if (dead || reentrantStock() || blocked && !blocked.startsWith("baseline_") || typeof key !== "string") return false;
|
|
468
|
+
const proposed = revision, d = descriptors.find(d => d.key === key); if (!d || d.trialStage && !coverage(d) || revision !== proposed || receipt(safety.resume, d.id, device()) !== true || revision !== proposed) return false;
|
|
469
|
+
revision++;
|
|
470
|
+
if (!stopAll("human_resume")) return false;
|
|
471
|
+
if (blocked && !blocked.startsWith("baseline_")) return false; blocked = null; paused.delete(key); failures.delete(key); baseline = null; serial++; reconcile(); return true;
|
|
472
|
+
},
|
|
473
|
+
/** Host-only content-free signal API. Raw pointer publishing is refused; native pointer metadata is coalesced here. */
|
|
474
|
+
publish(type, fields, instance = null) {
|
|
475
|
+
if (dead || blocked || !globalAllowed() || context.hidden || !coverage() || !TYPES.includes(type)) return 0;
|
|
476
|
+
const ts = time(); if (ts === null) { blocked = "clock_unavailable"; stopAll(blocked); tell(); return 0; }
|
|
477
|
+
let sent = 0; const proposal = revision;
|
|
478
|
+
for (const s of [...slots.values()]) {
|
|
479
|
+
if (dead || proposal !== revision) return sent;
|
|
480
|
+
if (!s.ready || !s.frame || !s.budget.snapshot().forward || !coverage(s.d) || !current(s)) continue;
|
|
481
|
+
if (["state", "reply", "mention"].includes(type) && (s.d.instance !== null ? instance !== s.d.instance : instance !== context.openInstance)) continue;
|
|
482
|
+
const e = effectEvent(type, fields, s.d.instance, ts); if (e && s.frame.send(e)) sent++;
|
|
483
|
+
}
|
|
484
|
+
return sent;
|
|
485
|
+
},
|
|
486
|
+
dispose() {
|
|
487
|
+
if (dead) return; dead = true; revision++; serial++; stopAll("disposed");
|
|
488
|
+
if (raf !== null) host.cancelAnimationFrame(raf); if (timer !== null) host.clearTimeout(timer);
|
|
489
|
+
observer.disconnect(); resize.disconnect(); longTasks?.disconnect(); for (const off of offs) off();
|
|
490
|
+
geometry.dispose(); root.remove(); observed.clear(); if (loads.size === 0 && registries.get(host) === api) registries.delete(host);
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
// Read-only host geometry seam; no selector guessing among poster and live roots.
|
|
494
|
+
Object.defineProperty(api, "frameRoot", { get: () => dead ? null : root });
|
|
495
|
+
registries.set(host, api); return api;
|
|
496
|
+
}
|