@songsid/agend 2.3.0-beta.2 → 2.3.0-beta.21
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 +7 -1
- package/README.zh-TW.md +7 -1
- package/dist/agent-cli-instructions.md +9 -2
- package/dist/agent-cli.js +63 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +4 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.d.ts +4 -1
- package/dist/agent-file-read.js +189 -16
- package/dist/agent-file-read.js.map +1 -1
- package/dist/agent-whats-new.d.ts +11 -0
- package/dist/agent-whats-new.js +29 -5
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.d.ts +30 -1
- package/dist/auth-api.js +45 -13
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/authority-state.d.ts +38 -0
- package/dist/authority/authority-state.js +114 -0
- package/dist/authority/authority-state.js.map +1 -0
- package/dist/authority/session-authorizations.d.ts +43 -0
- package/dist/authority/session-authorizations.js +102 -0
- package/dist/authority/session-authorizations.js.map +1 -0
- package/dist/authority/web-authority.d.ts +120 -0
- package/dist/authority/web-authority.js +157 -0
- package/dist/authority/web-authority.js.map +1 -0
- package/dist/backend/claude-code.d.ts +2 -2
- package/dist/backend/claude-code.js +18 -8
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +8 -0
- package/dist/backend/codex-metadata.js +74 -17
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex.js +15 -2
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +2 -0
- package/dist/backend/credential-profile.js +2 -0
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/types.d.ts +6 -0
- package/dist/backend/types.js +15 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-availability.d.ts +120 -0
- package/dist/backend-availability.js +396 -0
- package/dist/backend-availability.js.map +1 -0
- package/dist/backend-command.d.ts +23 -3
- package/dist/backend-command.js +25 -4
- package/dist/backend-command.js.map +1 -1
- package/dist/bug-report-cli.d.ts +30 -0
- package/dist/bug-report-cli.js +138 -0
- package/dist/bug-report-cli.js.map +1 -0
- package/dist/bug-report.d.ts +47 -0
- package/dist/bug-report.js +136 -0
- package/dist/bug-report.js.map +1 -0
- package/dist/bundled-skills.d.ts +14 -0
- package/dist/bundled-skills.js +29 -0
- package/dist/bundled-skills.js.map +1 -0
- package/dist/cache-ledger.d.ts +16 -3
- package/dist/cache-ledger.js +33 -13
- package/dist/cache-ledger.js.map +1 -1
- package/dist/cache-service.d.ts +55 -3
- package/dist/cache-service.js +152 -16
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
- package/dist/channel/adapters/discord-client-retirement.js +57 -0
- package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +9 -0
- package/dist/channel/adapters/discord.js +49 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-tools.js +22 -11
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +6 -0
- package/dist/classic-channel-manager.d.ts +10 -5
- package/dist/classic-channel-manager.js +12 -9
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +224 -111
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.d.ts +6 -0
- package/dist/config-validator.js +129 -3
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +13 -1
- package/dist/config.js +14 -5
- package/dist/config.js.map +1 -1
- package/dist/cross-instance-notice.d.ts +7 -0
- package/dist/cross-instance-notice.js +10 -0
- package/dist/cross-instance-notice.js.map +1 -1
- package/dist/daemon.d.ts +24 -1
- package/dist/daemon.js +151 -19
- package/dist/daemon.js.map +1 -1
- package/dist/decision-list.d.ts +25 -0
- package/dist/decision-list.js +30 -0
- package/dist/decision-list.js.map +1 -0
- package/dist/delivery-outbox.d.ts +10 -0
- package/dist/delivery-outbox.js +17 -1
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/diagnostic-redaction.d.ts +10 -0
- package/dist/diagnostic-redaction.js +167 -0
- package/dist/diagnostic-redaction.js.map +1 -0
- package/dist/fleet-context.d.ts +10 -0
- package/dist/fleet-manager.d.ts +505 -15
- package/dist/fleet-manager.js +1870 -204
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +18 -0
- package/dist/fleet-process-handlers.js +69 -0
- package/dist/fleet-process-handlers.js.map +1 -0
- package/dist/fleet-traffic.d.ts +74 -0
- package/dist/fleet-traffic.js +196 -0
- package/dist/fleet-traffic.js.map +1 -0
- package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +17 -6
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +6 -1
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +2 -0
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +3 -2
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
- package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +190 -47
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +545 -0
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/human-delivery-receipts.d.ts +24 -1
- package/dist/human-delivery-receipts.js +64 -11
- package/dist/human-delivery-receipts.js.map +1 -1
- package/dist/instance-config-impact.js +7 -1
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +10 -1
- package/dist/instance-lifecycle.js +79 -18
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instance-names.d.ts +4 -0
- package/dist/instance-names.js +12 -0
- package/dist/instance-names.js.map +1 -0
- package/dist/instructions.d.ts +12 -1
- package/dist/instructions.js +13 -2
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +173 -12
- package/dist/locale.js.map +1 -1
- package/dist/log-steps.d.ts +1 -0
- package/dist/log-steps.js +15 -0
- package/dist/log-steps.js.map +1 -1
- package/dist/login-controller.d.ts +45 -0
- package/dist/login-controller.js +101 -5
- package/dist/login-controller.js.map +1 -1
- package/dist/ls-attach-resolve.d.ts +96 -0
- package/dist/ls-attach-resolve.js +180 -0
- package/dist/ls-attach-resolve.js.map +1 -0
- package/dist/ls-rows.d.ts +12 -0
- package/dist/ls-rows.js +82 -3
- package/dist/ls-rows.js.map +1 -1
- package/dist/memory-hogs.d.ts +27 -0
- package/dist/memory-hogs.js +124 -0
- package/dist/memory-hogs.js.map +1 -0
- package/dist/needs-you.d.ts +10 -0
- package/dist/needs-you.js +2 -1
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +11 -0
- package/dist/outbound-handlers.js +139 -11
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +200 -4
- package/dist/outbound-schemas.js +124 -11
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +17 -4
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +9 -0
- package/dist/public-web-link.js +8 -0
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.d.ts +19 -1
- package/dist/quickstart-api.js +94 -4
- package/dist/quickstart-api.js.map +1 -1
- package/dist/reply-buttons-controller.d.ts +4 -0
- package/dist/reply-buttons-controller.js +2 -2
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/restart-progress.d.ts +80 -1
- package/dist/restart-progress.js +306 -21
- package/dist/restart-progress.js.map +1 -1
- package/dist/rollout-index.d.ts +5 -0
- package/dist/rollout-index.js +26 -5
- package/dist/rollout-index.js.map +1 -1
- package/dist/scheduler/db.d.ts +40 -13
- package/dist/scheduler/db.js +123 -89
- package/dist/scheduler/db.js.map +1 -1
- package/dist/scheduler/task-board-text.d.ts +26 -0
- package/dist/scheduler/task-board-text.js +135 -0
- package/dist/scheduler/task-board-text.js.map +1 -0
- package/dist/scheduler/task-board.d.ts +650 -0
- package/dist/scheduler/task-board.js +1938 -0
- package/dist/scheduler/task-board.js.map +1 -0
- package/dist/scheduler/types.d.ts +6 -1
- package/dist/search/search-docs.d.ts +58 -0
- package/dist/search/search-docs.js +63 -0
- package/dist/search/search-docs.js.map +1 -0
- package/dist/search/search-index.d.ts +141 -0
- package/dist/search/search-index.js +440 -0
- package/dist/search/search-index.js.map +1 -0
- package/dist/search/search-store.d.ts +122 -0
- package/dist/search/search-store.js +236 -0
- package/dist/search/search-store.js.map +1 -0
- package/dist/search/search-worker.d.ts +1 -0
- package/dist/search/search-worker.js +163 -0
- package/dist/search/search-worker.js.map +1 -0
- package/dist/service-installer.js +12 -0
- package/dist/service-installer.js.map +1 -1
- package/dist/settings-api.d.ts +23 -0
- package/dist/settings-api.js +164 -3
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +104 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +3 -1
- package/dist/settings-confirmation.js +2 -0
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-effect.js +34 -3
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +11 -0
- package/dist/settings-http-confirmation.js +10 -0
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +23 -7
- package/dist/setup-form.js.map +1 -1
- package/dist/spawn-gate.d.ts +1 -0
- package/dist/spawn-gate.js +13 -3
- package/dist/spawn-gate.js.map +1 -1
- package/dist/task-board-tool.d.ts +25 -0
- package/dist/task-board-tool.js +154 -0
- package/dist/task-board-tool.js.map +1 -0
- package/dist/task-board-waker.d.ts +44 -0
- package/dist/task-board-waker.js +128 -0
- package/dist/task-board-waker.js.map +1 -0
- package/dist/tmux-exec-helper.d.ts +94 -0
- package/dist/tmux-exec-helper.js +407 -0
- package/dist/tmux-exec-helper.js.map +1 -0
- package/dist/tmux-manager.d.ts +5 -0
- package/dist/tmux-manager.js +42 -11
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tool-permissions.d.ts +0 -7
- package/dist/tool-permissions.js +44 -5
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +17 -1
- package/dist/topic-commands.js +45 -19
- package/dist/topic-commands.js.map +1 -1
- package/dist/tunnel/cloudflared.js +37 -2
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/types.d.ts +3 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/types.d.ts +63 -1
- package/dist/ui/app-effects.js +90 -32
- package/dist/ui/backend-signin.js +297 -0
- package/dist/ui/chat-ambient.js +307 -0
- package/dist/ui/chat-effect-posters.js +8 -8
- package/dist/ui/chat-effects.js +110 -15
- package/dist/ui/chat-msg-actions.js +176 -0
- package/dist/ui/chat-render.js +21 -3
- package/dist/ui/chat-store.js +64 -12
- package/dist/ui/chat-strings.js +85 -8
- package/dist/ui/chat-thread.js +204 -21
- package/dist/ui/effect-trial-controller.js +13 -8
- package/dist/ui/effect-trial-panel.js +19 -16
- package/dist/ui/effects-waker.js +70 -0
- package/dist/ui/fleet-canvas-layout.js +117 -0
- package/dist/ui/fleet-canvas.js +555 -0
- package/dist/ui/fleet-org.js +27 -12
- package/dist/ui/fleet-route-scene.js +207 -0
- package/dist/ui/fleet-route-worker.js +21 -0
- package/dist/ui/fleet-route.js +88 -0
- package/dist/ui/fleet-task-card.js +436 -0
- package/dist/ui/fleet-task-common.js +448 -0
- package/dist/ui/fleet-tasks.js +535 -0
- package/dist/ui/fleet-traffic.js +359 -0
- package/dist/ui/fleet-usage.js +435 -0
- package/dist/ui/panel-chat.js +264 -66
- package/dist/ui/panel-details.js +2 -1
- package/dist/ui/panel-fleet.js +65 -83
- package/dist/ui/panel-needs.js +4 -2
- package/dist/ui/panel-settings.js +56 -11
- package/dist/ui/preview.js +3 -2
- package/dist/ui/search-dialog.js +349 -0
- package/dist/ui/settings-appearance.js +44 -19
- package/dist/ui/settings-apply.js +3 -3
- package/dist/ui/settings-catalog.js +92 -0
- package/dist/ui/settings-confirm.js +7 -2
- package/dist/ui/settings-dialogs.js +40 -12
- package/dist/ui/settings-effects.js +4 -3
- package/dist/ui/settings-guests.js +117 -0
- package/dist/ui/settings-learn.js +25 -0
- package/dist/ui/settings-model.js +15 -6
- package/dist/ui/settings-mods.js +23 -9
- package/dist/ui/settings-owner-effects.js +15 -13
- package/dist/ui/settings-strings.js +122 -42
- package/dist/ui/settings-web-authority.js +91 -0
- package/dist/ui/shared/agend-auth.js +1 -1
- package/dist/ui/shared/app-i18n.js +11 -2
- package/dist/ui/shared/app-prefs.js +17 -4
- package/dist/ui/shared/app-route.js +19 -1
- package/dist/ui/shared/app-session.js +2 -0
- package/dist/ui/shared/app-shell.js +174 -30
- package/dist/ui/shared/app-store.js +26 -1
- package/dist/ui/shared/app-stream.js +5 -1
- package/dist/ui/shared/app-themes.js +140 -7
- package/dist/ui/shared/app.css +705 -20
- package/dist/ui/shared/app.js +26 -15
- package/dist/ui/shared/card-strings.js +8 -0
- package/dist/ui/shared/effect-app-runtime.js +68 -19
- package/dist/ui/shared/effect-chat-runtime.js +16 -3
- package/dist/ui/shared/effect-frame.js +26 -7
- package/dist/ui/shared/effect-geometry.js +24 -9
- package/dist/ui/shared/effect-owner-source.js +8 -1
- package/dist/ui/shared/effect-policy.js +21 -7
- package/dist/ui/shared/effect-profiler.js +31 -9
- package/dist/ui/shared/effect-registry.js +97 -50
- package/dist/ui/shared/effect-stock-snapshot.js +9 -0
- package/dist/ui/shared/effect-stock-trust.js +62 -10
- package/dist/ui/shared/effect-trial-shadow.js +62 -0
- package/dist/ui/shared/effect-trial-source.js +1 -1
- package/dist/ui/shared/effect-trial-stage.js +54 -31
- package/dist/ui/shared/effect-trial.css +40 -0
- package/dist/ui/shared/fx-motion.js +67 -0
- package/dist/ui/shared/identity-card.js +100 -11
- package/dist/ui/shared/identity-color.js +14 -10
- package/dist/ui/shared/instance-nav.js +179 -23
- package/dist/ui/shared/owner-css.js +30 -1
- package/dist/ui/shared/panel-view.js +24 -4
- package/dist/ui/shared/tokens.css +9 -3
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/shared/ui-menu.js +20 -7
- package/dist/ui/shared/ui-toast.js +16 -3
- package/dist/ui/shared/usage-dialog.js +34 -3
- package/dist/ui/shared/view-strings.js +72 -0
- package/dist/ui/shared/web-authorize.js +198 -0
- package/dist/ui/web-terminal/terminal.css +4 -4
- package/dist/ui/web-terminal/terminal.html +1 -1
- package/dist/update-launch.d.ts +9 -0
- package/dist/update-launch.js +38 -12
- package/dist/update-launch.js.map +1 -1
- package/dist/usage/format-rich.js +6 -3
- package/dist/usage/format-rich.js.map +1 -1
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +2 -1
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/i18n.d.ts +13 -1
- package/dist/usage/i18n.js +29 -0
- package/dist/usage/i18n.js.map +1 -1
- package/dist/usage/providers.d.ts +81 -2
- package/dist/usage/providers.js +240 -38
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/usage-api.d.ts +5 -1
- package/dist/usage/usage-api.js +184 -58
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/usage-report.d.ts +158 -0
- package/dist/usage-report.js +226 -0
- package/dist/usage-report.js.map +1 -0
- package/dist/usage-rollup.d.ts +51 -0
- package/dist/usage-rollup.js +168 -0
- package/dist/usage-rollup.js.map +1 -0
- package/dist/user-systemd.d.ts +24 -0
- package/dist/user-systemd.js +75 -0
- package/dist/user-systemd.js.map +1 -0
- package/dist/view-api.d.ts +39 -0
- package/dist/view-api.js +69 -6
- package/dist/view-api.js.map +1 -1
- package/dist/web-ambient.d.ts +72 -0
- package/dist/web-ambient.js +161 -0
- package/dist/web-ambient.js.map +1 -0
- package/dist/web-api.d.ts +98 -14
- package/dist/web-api.js +1027 -83
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-policy.d.ts +4 -6
- package/dist/web-appearance-policy.js +5 -12
- package/dist/web-appearance-policy.js.map +1 -1
- package/dist/web-appearance-tools.d.ts +3 -0
- package/dist/web-appearance-tools.js +22 -3
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance-view.d.ts +27 -2
- package/dist/web-appearance-view.js +129 -14
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-appearance.d.ts +17 -3
- package/dist/web-appearance.js +85 -8
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-asset-parts.d.ts +2 -2
- package/dist/web-asset-parts.js +3 -3
- package/dist/web-asset-parts.js.map +1 -1
- package/dist/web-auth.js +3 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-backend-login.d.ts +130 -0
- package/dist/web-backend-login.js +225 -0
- package/dist/web-backend-login.js.map +1 -0
- package/dist/web-card.d.ts +14 -0
- package/dist/web-card.js +40 -6
- package/dist/web-card.js.map +1 -1
- package/dist/web-channel-echo.d.ts +7 -1
- package/dist/web-channel-echo.js +6 -2
- package/dist/web-channel-echo.js.map +1 -1
- package/dist/web-chat-history.d.ts +83 -0
- package/dist/web-chat-history.js +137 -5
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +6 -1
- package/dist/web-commands.js +1 -1
- package/dist/web-commands.js.map +1 -1
- package/dist/web-effect-bootstrap.d.ts +12 -0
- package/dist/web-effect-bootstrap.js +49 -0
- package/dist/web-effect-bootstrap.js.map +1 -0
- package/dist/web-effect-bundle.js +46 -1
- package/dist/web-effect-bundle.js.map +1 -1
- package/dist/web-effect-playback.d.ts +30 -0
- package/dist/web-effect-playback.js +71 -0
- package/dist/web-effect-playback.js.map +1 -0
- package/dist/web-effect-profiles.d.ts +4 -4
- package/dist/web-effect-service.d.ts +11 -4
- package/dist/web-effect-service.js +25 -4
- package/dist/web-effect-service.js.map +1 -1
- package/dist/web-effect-tools.d.ts +1 -0
- package/dist/web-effect-tools.js +4 -4
- package/dist/web-effect-tools.js.map +1 -1
- package/dist/web-effect-trials.d.ts +2 -2
- package/dist/web-effect-trials.js +3 -3
- package/dist/web-effect-trials.js.map +1 -1
- package/dist/web-effect-upload.js +1 -1
- package/dist/web-effect-upload.js.map +1 -1
- package/dist/web-effect-worker.d.ts +1 -1
- package/dist/web-effect-worker.js +2 -2
- package/dist/web-effect-worker.js.map +1 -1
- package/dist/web-effect.d.ts +1 -1
- package/dist/web-guest-access.d.ts +126 -0
- package/dist/web-guest-access.js +238 -0
- package/dist/web-guest-access.js.map +1 -0
- package/dist/web-guest-rooms.d.ts +82 -0
- package/dist/web-guest-rooms.js +135 -0
- package/dist/web-guest-rooms.js.map +1 -0
- package/dist/web-host-guard.d.ts +11 -0
- package/dist/web-host-guard.js +11 -0
- package/dist/web-host-guard.js.map +1 -1
- package/dist/web-identity-color.d.ts +1 -1
- package/dist/web-identity-color.js +2 -2
- package/dist/web-identity-color.js.map +1 -1
- package/dist/web-identity-palette.d.ts +1 -1
- package/dist/web-identity-palette.js +2 -2
- package/dist/web-identity-palette.js.map +1 -1
- package/dist/web-image-meta.d.ts +13 -0
- package/dist/web-image-meta.js +62 -0
- package/dist/web-image-meta.js.map +1 -1
- package/dist/web-libavoid.d.ts +14 -0
- package/dist/web-libavoid.js +46 -0
- package/dist/web-libavoid.js.map +1 -0
- package/dist/web-login.d.ts +47 -0
- package/dist/web-login.js +115 -0
- package/dist/web-login.js.map +1 -1
- package/dist/web-mod-agent.d.ts +1 -1
- package/dist/web-mod-agent.js +7 -5
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-mod-bundle.d.ts +9 -1
- package/dist/web-mod-bundle.js +62 -3
- package/dist/web-mod-bundle.js.map +1 -1
- package/dist/web-mod-export.d.ts +9 -0
- package/dist/web-mod-export.js +21 -0
- package/dist/web-mod-export.js.map +1 -1
- package/dist/web-mod-store.d.ts +7 -1
- package/dist/web-mod-store.js +19 -6
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-owner-css-store.d.ts +44 -1
- package/dist/web-owner-css-store.js +70 -9
- package/dist/web-owner-css-store.js.map +1 -1
- package/dist/web-prefs.d.ts +14 -0
- package/dist/web-prefs.js +37 -4
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +6 -2
- package/dist/web-preview.js +4 -2
- package/dist/web-preview.js.map +1 -1
- package/dist/web-returning-device.d.ts +41 -0
- package/dist/web-returning-device.js +57 -5
- package/dist/web-returning-device.js.map +1 -1
- package/dist/web-session-authorization.d.ts +132 -0
- package/dist/web-session-authorization.js +193 -0
- package/dist/web-session-authorization.js.map +1 -0
- package/dist/web-session.d.ts +70 -10
- package/dist/web-session.js +137 -22
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +49 -2
- package/dist/web-settings-patch.js +145 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +94 -0
- package/dist/web-settings-tools.js +301 -0
- package/dist/web-settings-tools.js.map +1 -0
- 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-terminal-http.js +15 -2
- package/dist/web-terminal-http.js.map +1 -1
- package/dist/web-theme-store.d.ts +39 -0
- package/dist/web-theme-store.js +122 -11
- package/dist/web-theme-store.js.map +1 -1
- package/dist/web-theme.d.ts +31 -0
- package/dist/web-theme.js +99 -2
- package/dist/web-theme.js.map +1 -1
- package/dist/web-upload.d.ts +13 -0
- package/dist/web-upload.js +39 -3
- package/dist/web-upload.js.map +1 -1
- package/dist/windows-shortcuts.d.ts +78 -0
- package/dist/windows-shortcuts.js +203 -0
- package/dist/windows-shortcuts.js.map +1 -0
- package/dist/workflow-templates/default.md +4 -1
- package/dist/yaml-shared-nodes.d.ts +25 -0
- package/dist/yaml-shared-nodes.js +185 -0
- package/dist/yaml-shared-nodes.js.map +1 -0
- package/launcher/agend-install.cjs +553 -0
- package/launcher/install-admission.cjs +4 -39
- package/launcher/postinstall.cjs +14 -12
- package/package.json +4 -2
- package/scripts/preinstall-guard.cjs +2 -5
- package/templates/windows-shortcuts.ps1 +181 -0
- package/launcher/old-updater-note.cjs +0 -48
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/** #1629 B2: one host-owned Canvas Worker pool. Product adapters are deliberately separate. */
|
|
2
|
-
import { allocateEffectFrames, effectEvent } from "./effect-policy.js";
|
|
3
|
-
import {
|
|
4
|
-
import { createEffectFrame } from "./effect-frame.js";
|
|
2
|
+
import { allocateEffectFrames, effectEvent, effectPlaybackReason } from "./effect-policy.js";
|
|
3
|
+
import { createOpaqueEffectFrame } from "./effect-frame.js";
|
|
5
4
|
import { createEffectGeometry, hostEffectRect } from "./effect-geometry.js";
|
|
6
|
-
import { effectStockSnapshot, effectStockAllows } from "./effect-stock-snapshot.js";
|
|
5
|
+
import { effectStockSnapshot, effectStockAllows, effectStockRefusal } from "./effect-stock-snapshot.js";
|
|
7
6
|
import { effectTrialStage, effectTrialStageIdentity, watchEffectTrialStage } from "./effect-trial-stage.js";
|
|
8
7
|
import { EffectBudget } from "./effect-profiler.js";
|
|
9
8
|
|
|
10
9
|
const registries = new WeakMap();
|
|
11
10
|
const plain = o => !!o && (Object.getPrototypeOf(o) === Object.prototype || Object.getPrototypeOf(o) === null);
|
|
12
11
|
const finite = v => typeof v === "number" && Number.isFinite(v);
|
|
13
|
-
const FLAGS = ["safe", "publicLink", "reducedMotion", "
|
|
12
|
+
const FLAGS = ["safe", "publicLink", "reducedMotion", "hidden", "enabled", "show", "transportReady", "constrained", "modal"];
|
|
14
13
|
const TYPES = ["state", "reply", "theme"];
|
|
15
14
|
function unsafeSnapshotDescriptor(d) {
|
|
16
15
|
if (!plain(d) || !plain(d.params ?? {})) return null;
|
|
@@ -41,9 +40,9 @@ function snapshotDescriptor(d) { try { return unsafeSnapshotDescriptor(d); } cat
|
|
|
41
40
|
*/
|
|
42
41
|
export function createEffectRegistry({ window: host, origin, boot, load, safety, stockSnapshot, onChange = () => {}, onProfile = () => {}, onMount = () => {}, onRetire = () => {}, clock = () => host.performance.now() } = {}) {
|
|
43
42
|
try { if (!host?.document || !host.document.body || registries.has(host) || typeof load !== "function" || typeof stockSnapshot !== "function" || typeof onChange !== "function" || typeof onProfile !== "function" || typeof onMount !== "function" || typeof onRetire !== "function" || typeof clock !== "function" || !safety || ["allowed", "begin", "finish", "pause", "resume"].some(k => typeof safety[k] !== "function") || ["requestAnimationFrame", "cancelAnimationFrame", "setTimeout", "clearTimeout", "MutationObserver", "ResizeObserver", "AbortController"].some(k => typeof host[k] !== "function")) return { ok: false, reason: "registry_unsupported" }; } catch { return { ok: false, reason: "registry_unsupported" }; }
|
|
44
|
-
let dead = false, blocked = null, revision = 0, last = null, lastView = null, frameSerial = 0, context = null, descriptors = [],
|
|
43
|
+
let dead = false, blocked = null, revision = 0, last = null, lastView = null, frameSerial = 0, context = null, descriptors = [], raf = null, timer = null;
|
|
45
44
|
const slots = new Map(), loads = new Set(), paused = new Map(), offs = [], observed = new Set(), failures = new Map(), results = new Map();
|
|
46
|
-
let readingStock = false;
|
|
45
|
+
let readingStock = false, stockFailure = "stock_evidence_invalid", warned = null;
|
|
47
46
|
let root, geometry, observer, resize, longTasks = null, longTasksSupported = false;
|
|
48
47
|
const time = () => {
|
|
49
48
|
let n; try { n = clock(); } catch { return null; }
|
|
@@ -65,14 +64,18 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
65
64
|
finally { readingStages.delete(d.trialStage); }
|
|
66
65
|
return !dead && !blocked && revision === before && stage?.root === d.element ? stage : null;
|
|
67
66
|
};
|
|
68
|
-
const permits = (d, proof) => d.trialStage ? !!localStage(d, proof) : effectStockAllows(proof, d);
|
|
67
|
+
const permits = (d, proof) => eligible(d) && (d.trialStage ? !!localStage(d, proof) : effectStockAllows(proof, d));
|
|
69
68
|
const coverage = (d = null) => {
|
|
70
69
|
if (dead || blocked || readingStock) return null;
|
|
71
70
|
const before = revision; let proof = null; readingStock = true;
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
let failure = "stock_provider_failed";
|
|
72
|
+
try { const raw = stockSnapshot(Object.freeze({ frameRoot: root })); proof = effectStockSnapshot(raw); failure = proof ? null : effectStockRefusal(raw); }
|
|
73
|
+
catch { /* unavailable stays denied, with a local diagnostic */ }
|
|
74
74
|
finally { readingStock = false; }
|
|
75
75
|
if (dead || blocked || before !== revision) return null;
|
|
76
|
+
stockFailure = failure;
|
|
77
|
+
if (failure !== warned) { warned = failure; if (failure) { try { host.console?.warn("[AgEnD effects] Playback blocked:", failure); } catch { /* display only */ } } }
|
|
78
|
+
if (dead || blocked || before !== revision) return null;
|
|
76
79
|
return d === null || permits(d, proof) ? proof : null;
|
|
77
80
|
};
|
|
78
81
|
const position = (d, proof) => d.trialStage ? localStage(d, proof)?.rect ?? null : hostEffectRect(d.element);
|
|
@@ -91,6 +94,21 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
91
94
|
const current = s => !dead && !blocked && slots.get(s.d.key) === s && s.live;
|
|
92
95
|
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
96
|
const receipt = (fn, ...args) => { try { return Reflect.apply(fn, safety, args); } catch { return null; } };
|
|
97
|
+
// #2055: the history's own read names a denial; any other answer stays unknown (and denied).
|
|
98
|
+
const SAFETY_REASON = Object.freeze({ __proto__: null, off: "safety_off", paused: "paused", interrupted: "interrupted" });
|
|
99
|
+
// Display only: the sticky history state per descriptor, which outranks a waiting reason (a queue, a dialog, typing)
|
|
100
|
+
// because it is what Resume must answer. Admission, caps, latches and safety policy never read it.
|
|
101
|
+
const named = new Map();
|
|
102
|
+
// The read can re-enter (an update from a callback): only a pass still current, for the same device, may write.
|
|
103
|
+
const nameSafety = (d, dev = device()) => {
|
|
104
|
+
const proposed = revision;
|
|
105
|
+
const reason = d.trialStage ? null : SAFETY_REASON[receipt(safety.status, d.id, dev)?.state];
|
|
106
|
+
if (dead || proposed !== revision || dev !== device()) return false;
|
|
107
|
+
if (reason) named.set(d.key, { identity: signature(d), reason }); else named.delete(d.key);
|
|
108
|
+
return true;
|
|
109
|
+
};
|
|
110
|
+
// Display only: the closed global gate a row is waiting on, when the host knows it (else the caller's unknown).
|
|
111
|
+
const gateReason = () => effectPlaybackReason(context);
|
|
94
112
|
const clearMarker = (s, why) => {
|
|
95
113
|
if (!s.token) return true;
|
|
96
114
|
const token = s.token; s.token = null;
|
|
@@ -102,7 +120,9 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
102
120
|
s.live = false;
|
|
103
121
|
if (slots.get(s.d.key) === s) slots.delete(s.d.key);
|
|
104
122
|
if (s.request) { s.request.controller.abort(); if (s.request.timer !== null) host.clearTimeout(s.request.timer); }
|
|
105
|
-
|
|
123
|
+
// A closed/unknown viewer gate revokes paint, not the effect identity. Fresh known gates
|
|
124
|
+
// may admit it again; resource failures and actual safety pauses retain their latches.
|
|
125
|
+
if (!["disposed", "superseded", "hidden", "human_resume", "geometry_changed", "gates_unknown"].includes(why)) failures.set(s.d.key, { identity: signature(s.d), reason: why });
|
|
106
126
|
s.stageOff?.(); s.stageOff = null;
|
|
107
127
|
s.frame?.remove(why); s.geometry?.remove();
|
|
108
128
|
if (s.loadOff) s.loadOff();
|
|
@@ -110,6 +130,7 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
110
130
|
paused.set(s.d.key, signature(s.d));
|
|
111
131
|
if (receipt(safety.pause, { id: s.d.id, device: s.device, reason: why, metrics: s.budget?.snapshot().metrics ?? null }) !== true) blocked = "safety_unknown";
|
|
112
132
|
}
|
|
133
|
+
if (count || why === "safety_revoked") nameSafety(s.d, s.device); // #2055: the third pause, or another tab's, says off now
|
|
113
134
|
clearMarker(s, why);
|
|
114
135
|
if (s.owner) { try { onRetire(s.owner, why); } catch { /* an observation cannot prevent physical cleanup */ } }
|
|
115
136
|
if (blocked) for (const other of [...slots.values()]) retire(other, blocked);
|
|
@@ -120,18 +141,24 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
120
141
|
retire(s, why);
|
|
121
142
|
if (revision !== proposed || dead !== wasDead) return false;
|
|
122
143
|
}
|
|
123
|
-
if (calibration) { calibration.cancel(); calibration = null; }
|
|
124
144
|
return true;
|
|
125
145
|
}
|
|
126
146
|
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(
|
|
128
|
-
|
|
147
|
+
function eligible(d = null) {
|
|
148
|
+
return gatesKnown() && !context.safe && !context.reducedMotion && context.enabled && context.show && context.transportReady
|
|
149
|
+
&& (!d || !context.publicLink || d.region === "chat" && !d.trialStage);
|
|
150
|
+
}
|
|
151
|
+
const globalAllowed = (d = null) => eligible(d) && host.document.visibilityState === "visible";
|
|
129
152
|
const signature = d => d.identity;
|
|
153
|
+
// A frame stopped because its gates closed is recorded as gates_unknown; when the host knows which gate, say it.
|
|
154
|
+
const shown = why => (why === "gates_unknown" && !eligible() && gateReason()) || why;
|
|
130
155
|
function view() {
|
|
131
156
|
return descriptors.map(d => {
|
|
132
|
-
const r = results.get(d.key) ?? { verdict: "off", reason: blocked ?? "
|
|
133
|
-
|
|
134
|
-
|
|
157
|
+
const r = results.get(d.key) ?? { verdict: "off", reason: blocked ?? (eligible() ? stockFailure : gateReason()) ?? "runtime_unavailable", queuePos: null }, s = slots.get(d.key);
|
|
158
|
+
// #2055 one display precedence: a global latch, then the sticky safety history, then this page's own pause/failure.
|
|
159
|
+
const n = named.get(d.key), sticky = n && n.identity === signature(d) ? n.reason : null;
|
|
160
|
+
return { key: d.key, id: d.id, ...r, ...(sticky && r.verdict === "queued" ? { verdict: "off", queuePos: null } : {}), phase: s?.frame ? s.ready ? "running" : "starting" : s ? "loading" : null,
|
|
161
|
+
quality: s?.budget?.snapshot().quality ?? null, reason: blocked ?? sticky ?? ((paused.get(d.key) === signature(d)) ? "paused" : failures.get(d.key)?.identity === signature(d) ? shown(failures.get(d.key).reason) : s && context?.hidden ? "hidden" : r.reason) };
|
|
135
162
|
});
|
|
136
163
|
}
|
|
137
164
|
function schedule() {
|
|
@@ -150,7 +177,7 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
150
177
|
};
|
|
151
178
|
function observe() {
|
|
152
179
|
const nodes = host.document.querySelectorAll("[data-trust]");
|
|
153
|
-
if (nodes.length >
|
|
180
|
+
if (nodes.length > 4096) throw Error("trust coverage unavailable");
|
|
154
181
|
const wanted = new Set([host.document.documentElement, ...nodes]);
|
|
155
182
|
for (const d of descriptors) if (d.element?.ownerDocument === host.document && d.element.isConnected === true) wanted.add(d.element);
|
|
156
183
|
for (const n of observed) if (!wanted.has(n)) { resize.unobserve(n); observed.delete(n); }
|
|
@@ -162,10 +189,19 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
162
189
|
const proposal = revision;
|
|
163
190
|
if (time() === null) blocked = "clock_unavailable";
|
|
164
191
|
const hidden = context?.hidden === true || host.document.visibilityState !== "visible";
|
|
192
|
+
// #2188: nothing to place, nothing to prove — the stock walk (thousands of computed styles) is not run for an empty
|
|
193
|
+
// list; a frame still held is retired as superseded, exactly as an allocation of nothing would.
|
|
194
|
+
if (!blocked && descriptors.length === 0) {
|
|
195
|
+
for (const s of [...slots.values()]) { retire(s, "superseded"); if (dead || proposal !== revision) return; }
|
|
196
|
+
results.clear(); tell(); return;
|
|
197
|
+
}
|
|
165
198
|
const stock = eligible() ? coverage() : null;
|
|
199
|
+
if (dead || proposal !== revision) return;
|
|
166
200
|
if (blocked || !eligible() || !stock) {
|
|
167
201
|
if (!stopAll(blocked ?? "gates_unknown")) return;
|
|
168
|
-
results.clear();
|
|
202
|
+
results.clear();
|
|
203
|
+
if (!blocked) for (const d of descriptors) if (!nameSafety(d) || dead || proposal !== revision) return;
|
|
204
|
+
tell(); return;
|
|
169
205
|
}
|
|
170
206
|
// Hidden frames already owned may survive for <=10 s, but no new frame or load is admitted while hidden.
|
|
171
207
|
const ctx = { ...context, hidden: false };
|
|
@@ -176,6 +212,7 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
176
212
|
if (dead || proposal !== revision) return;
|
|
177
213
|
ds.push({ ...d, paused: !allowed || d.paused === true || paused.get(d.key) === signature(d) || failures.get(d.key)?.identity === signature(d) });
|
|
178
214
|
}
|
|
215
|
+
for (const d of descriptors) if (!nameSafety(d) || dead || proposal !== revision) return;
|
|
179
216
|
const allocation = allocateEffectFrames(ds, ctx); results.clear();
|
|
180
217
|
for (const r of allocation) {
|
|
181
218
|
const d = descriptors.find(d => d.key === r.key);
|
|
@@ -193,10 +230,9 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
193
230
|
if (!chosen.has(s.d.key) || !d || signature(d) !== signature(s.d) || d.element !== s.d.element || s.device !== device()) retire(s, "superseded");
|
|
194
231
|
if (dead || proposal !== revision) return;
|
|
195
232
|
}
|
|
196
|
-
if (chosen.size === 0) {
|
|
233
|
+
if (chosen.size === 0) { tell(); return; }
|
|
197
234
|
if (hidden) {
|
|
198
235
|
hideGeometry();
|
|
199
|
-
if (calibration) { calibration.cancel(); calibration = null; }
|
|
200
236
|
for (const s of [...slots.values()]) {
|
|
201
237
|
if (!s.frame) retire(s, "hidden");
|
|
202
238
|
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"); }
|
|
@@ -209,19 +245,9 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
209
245
|
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
246
|
if (dead || proposal !== revision) return;
|
|
211
247
|
}
|
|
212
|
-
try { observe(); } catch {
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
});
|
|
248
|
+
try { observe(); } catch {
|
|
249
|
+
if (dead || proposal !== revision || !stopAll("trust_geometry_unknown")) return;
|
|
250
|
+
for (const d of descriptors) results.set(d.key, { verdict: "off", reason: "trust_geometry_unknown", queuePos: null });
|
|
225
251
|
tell(); return;
|
|
226
252
|
}
|
|
227
253
|
const max = context.constrained ? 1 : 3;
|
|
@@ -230,8 +256,14 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
230
256
|
if (slots.size >= max || loads.size >= max) break;
|
|
231
257
|
const permitted = receipt(safety.allowed, d.id, device());
|
|
232
258
|
if (proposal !== revision) return;
|
|
233
|
-
if (permitted !== true) {
|
|
234
|
-
|
|
259
|
+
if (permitted !== true) {
|
|
260
|
+
// #2055: say which denial it is. Only the safety history's own read names it; anything else stays unknown (still denied).
|
|
261
|
+
const st = receipt(safety.status, d.id, device());
|
|
262
|
+
if (proposal !== revision) return;
|
|
263
|
+
const why = SAFETY_REASON[st?.state] ?? "safety_unknown";
|
|
264
|
+
results.set(d.key, { verdict: "off", reason: why, queuePos: null }); continue;
|
|
265
|
+
}
|
|
266
|
+
if (slots.has(d.key) || slots.size >= max || loads.size >= max || !globalAllowed(d) || context.hidden || !coverage(d) || proposal !== revision || !descriptors.some(x => x.key === d.key && signature(x) === signature(d) && x.element === d.element)) break;
|
|
235
267
|
const rect = position(d, coverage(d));
|
|
236
268
|
if (dead || proposal !== revision) return;
|
|
237
269
|
if (!rect || d.element.ownerDocument !== host.document) { results.set(d.key, { verdict: "off", reason: "geometry_unknown", queuePos: null }); continue; }
|
|
@@ -254,7 +286,7 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
254
286
|
const acceptCompletion = () => {
|
|
255
287
|
if (!current(s)) { clearMarker(s, "superseded"); return false; }
|
|
256
288
|
if (!withinDeadline()) return false;
|
|
257
|
-
if (request.controller.signal.aborted || !globalAllowed() || context.hidden || !coverage(d)) {
|
|
289
|
+
if (request.controller.signal.aborted || !globalAllowed(d) || context.hidden || !coverage(d)) {
|
|
258
290
|
if (current(s)) retire(s, "admission_revoked"); else clearMarker(s, "superseded");
|
|
259
291
|
return false;
|
|
260
292
|
}
|
|
@@ -287,10 +319,10 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
287
319
|
if (d.trialStage && !local || !current(s)) { if (current(s)) retire(s, "admission_revoked"); return; }
|
|
288
320
|
if (local) fresh = local.rect;
|
|
289
321
|
s.rect = fresh;
|
|
290
|
-
s.budget = new EffectBudget({ device: s.device,
|
|
291
|
-
const frame =
|
|
322
|
+
s.budget = new EffectBudget({ device: s.device, clock: nativeClock, longTasksSupported });
|
|
323
|
+
const frame = createOpaqueEffectFrame({ window: host, root: local?.root ?? root, origin, boot, clock: nativeClock,
|
|
292
324
|
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(); },
|
|
325
|
+
onReady() { if (!current(s)) return; if (!globalAllowed(d) || 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
326
|
onRemove(why) { if (current(s)) { retire(s, why); tell(); } },
|
|
295
327
|
});
|
|
296
328
|
s.frame = frame;
|
|
@@ -316,7 +348,7 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
316
348
|
schedule(); tell();
|
|
317
349
|
}
|
|
318
350
|
function publishEnv(s, proof = coverage(s.d)) {
|
|
319
|
-
if (!s.ready || !current(s) || context.hidden || !globalAllowed() || !permits(s.d, proof)) return;
|
|
351
|
+
if (!s.ready || !current(s) || context.hidden || !globalAllowed(s.d) || !permits(s.d, proof)) return;
|
|
320
352
|
const e = effectEvent("env", { width: s.rect.width, height: s.rect.height, dpr: dpr(s.device), quality: s.budget.snapshot().quality }, null, time());
|
|
321
353
|
if (e) s.frame.send(e);
|
|
322
354
|
}
|
|
@@ -339,12 +371,17 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
339
371
|
if (changed) publishEnv(s, paint);
|
|
340
372
|
if (s.ready) s.budget.frame();
|
|
341
373
|
if (s.pointer) {
|
|
342
|
-
const packet = s.pointer;
|
|
374
|
+
const packet = s.pointer;
|
|
343
375
|
const n = time(), b = s.budget.snapshot();
|
|
344
|
-
if (n
|
|
376
|
+
if (n === null || n - packet.at > 100 || !permits(s.d, paint) || !pointerGate(paint) || !current(s) || !b.forward) {
|
|
377
|
+
if (s.pointer === packet) s.pointer = null;
|
|
378
|
+
} else if (s.lastPointer === null || n - s.lastPointer >= 1000 / b.pointerHz) {
|
|
379
|
+
if (s.pointer === packet) s.pointer = null;
|
|
345
380
|
const event = effectEvent("pointer", packet.fields, s.d.instance, packet.at);
|
|
346
381
|
if (event && s.frame.send(event)) s.lastPointer = n;
|
|
347
382
|
}
|
|
383
|
+
// Keep the latest fresh sample until the next eligible frame. An early rAF must
|
|
384
|
+
// not consume a click just because the preceding move used this rate interval.
|
|
348
385
|
}
|
|
349
386
|
}
|
|
350
387
|
if (dead || proposal !== revision) return;
|
|
@@ -401,11 +438,16 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
401
438
|
if (!globalAllowed() || context.hidden || context.modal || !proof || proof.front !== true) return false;
|
|
402
439
|
try {
|
|
403
440
|
const focused = host.document.activeElement;
|
|
404
|
-
|
|
441
|
+
// Native clicks on ordinary stock content focus its tabindex=-1 main ancestor.
|
|
442
|
+
// Recognize only that unique host root; unknown/editor focus remains a refusal.
|
|
443
|
+
const mains = focused?.tagName === "MAIN" ? host.document.querySelectorAll("#app > .shell > main#main.main[tabindex='-1']") : [];
|
|
444
|
+
const stockMain = focused?.isConnected === true && focused.ownerDocument === host.document && mains.length === 1 && mains[0] === focused;
|
|
445
|
+
return host.document.designMode !== "on" && !!focused && (["BODY", "BUTTON", "A"].includes(focused.tagName) || stockMain) && focused.isContentEditable === false && typeof focused.matches === "function" && !focused.matches("input,textarea,select,[contenteditable]:not([contenteditable='false'])");
|
|
405
446
|
} catch { return false; }
|
|
406
447
|
}
|
|
407
448
|
function pointer(event) {
|
|
408
|
-
|
|
449
|
+
// #2188: no frame to forward to — no gate to read (each read walks the page's computed styles, per pointer event).
|
|
450
|
+
if (dead || blocked || slots.size === 0 || !pointerGate() || event.isTrusted !== true) return;
|
|
409
451
|
const kinds = { pointermove: "move", pointerdown: "down", pointerup: "up", click: "click", wheel: "wheel" }, kind = kinds[event.type];
|
|
410
452
|
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
453
|
try { const target = host.document.elementFromPoint(event.clientX, event.clientY); if (!target || typeof target.closest !== "function" || target.closest("[data-trust]")) return; } catch { return; }
|
|
@@ -416,7 +458,11 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
416
458
|
const fields = { kind, x: event.clientX - r.x, y: event.clientY - r.y, buttons: event.buttons };
|
|
417
459
|
if (fields.x < 0 || fields.y < 0 || fields.x > r.width || fields.y > r.height) continue;
|
|
418
460
|
if (kind === "wheel") { fields.dx = event.deltaX; fields.dy = event.deltaY; }
|
|
419
|
-
if (effectEvent("pointer", fields, s.d.instance, at))
|
|
461
|
+
if (effectEvent("pointer", fields, s.d.instance, at)) {
|
|
462
|
+
// One slot, with discrete input ahead of motion. A later move must not erase
|
|
463
|
+
// a waiting click; down/up/click may still coalesce to the latest discrete event.
|
|
464
|
+
if (kind !== "move" || !s.pointer || s.pointer.fields.kind === "move" || at - s.pointer.at > 100) s.pointer = { fields, at };
|
|
465
|
+
}
|
|
420
466
|
}
|
|
421
467
|
schedule();
|
|
422
468
|
}
|
|
@@ -464,15 +510,16 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
464
510
|
revalidateSafety,
|
|
465
511
|
/** Called only by the host's explicit human Resume UI. A descriptor update never clears this latch. */
|
|
466
512
|
resume(key) {
|
|
467
|
-
if (dead || reentrantStock() || blocked
|
|
513
|
+
if (dead || reentrantStock() || blocked || typeof key !== "string") return false;
|
|
468
514
|
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
515
|
revision++;
|
|
470
516
|
if (!stopAll("human_resume")) return false;
|
|
471
|
-
if (blocked
|
|
517
|
+
if (blocked) return false; paused.delete(key); failures.delete(key); reconcile(); return true;
|
|
472
518
|
},
|
|
473
519
|
/** Host-only content-free signal API. Raw pointer publishing is refused; native pointer metadata is coalesced here. */
|
|
474
520
|
publish(type, fields, instance = null) {
|
|
475
|
-
|
|
521
|
+
// #2188: no frame to send to — nothing to prove (the stock walk ran twice on every page change).
|
|
522
|
+
if (dead || blocked || slots.size === 0 || !globalAllowed() || context.hidden || !coverage() || !TYPES.includes(type)) return 0;
|
|
476
523
|
const ts = time(); if (ts === null) { blocked = "clock_unavailable"; stopAll(blocked); tell(); return 0; }
|
|
477
524
|
let sent = 0; const proposal = revision;
|
|
478
525
|
for (const s of [...slots.values()]) {
|
|
@@ -484,7 +531,7 @@ export function createEffectRegistry({ window: host, origin, boot, load, safety,
|
|
|
484
531
|
return sent;
|
|
485
532
|
},
|
|
486
533
|
dispose() {
|
|
487
|
-
if (dead) return; dead = true; revision++;
|
|
534
|
+
if (dead) return; dead = true; revision++; stopAll("disposed");
|
|
488
535
|
if (raf !== null) host.cancelAnimationFrame(raf); if (timer !== null) host.clearTimeout(timer);
|
|
489
536
|
observer.disconnect(); resize.disconnect(); longTasks?.disconnect(); for (const off of offs) off();
|
|
490
537
|
geometry.dispose(); root.remove(); observed.clear(); if (loads.size === 0 && registries.get(host) === api) registries.delete(host);
|
|
@@ -32,3 +32,12 @@ export function effectStockAllows(snapshot, { layer, by } = {}) {
|
|
|
32
32
|
const proof = effectStockSnapshot(snapshot);
|
|
33
33
|
return !!proof && (layer === "behind" || layer === "front" && proof.front && (by === "human" || proof.agentFront));
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
/** Display only. Refused provider metadata never becomes paint evidence or authority. */
|
|
37
|
+
export function effectStockRefusal(value) {
|
|
38
|
+
try {
|
|
39
|
+
if (!plain(value)) return "stock_evidence_invalid";
|
|
40
|
+
const d = Object.getOwnPropertyDescriptor(value, "reason");
|
|
41
|
+
return d && Object.hasOwn(d, "value") && typeof d.value === "string" && /^[a-z][a-z0-9_]{0,79}$/.test(d.value) ? d.value : "stock_evidence_invalid";
|
|
42
|
+
} catch { return "stock_evidence_invalid"; }
|
|
43
|
+
}
|
|
@@ -11,7 +11,7 @@ const SPECS = [
|
|
|
11
11
|
["confirmation", ".shell > .pending-stack, .shell .p-settings > .panel-body > .col > .pending-stack.inline"], ["preview", ".shell .chat-split > .pv-panel, .shell .chat-split > .pv-divider"],
|
|
12
12
|
["preview-menu", ".shell .thread details.pv-menu"], ["palette", ".shell .dock .cmd-palette"],
|
|
13
13
|
["drop", ".shell .p-chat > .drop-overlay"],
|
|
14
|
-
["thread-control", ".shell .p-chat .jump-latest, .shell .thread .msg-tools, .shell .thread .st-more, .shell .thread .cb-head, .shell .thread .cb-more, .shell .thread .tc-head, .shell .thread .tc-more, .shell .thread .pv-head, .shell .thread .pv-note, .shell .thread .pv-banner, .shell .thread .effect-trial-offer, .shell .thread .click-chip"],
|
|
14
|
+
["thread-control", ".shell .chat-main > .amb-note, .shell .p-chat .jump-latest, .shell .thread .msg-tools, .shell .thread .st-more, .shell .thread .cb-head, .shell .thread .cb-more, .shell .thread .tc-head, .shell .thread .tc-more, .shell .thread .pv-head, .shell .thread .pv-note, .shell .thread .pv-banner, .shell .thread .effect-trial-offer, .shell .thread .click-chip"],
|
|
15
15
|
["link", ".shell .thread .md a, .shell .thread .st-text > a.st-link, .shell .dock .prompts .txt > a.st-link"], ["attachment", ".shell .thread .atts"], ["media", ".shell .thread .att-media"],
|
|
16
16
|
["panel-navigation", ".shell .p-fleet > .seg, .shell .p-settings > .seg"],
|
|
17
17
|
["panel-content", ".shell .p-fleet > .panel-body, .shell .p-needs > .panel-body, .shell .p-settings > .panel-body, .shell .p-log > .panel-body, .shell .p-details > .panel-body, .shell .p-view > .panel-body, .shell .p-view > .v-term, .shell .p-view > .v-id, .shell .p-view > .v-card"],
|
|
@@ -20,7 +20,7 @@ const SPECS = [
|
|
|
20
20
|
];
|
|
21
21
|
export const STOCK_TRUST_INVENTORY = Object.freeze(SPECS.map(([kind, selector]) => Object.freeze({ kind, selector })));
|
|
22
22
|
const STRUCTURAL = ["html", "body", "#app", "#app > .shell", ".shell > .main", ".main > .p-chat", ".p-chat > .chat-split", ".chat-split > .chat-main"];
|
|
23
|
-
const CONTENT = [".main > .conn", ".p-chat > .panel-head", ".p-chat > .chat-card", ".p-chat > .aw-chat_header", ".chat-main > .scroller", ".chat-main > .dock", ".sidebar > .side-head", ".sidebar > .side-nav", ".sidebar > .side-section", ".sidebar > .side-widget", ".sidebar > .side-foot", ".u-rail > .u-rail-head", ".u-rail > .u-rail-body"];
|
|
23
|
+
const CONTENT = [".main > .conn", ".p-chat > .panel-head", ".p-chat > .chat-card", ".p-chat > .aw-chat_header", ".chat-main > .amb-note", ".chat-main > .scroller", ".chat-main > .dock", ".sidebar > .side-head", ".sidebar > .side-nav", ".sidebar > .side-section", ".sidebar > .side-widget", ".sidebar > .side-foot", ".u-rail > .u-rail-head", ".u-rail > .u-rail-body"];
|
|
24
24
|
// Closed producer/topology inventory. Bare Outlet loading/error panels never become an effect surface.
|
|
25
25
|
const PANELS = Object.freeze({
|
|
26
26
|
fleet: { required: [".panel-head", ".seg", ".panel-body"], optional: [] },
|
|
@@ -95,14 +95,58 @@ function outset(style) {
|
|
|
95
95
|
}
|
|
96
96
|
return pad <= 256 ? Math.ceil(pad) : null;
|
|
97
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* #2086: the identity card's banner fill (a blurred copy beside a centred banner) — the one filter stock admits. Only
|
|
100
|
+
* this exact value, on exactly `.id-banner-box > img.id-banner-fill`, absolutely positioned in that box (so the box is
|
|
101
|
+
* its containing block — #2089 review: a fixed fill is the viewport's, and no box clips it), and the box positioned and
|
|
102
|
+
* clipping on both axes; its paint is then that box's rectangle (the blur and its scale never leave it). The box must
|
|
103
|
+
* also be a real block box that the browser reports as the fill's offset parent (#2089 review r3: `display: contents`
|
|
104
|
+
* keeps the computed position and overflow but generates no box, so an outer ancestor would place the fill, and an inline
|
|
105
|
+
* box clips differently). Anything else with a filter refuses.
|
|
106
|
+
*/
|
|
107
|
+
export const STOCK_BANNER_FILL_FILTER = "blur(24px) saturate(0.75) brightness(0.7)";
|
|
108
|
+
function stockBannerFill(host, el) {
|
|
109
|
+
const box = el.parentElement;
|
|
110
|
+
if (typeof el.matches !== "function" || !el.matches(".id-banner-box > img.id-banner-fill") || !box) return null;
|
|
111
|
+
const s = host.getComputedStyle(el), b = host.getComputedStyle(box);
|
|
112
|
+
if (s.filter !== STOCK_BANNER_FILL_FILTER || !none(s.backdropFilter) || !none(b.filter) || !none(b.backdropFilter)) return null;
|
|
113
|
+
if (!["hidden", "clip"].includes(b.overflowX) || !["hidden", "clip"].includes(b.overflowY)) return null;
|
|
114
|
+
if (s.position !== "absolute" || !["relative", "absolute"].includes(b.position)) return null;
|
|
115
|
+
if (b.display !== "block" || el.offsetParent !== box) return null;
|
|
116
|
+
return rect(box);
|
|
117
|
+
}
|
|
118
|
+
function zeroClipMargin(host, style) {
|
|
119
|
+
const margin = style.overflowClipMargin ?? style.getPropertyValue?.("overflow-clip-margin");
|
|
120
|
+
// WebKit versions without this property still implement paint containment. An absent
|
|
121
|
+
// computed value is usable only when the engine explicitly reports it unsupported;
|
|
122
|
+
// unknown capability or a supported but unreadable/expanded margin cannot prove a box.
|
|
123
|
+
return margin === "0px" || [undefined, ""].includes(margin)
|
|
124
|
+
&& host.CSS?.supports?.("overflow-clip-margin", "1px") === false;
|
|
125
|
+
}
|
|
98
126
|
function protectedPaint(host, root, budget) {
|
|
127
|
+
// These two stock toolbar boxes physically clip ALL descendants, including fixed-position
|
|
128
|
+
// children. Their entire box is a hole; descendant ink cannot escape it. Inline, fragmented,
|
|
129
|
+
// expanded-clip or CSS-overridden boxes take the ordinary bounded walk instead.
|
|
130
|
+
const s = host.getComputedStyle(root);
|
|
131
|
+
if (root.matches?.(".shell .thread .msg-tools, .shell .thread .codeblock > .cb-head") && s.contain === "paint"
|
|
132
|
+
&& s.display === "flex" && s.overflowX === "clip" && s.overflowY === "clip" && zeroClipMargin(host, s)
|
|
133
|
+
&& none(s.filter) && none(s.backdropFilter) && s.borderImageSource === "none" && [undefined, "", "visible"].includes(s.contentVisibility) && root.getClientRects().length === 1) {
|
|
134
|
+
if (++budget.n > 4096) { budget.exceeded = true; return null; }
|
|
135
|
+
const r = rect(root), pad = outset(s);
|
|
136
|
+
// Containment clips descendants, not the root's own ink. Do not infer a world-space
|
|
137
|
+
// outset from local CSS lengths under a potentially transformed content ancestor.
|
|
138
|
+
if (!r || pad !== 0) return null;
|
|
139
|
+
return r;
|
|
140
|
+
}
|
|
99
141
|
const nodes = [root, ...root.querySelectorAll("*")]; budget.n += nodes.length;
|
|
100
|
-
if (budget.n > 4096) return null;
|
|
142
|
+
if (budget.n > 4096) { budget.exceeded = true; return null; }
|
|
101
143
|
let union = null;
|
|
102
144
|
for (const el of nodes) {
|
|
103
145
|
if (!visible(host, el)) continue;
|
|
104
|
-
const style = host.getComputedStyle(el),
|
|
105
|
-
if (
|
|
146
|
+
const style = host.getComputedStyle(el), pad = outset(style);
|
|
147
|
+
if (style.borderImageSource !== undefined && style.borderImageSource !== "none" || ![undefined, "", "visible"].includes(style.contentVisibility)) return null;
|
|
148
|
+
const r = none(style.filter) ? rect(el) : stockBannerFill(host, el);
|
|
149
|
+
if (!r || pad === null || !none(style.backdropFilter)) return null;
|
|
106
150
|
const a = { x: r.x - pad, y: r.y - pad, width: r.width + pad * 2, height: r.height + pad * 2 };
|
|
107
151
|
if (!union) union = a;
|
|
108
152
|
else { const x = Math.min(union.x, a.x), y = Math.min(union.y, a.y); union = { x, y, width: Math.max(union.x + union.width, a.x + a.width) - x, height: Math.max(union.y + union.height, a.y + a.height) - y }; }
|
|
@@ -144,22 +188,30 @@ export function stockEffectTrust(host, { frameRoot = null, ownerCss = "unknown"
|
|
|
144
188
|
if (s.position !== "relative" || s.zIndex !== "1" || !neutral(s)) return fail("stock_order_unknown");
|
|
145
189
|
}
|
|
146
190
|
const marked = [...doc.querySelectorAll("[data-trust]")], expected = new Set(), rects = [], budget = { n: 0 };
|
|
147
|
-
if (marked.length >
|
|
191
|
+
if (marked.length > 4096) return fail("stock_marker_limit");
|
|
148
192
|
for (const { kind, selector } of STOCK_TRUST_INVENTORY) for (const el of doc.querySelectorAll(selector)) {
|
|
149
193
|
if (el.ownerDocument !== doc || el.isConnected !== true || el.getAttribute("data-trust") !== kind) return fail("stock_trust_unknown");
|
|
150
194
|
expected.add(el);
|
|
151
195
|
}
|
|
152
196
|
if (marked.some(el => !expected.has(el)) || surface.kind === "chat" && !chat.querySelector('.dock[data-trust="composer"]') || !surface.panel.querySelector('.panel-head[data-trust="header"]')) return fail("stock_trust_unknown");
|
|
153
197
|
for (const el of marked) {
|
|
154
|
-
const bounds = protectedPaint(host, el, budget); if (!bounds) return fail("stock_paint_unknown");
|
|
155
|
-
|
|
198
|
+
const bounds = protectedPaint(host, el, budget); if (!bounds) return fail(budget.exceeded ? "stock_paint_limit" : "stock_paint_unknown");
|
|
199
|
+
// Off-screen history remains inventoried and paint-checked; it need not consume a
|
|
200
|
+
// viewport hole. Include the clip algorithm's extra 8px protection margin.
|
|
201
|
+
if (bounds.width && bounds.height && (!finite(host.innerHeight) || bounds.x + bounds.width + 8 >= 0 && bounds.y + bounds.height + 8 >= 0 && bounds.x - 8 <= host.innerWidth && bounds.y - 8 <= host.innerHeight)) rects.push(bounds);
|
|
202
|
+
}
|
|
203
|
+
// Keep the existing 128-hole transport bound. Conservative union may hide extra
|
|
204
|
+
// effect pixels; it can never reveal protected pixels, even for a dense viewport.
|
|
205
|
+
if (rects.length > 128) {
|
|
206
|
+
const rest = rects.splice(127), x = Math.min(...rest.map(r => r.x)), y = Math.min(...rest.map(r => r.y));
|
|
207
|
+
rects.push({ x, y, width: Math.max(...rest.map(r => r.x + r.width)) - x, height: Math.max(...rest.map(r => r.y + r.height)) - y });
|
|
156
208
|
}
|
|
157
209
|
if (doc.querySelector(".agend-session-ended")) return fail("session_ended");
|
|
158
210
|
let barrier = [...doc.querySelectorAll(BARRIERS)].some(el => visible(host, el));
|
|
159
211
|
if (host.innerWidth < 900 && [...doc.querySelectorAll(".pv-panel")].some(el => visible(host, el))) barrier = true;
|
|
160
|
-
const active = doc.activeElement;
|
|
161
212
|
if (doc.fullscreenElement || doc.pictureInPictureElement) barrier = true;
|
|
162
|
-
|
|
213
|
+
// Focus alone does not change protected paint bounds. Composer/controls stay clipped; editable focus
|
|
214
|
+
// separately suppresses pointer delivery in the registry, and keyboard events never enter a Worker.
|
|
163
215
|
return { ok: true, rects, front: !barrier, reason: barrier ? "stock_overlay" : "stock", agentFront: !barrier && ownerCss === "off", agentReason: barrier ? "stock_overlay" : ownerCss === "off" ? "stock" : "owner_css", settingsHref: "/settings/appearance" };
|
|
164
216
|
} catch { return fail("stock_trust_unknown"); }
|
|
165
217
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** #2039: fixed host-only closed shadow shell. Owner CSS has no exported parts or slots into it. */
|
|
2
|
+
const roots = new WeakMap();
|
|
3
|
+
const clear = root => { while (root.firstChild) root.removeChild(root.firstChild); };
|
|
4
|
+
function sheetOf(host, record) {
|
|
5
|
+
try {
|
|
6
|
+
const link = record.link, sheet = link?.sheet;
|
|
7
|
+
return record.ready && !record.dead && roots.get(record.panel)?.current === record && record.root.mode === "closed" && record.root.host === record.panel
|
|
8
|
+
&& link.getRootNode() === record.root && link.isConnected && link.disabled === false && sheet?.ownerNode === link && sheet.disabled === false
|
|
9
|
+
&& sheet.href === new URL("/assets/effect-trial.css", host.location.origin).href && typeof sheet.insertRule === "function" && typeof sheet.deleteRule === "function" && sheet.cssRules ? sheet : null;
|
|
10
|
+
} catch { return null; }
|
|
11
|
+
}
|
|
12
|
+
/** Reflect only a shell issued here, after its fixed same-origin stylesheet loaded. Never a serialized capability. */
|
|
13
|
+
export function effectTrialShadow(host, panel) {
|
|
14
|
+
const record = roots.get(panel)?.current;
|
|
15
|
+
return record && sheetOf(host, record) === record.proof?.sheet ? record.proof : null;
|
|
16
|
+
}
|
|
17
|
+
export function createEffectTrialShadow({ window: host, panel, title, labels, onStop, onClose, onReady, onError } = {}) {
|
|
18
|
+
if (!host?.document || panel?.ownerDocument !== host.document || typeof panel.attachShadow !== "function" || typeof onReady !== "function" || typeof onError !== "function") return null;
|
|
19
|
+
let slot = roots.get(panel), cleanup = null;
|
|
20
|
+
const clock = () => (host.performance ?? globalThis.performance).now(), later = host.setTimeout?.bind(host) ?? globalThis.setTimeout, cancel = host.clearTimeout?.bind(host) ?? globalThis.clearTimeout;
|
|
21
|
+
try {
|
|
22
|
+
if (slot?.current && !slot.current.dead) return null;
|
|
23
|
+
if (!slot) { slot = { root: panel.attachShadow({ mode: "closed" }), current: null }; roots.set(panel, slot); }
|
|
24
|
+
const root = slot.root; clear(root);
|
|
25
|
+
const doc = host.document, element = (tag, cls) => { const el = doc.createElement(tag); el.className = cls; return el; };
|
|
26
|
+
const link = element("link", "effect-trial-style"); link.setAttribute("rel", "stylesheet"); link.setAttribute("href", "/assets/effect-trial.css");
|
|
27
|
+
const head = element("header", "effect-trial-head"), label = element("strong", "effect-trial-label"), name = element("span", "effect-trial-title"), close = element("button", "effect-trial-close"), controls = element("div", "effect-trial-controls"), stop = element("button", "effect-trial-stop"), body = element("div", "effect-trial-body"), stage = element("div", "effect-trial-stage"), note = element("p", "effect-trial-note");
|
|
28
|
+
close.setAttribute("type", "button"); stop.setAttribute("type", "button"); stage.setAttribute("aria-hidden", "true");
|
|
29
|
+
head.append(label, name, close); controls.append(stop); body.append(stage);
|
|
30
|
+
const nodes = [head, controls, body, note]; for (const el of nodes) el.setAttribute("hidden", "");
|
|
31
|
+
const began = clock(); if (!Number.isFinite(began) || began < 0) return null;
|
|
32
|
+
let timer = null;
|
|
33
|
+
const record = { panel, root, link, stage, head, controls, body, note, close, stop, ready: false, dead: false, proof: null }; slot.current = record;
|
|
34
|
+
const text = (nextTitle, nextLabels) => {
|
|
35
|
+
if (record.dead || !nextLabels) return;
|
|
36
|
+
label.textContent = nextLabels.label; name.textContent = typeof nextTitle === "string" ? nextTitle : "";
|
|
37
|
+
close.textContent = nextLabels.close; stop.textContent = nextLabels.stop; note.textContent = nextLabels.note;
|
|
38
|
+
panel.setAttribute("data-effect-trial-theme", doc.documentElement.dataset.theme === "dark" ? "dark" : "light");
|
|
39
|
+
};
|
|
40
|
+
const failed = () => { if (!record.dead) { dispose(); try { onError("stage_unavailable"); } catch { /* cleanup already owns failure */ } } };
|
|
41
|
+
const loaded = () => {
|
|
42
|
+
if (record.dead || record.ready || slot.current !== record) return;
|
|
43
|
+
const at = clock(); if (!Number.isFinite(at) || at < began || at - began >= 10000) { failed(); return; }
|
|
44
|
+
record.ready = true; const sheet = sheetOf(host, record);
|
|
45
|
+
if (!sheet) { failed(); return; }
|
|
46
|
+
cancel(timer); timer = null;
|
|
47
|
+
record.proof = Object.freeze({ panel, root, link, sheet, stage, head, controls, body, note, close, stop });
|
|
48
|
+
for (const el of nodes) el.removeAttribute("hidden");
|
|
49
|
+
try { onReady(record.proof); } catch { failed(); }
|
|
50
|
+
};
|
|
51
|
+
const stopClick = () => { if (!record.dead) onStop?.(); }, closeClick = () => { if (!record.dead) onClose?.(); };
|
|
52
|
+
function dispose() {
|
|
53
|
+
if (record.dead) return; record.dead = true; cancel(timer); timer = null;
|
|
54
|
+
link.removeEventListener("load", loaded); link.removeEventListener("error", failed); stop.removeEventListener("click", stopClick); close.removeEventListener("click", closeClick);
|
|
55
|
+
if (slot.current === record) { slot.current = null; clear(root); }
|
|
56
|
+
}
|
|
57
|
+
cleanup = dispose;
|
|
58
|
+
link.addEventListener("load", loaded); link.addEventListener("error", failed); stop.addEventListener("click", stopClick); close.addEventListener("click", closeClick);
|
|
59
|
+
text(title, labels); timer = later(failed, 10000); root.append(link, ...nodes);
|
|
60
|
+
return Object.freeze({ dispose, text });
|
|
61
|
+
} catch { cleanup?.(); return null; }
|
|
62
|
+
}
|
|
@@ -64,7 +64,7 @@ export function createEffectTrialSource({ window: host, current, ownerCurrent, s
|
|
|
64
64
|
const lease = { identity, reply, stage, owner, current: x.current, onStop: x.onStop, startedAt: x.startedAt, until, dead: false, checking: false, pending: new Set(), timer: null, off: null, binding: null };
|
|
65
65
|
lease.binding = Object.freeze({ kind: "trial", key: identity.key, id: identity.id, source: lease, generation: identity.generation });
|
|
66
66
|
active = lease; used.add(stage.receipt);
|
|
67
|
-
lease.off = watchEffectTrialStage(stage.receipt,
|
|
67
|
+
lease.off = watchEffectTrialStage(stage.receipt, reason => stop(lease, typeof reason === "string" ? reason : "stage_ended"));
|
|
68
68
|
if (typeof lease.off !== "function" || constrainEffectTrialStage(stage.receipt, () => checked(lease)) !== true || !checked(lease)) { stop(lease, "stage_unavailable"); return null; }
|
|
69
69
|
try { arm(lease); } catch { stop(lease, "trial_unavailable"); return null; }
|
|
70
70
|
if (!checked(lease)) return null;
|