@songsid/agend 2.3.2 → 2.3.3-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-cli-instructions.md +2 -2
- package/dist/agent-cli.js +13 -112
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +0 -1
- package/dist/agent-endpoint.js +1 -9
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.d.ts +23 -5
- package/dist/agent-whats-new.js +58 -40
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.d.ts +0 -7
- package/dist/auth-api.js +1 -15
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/authority-state.js +1 -1
- package/dist/authority/authority-state.js.map +1 -1
- package/dist/authority/web-authority.d.ts +9 -4
- package/dist/authority/web-authority.js +10 -5
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/antigravity.js +6 -1
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +20 -1
- package/dist/backend/claude-code.js +54 -29
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/claude-transcript-errors.d.ts +18 -0
- package/dist/backend/claude-transcript-errors.js +19 -0
- package/dist/backend/claude-transcript-errors.js.map +1 -0
- package/dist/backend/codex-session-lookup.d.ts +16 -3
- package/dist/backend/codex-session-lookup.js +45 -11
- package/dist/backend/codex-session-lookup.js.map +1 -1
- package/dist/backend/codex.d.ts +16 -0
- package/dist/backend/codex.js +184 -35
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok.js +58 -12
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro-reconcile-store.js +8 -1
- package/dist/backend/kiro-reconcile-store.js.map +1 -1
- package/dist/backend/kiro.d.ts +0 -5
- package/dist/backend/kiro.js +2 -10
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/muse.js +2 -1
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +53 -4
- package/dist/backend/types.js.map +1 -1
- package/dist/bundled-skills.d.ts +4 -6
- package/dist/bundled-skills.js +10 -14
- package/dist/bundled-skills.js.map +1 -1
- package/dist/channel/adapters/discord.js +60 -17
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-server.js +5 -5
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +1 -3
- package/dist/channel/mcp-tools.js +4 -58
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +4 -1
- package/dist/classic-channel-manager.js +21 -7
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +23 -6
- package/dist/cli.js.map +1 -1
- package/dist/config-history.d.ts +50 -0
- package/dist/config-history.js +263 -0
- package/dist/config-history.js.map +1 -0
- package/dist/config-validator.js +10 -8
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.js +11 -4
- package/dist/config.js.map +1 -1
- package/dist/cross-instance-envelope.d.ts +10 -5
- package/dist/cross-instance-envelope.js +20 -17
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/daemon.d.ts +130 -64
- package/dist/daemon.js +603 -428
- package/dist/daemon.js.map +1 -1
- package/dist/daily-summary.d.ts +8 -1
- package/dist/daily-summary.js +8 -5
- package/dist/daily-summary.js.map +1 -1
- package/dist/dashboard-live.d.ts +1 -1
- package/dist/dashboard-live.js +3 -3
- package/dist/dashboard-live.js.map +1 -1
- package/dist/dashboard-permissions.d.ts +1 -1
- package/dist/dashboard-permissions.js +1 -3
- package/dist/dashboard-permissions.js.map +1 -1
- package/dist/delivery-outbox.d.ts +31 -22
- package/dist/delivery-outbox.js +119 -161
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-outbox.test.js +10 -25
- package/dist/delivery-outbox.test.js.map +1 -1
- package/dist/doctor.d.ts +4 -0
- package/dist/doctor.js +16 -1
- package/dist/doctor.js.map +1 -1
- package/dist/fleet-level-config.js +1 -1
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +74 -66
- package/dist/fleet-manager.js +285 -414
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +5 -0
- package/dist/fleet-process-handlers.js +21 -0
- package/dist/fleet-process-handlers.js.map +1 -1
- package/dist/fleet-service-owner.d.ts +11 -0
- package/dist/fleet-service-owner.js +3 -0
- package/dist/fleet-service-owner.js.map +1 -0
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +11 -1
- package/dist/general-knowledge/skills/delegation-playbook/SKILL.md +1 -1
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +1 -1
- package/dist/general-knowledge/skills/session-management/SKILL.md +7 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +13 -204
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +30 -68
- package/dist/instance-lifecycle.d.ts +19 -0
- package/dist/instance-lifecycle.js +73 -15
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.js +6 -7
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-reconcile.js +3 -3
- package/dist/kiro-reconcile.js.map +1 -1
- package/dist/locale.js +96 -58
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +1 -1
- package/dist/log-service.js.map +1 -1
- package/dist/needs-you-hub.d.ts +1 -0
- package/dist/needs-you-hub.js +6 -3
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +3 -1
- package/dist/needs-you-live.js +24 -2
- package/dist/needs-you-live.js.map +1 -1
- package/dist/needs-you.d.ts +13 -2
- package/dist/needs-you.js +11 -1
- package/dist/needs-you.js.map +1 -1
- package/dist/notify-socket.d.ts +10 -0
- package/dist/notify-socket.js +45 -0
- package/dist/notify-socket.js.map +1 -0
- package/dist/outbound-handlers.js +20 -8
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +0 -62
- package/dist/outbound-schemas.js +4 -43
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/parked-notices.d.ts +87 -0
- package/dist/parked-notices.js +194 -0
- package/dist/parked-notices.js.map +1 -0
- package/dist/public-link-progress.d.ts +5 -2
- package/dist/public-link-progress.js +4 -3
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-web-gateway.js +0 -9
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +12 -0
- package/dist/public-web-link.js +29 -5
- package/dist/public-web-link.js.map +1 -1
- package/dist/quota-notice.d.ts +23 -0
- package/dist/quota-notice.js +22 -0
- package/dist/quota-notice.js.map +1 -0
- package/dist/scheduler/task-board.d.ts +17 -25
- package/dist/scheduler/task-board.js +29 -39
- package/dist/scheduler/task-board.js.map +1 -1
- package/dist/sd-notify.d.ts +23 -15
- package/dist/sd-notify.js +88 -29
- package/dist/sd-notify.js.map +1 -1
- package/dist/search/search-docs.d.ts +1 -1
- package/dist/search/search-docs.js +2 -2
- package/dist/search/search-docs.js.map +1 -1
- package/dist/settings-api.d.ts +16 -1
- package/dist/settings-api.js +56 -16
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +3 -1
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +17 -3
- package/dist/settings-confirmation.js +8 -5
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-effect.js +0 -2
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.js +31 -1
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/setup-wizard.d.ts +3 -0
- package/dist/setup-wizard.js +4 -2
- package/dist/setup-wizard.js.map +1 -1
- package/dist/task-board-waker.d.ts +43 -1
- package/dist/task-board-waker.js +121 -9
- package/dist/task-board-waker.js.map +1 -1
- package/dist/tmux-control.d.ts +1 -1
- package/dist/tmux-control.js +3 -2
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-manager.js +18 -16
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-read.d.ts +2 -0
- package/dist/tmux-read.js +7 -1
- package/dist/tmux-read.js.map +1 -1
- package/dist/tool-permissions.js +3 -10
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +29 -7
- package/dist/topic-commands.js +97 -37
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-monitor.d.ts +7 -0
- package/dist/transcript-monitor.js +48 -3
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +5 -0
- package/dist/tunnel/cloudflared.js +32 -1
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/named-diagnostics.d.ts +2 -1
- package/dist/tunnel/named-diagnostics.js +4 -1
- package/dist/tunnel/named-diagnostics.js.map +1 -1
- package/dist/tunnel/named-link-test.d.ts +90 -0
- package/dist/tunnel/named-link-test.js +270 -0
- package/dist/tunnel/named-link-test.js.map +1 -0
- package/dist/tunnel/purpose-lane.d.ts +3 -1
- package/dist/tunnel/purpose-lane.js +2 -0
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/types.d.ts +9 -11
- package/dist/ui/chat-ambient.js +4 -4
- package/dist/ui/chat-commands.js +3 -2
- package/dist/ui/chat-store.js +4 -1
- package/dist/ui/chat-strings.js +12 -46
- package/dist/ui/chat-thread.js +51 -59
- package/dist/ui/fleet-office-skin.js +37 -14
- package/dist/ui/fleet-office.js +31 -7
- package/dist/ui/html-attachment.js +22 -8
- package/dist/ui/panel-chat.js +21 -50
- package/dist/ui/panel-log.js +2 -2
- package/dist/ui/panel-needs.js +11 -9
- package/dist/ui/panel-settings.js +5 -3
- package/dist/ui/preview-panel.js +12 -21
- package/dist/ui/preview.js +10 -3
- package/dist/ui/search-dialog.js +30 -14
- package/dist/ui/settings-appearance.js +3 -37
- package/dist/ui/settings-confirm.js +18 -0
- package/dist/ui/settings-guests.js +13 -4
- package/dist/ui/settings-learn.js +1 -1
- package/dist/ui/settings-mods.js +5 -12
- package/dist/ui/settings-named-test.js +144 -0
- package/dist/ui/settings-registry.js +0 -2
- package/dist/ui/settings-strings.js +16 -16
- package/dist/ui/settings-web-authority.js +4 -3
- package/dist/ui/shared/app-i18n.js +15 -4
- package/dist/ui/shared/app-needs.js +5 -1
- package/dist/ui/shared/app-prefs.js +17 -17
- package/dist/ui/shared/app-shell.js +47 -9
- package/dist/ui/shared/app-store.js +6 -2
- package/dist/ui/shared/app.css +33 -39
- package/dist/ui/shared/app.js +5 -4
- package/dist/ui/shared/instance-nav.js +9 -9
- package/dist/ui/shared/instance-switch.js +8 -2
- package/dist/ui/shared/panel-view.js +22 -8
- package/dist/ui/shared/view-strings.js +6 -0
- package/dist/ui/shared/web-authorize.js +35 -13
- package/dist/update-check.d.ts +13 -4
- package/dist/update-check.js +17 -4
- package/dist/update-check.js.map +1 -1
- package/dist/usage/usage-api.d.ts +3 -0
- package/dist/usage/usage-api.js +5 -1
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/view-api.d.ts +2 -0
- package/dist/view-api.js +64 -0
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +9 -17
- package/dist/web-api.js +257 -371
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-tools.d.ts +0 -2
- package/dist/web-appearance-tools.js +2 -5
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance-view.d.ts +0 -6
- package/dist/web-appearance-view.js +0 -1
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-appearance.d.ts +14 -7
- package/dist/web-appearance.js +5 -6
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-asset-parts.d.ts +1 -17
- package/dist/web-asset-parts.js +1 -15
- package/dist/web-asset-parts.js.map +1 -1
- package/dist/web-auth.js +1 -7
- package/dist/web-auth.js.map +1 -1
- package/dist/web-chat-history.d.ts +3 -7
- package/dist/web-chat-history.js +10 -17
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +9 -1
- package/dist/web-commands.js +13 -0
- package/dist/web-commands.js.map +1 -1
- package/dist/web-experimental.d.ts +3 -8
- package/dist/web-experimental.js +9 -33
- package/dist/web-experimental.js.map +1 -1
- package/dist/web-guest-access.d.ts +40 -2
- package/dist/web-guest-access.js +50 -14
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-mod-bundle.d.ts +2 -45
- package/dist/web-mod-bundle.js +15 -63
- package/dist/web-mod-bundle.js.map +1 -1
- package/dist/web-mod-store.d.ts +3 -48
- package/dist/web-mod-store.js +30 -97
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-prefs.d.ts +13 -0
- package/dist/web-prefs.js +38 -0
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +6 -13
- package/dist/web-preview.js +12 -23
- package/dist/web-preview.js.map +1 -1
- package/dist/web-session.d.ts +11 -3
- package/dist/web-session.js +22 -11
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +1 -1
- package/dist/web-settings-patch.js +9 -7
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +0 -13
- package/dist/web-settings-tools.js +12 -84
- package/dist/web-settings-tools.js.map +1 -1
- package/dist/workflow-templates/default.md +2 -2
- package/dist/working-recovery.d.ts +0 -2
- package/dist/working-recovery.js +2 -23
- package/dist/working-recovery.js.map +1 -1
- package/launcher/agend-install.cjs +7 -1
- package/launcher/fleet-service-owner.cjs +150 -0
- package/package.json +1 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +0 -376
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +0 -673
- package/dist/task-board-summary.d.ts +0 -101
- package/dist/task-board-summary.js +0 -177
- package/dist/task-board-summary.js.map +0 -1
- package/dist/ui/app-effects.js +0 -251
- package/dist/ui/chat-effect-posters.js +0 -42
- package/dist/ui/chat-effects.js +0 -167
- package/dist/ui/effect-trial-controller.js +0 -124
- package/dist/ui/effect-trial-offer.js +0 -2
- package/dist/ui/effect-trial-panel.js +0 -40
- package/dist/ui/effects-waker.js +0 -2
- package/dist/ui/settings-effects.js +0 -202
- package/dist/ui/settings-owner-effects.js +0 -82
- package/dist/ui/shared/effect-app-runtime.js +0 -299
- package/dist/ui/shared/effect-baseline.js +0 -64
- package/dist/ui/shared/effect-chat-runtime.js +0 -162
- package/dist/ui/shared/effect-cursor.js +0 -126
- package/dist/ui/shared/effect-display-metadata.js +0 -39
- package/dist/ui/shared/effect-frame.js +0 -146
- package/dist/ui/shared/effect-geometry.js +0 -137
- package/dist/ui/shared/effect-host-style.js +0 -10
- package/dist/ui/shared/effect-owner-regions.js +0 -74
- package/dist/ui/shared/effect-owner-source.js +0 -122
- package/dist/ui/shared/effect-policy.js +0 -151
- package/dist/ui/shared/effect-poster-reader.js +0 -98
- package/dist/ui/shared/effect-posters.js +0 -117
- package/dist/ui/shared/effect-profiler.js +0 -184
- package/dist/ui/shared/effect-profiles.js +0 -65
- package/dist/ui/shared/effect-registry.js +0 -545
- package/dist/ui/shared/effect-runtime-loader.js +0 -236
- package/dist/ui/shared/effect-safety.js +0 -153
- package/dist/ui/shared/effect-stock-snapshot.js +0 -43
- package/dist/ui/shared/effect-stock-trust.js +0 -217
- package/dist/ui/shared/effect-trial-shadow.js +0 -62
- package/dist/ui/shared/effect-trial-source.js +0 -103
- package/dist/ui/shared/effect-trial-stage.js +0 -170
- package/dist/ui/shared/effect-trial.css +0 -40
- package/dist/ui/shared/feature-flags.js +0 -127
- package/dist/ui/shared/owner-effect-prefs.js +0 -117
- package/dist/upgrade-notices.d.ts +0 -17
- package/dist/upgrade-notices.js +0 -93
- package/dist/upgrade-notices.js.map +0 -1
- package/dist/web-effect-bootstrap.d.ts +0 -12
- package/dist/web-effect-bootstrap.js +0 -49
- package/dist/web-effect-bootstrap.js.map +0 -1
- package/dist/web-effect-bundle.d.ts +0 -28
- package/dist/web-effect-bundle.js +0 -171
- package/dist/web-effect-bundle.js.map +0 -1
- package/dist/web-effect-canonical.d.ts +0 -8
- package/dist/web-effect-canonical.js +0 -27
- package/dist/web-effect-canonical.js.map +0 -1
- package/dist/web-effect-library.d.ts +0 -114
- package/dist/web-effect-library.js +0 -530
- package/dist/web-effect-library.js.map +0 -1
- package/dist/web-effect-playback.d.ts +0 -30
- package/dist/web-effect-playback.js +0 -71
- package/dist/web-effect-playback.js.map +0 -1
- package/dist/web-effect-poster.d.ts +0 -8
- package/dist/web-effect-poster.js +0 -52
- package/dist/web-effect-poster.js.map +0 -1
- package/dist/web-effect-profiles.d.ts +0 -118
- package/dist/web-effect-profiles.js +0 -181
- package/dist/web-effect-profiles.js.map +0 -1
- package/dist/web-effect-service.d.ts +0 -93
- package/dist/web-effect-service.js +0 -335
- package/dist/web-effect-service.js.map +0 -1
- package/dist/web-effect-tools.d.ts +0 -48
- package/dist/web-effect-tools.js +0 -129
- package/dist/web-effect-tools.js.map +0 -1
- package/dist/web-effect-trials.d.ts +0 -86
- package/dist/web-effect-trials.js +0 -204
- package/dist/web-effect-trials.js.map +0 -1
- package/dist/web-effect-upload.d.ts +0 -27
- package/dist/web-effect-upload.js +0 -185
- package/dist/web-effect-upload.js.map +0 -1
- package/dist/web-effect-worker.d.ts +0 -8
- package/dist/web-effect-worker.js +0 -170
- package/dist/web-effect-worker.js.map +0 -1
- package/dist/web-effect.d.ts +0 -103
- package/dist/web-effect.js +0 -153
- package/dist/web-effect.js.map +0 -1
- package/dist/web-experimental-http.d.ts +0 -2
- package/dist/web-experimental-http.js +0 -12
- package/dist/web-experimental-http.js.map +0 -1
- package/dist/web-mod-agent.d.ts +0 -50
- package/dist/web-mod-agent.js +0 -207
- package/dist/web-mod-agent.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"purpose-lane.js","sourceRoot":"","sources":["../../src/tunnel/purpose-lane.ts"],"names":[],"mappings":"AAYA,MAAM,QAAQ,GAAG,GAAqB,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAClH,kGAAkG;AAClG,MAAM,OAAO,iBAAiB;IAEC,OAAO;IAD5B,KAAK,GAA2E,IAAI,CAAC;IAC7F,YAA6B,OAA8C;uBAA9C,OAAO;IAA0C,CAAC;IAC/E,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"purpose-lane.js","sourceRoot":"","sources":["../../src/tunnel/purpose-lane.ts"],"names":[],"mappings":"AAYA,MAAM,QAAQ,GAAG,GAAqB,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAClH,kGAAkG;AAClG,MAAM,OAAO,iBAAiB;IAEC,OAAO;IAD5B,KAAK,GAA2E,IAAI,CAAC;IAC7F,YAA6B,OAA8C;uBAA9C,OAAO;IAA0C,CAAC;IAC/E,+FAA+F;IAC/F,MAAM,KAAoB,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC;IAC/D,OAAO,CAAC,OAA6C,EAAE,EAAU;QAC/D,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9G,IAAI,OAAO,GAAG,IAAI,CAAC;QACnB,IAAI,QAAiD,CAAC;QACtD,IAAI,QAA+C,CAAC;QACpD,MAAM,OAAO,GAAG,GAAS,EAAE,GAAG,IAAI,OAAO,IAAI,IAAI,CAAC,KAAK,EAAE,WAAW,KAAK,WAAW;YAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3G,MAAM,WAAW,GAAsB;YACrC,KAAK,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE;gBAC3B,IAAI,IAAI,CAAC,KAAK,EAAE,WAAW,KAAK,WAAW;oBAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;gBACzG,IAAI,QAAQ;oBAAE,OAAO,QAAQ,CAAC;gBAC9B,OAAO,GAAG,KAAK,CAAC;gBAChB,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;oBAC7D,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;wBAAE,OAAO,GAAG,IAAI,CAAC;oBACpD,OAAO,MAAM,CAAC;gBAChB,CAAC,CAAC,CAAC;gBACH,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,IAAI,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE;gBAC3B,4GAA4G;gBAC5G,6CAA6C;gBAC7C,MAAM,KAAK,GAAG,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;gBACjD,OAAO,QAAQ,KAAK,CAAC,KAAK,IAAI,EAAE;oBAC9B,MAAM,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBAChC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;oBAC5D,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;oBAChE,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC;oBAC3B,OAAO,EAAE,CAAC;oBACV,OAAO,MAAM,CAAC;gBAChB,CAAC,CAAC,EAAE,CAAC;YACP,CAAC;YACD,aAAa,EAAE,OAAO;SACvB,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC;QAC1C,OAAO,WAAW,CAAC;IACrB,CAAC;CACF"}
|
package/dist/types.d.ts
CHANGED
|
@@ -271,11 +271,7 @@ export interface FleetDefaults extends Partial<InstanceConfig> {
|
|
|
271
271
|
progress_min_elapsed?: number;
|
|
272
272
|
/** Maximum UTF-8 byte size of one cross-instance tool message body. Default: 12288. */
|
|
273
273
|
max_cross_instance_message_bytes?: number;
|
|
274
|
-
/**
|
|
275
|
-
* #926: minutes after the last ask (or reminder) before a requester is told
|
|
276
|
-
* that an idle owner has not answered a requires_reply request. Default 15;
|
|
277
|
-
* 0 turns the notice off. The owner reminder is not affected.
|
|
278
|
-
*/
|
|
274
|
+
/** Obsolete since #2802 (the requester's overdue notice is gone): ignored, still validated as before for downgrades. */
|
|
279
275
|
reply_overdue_minutes?: number;
|
|
280
276
|
/** #1694: hours since the last ask before an open reply obligation expires (default 24; positive finite duration). */
|
|
281
277
|
reply_obligation_ttl_hours?: number;
|
|
@@ -300,8 +296,8 @@ export interface FleetDefaults extends Partial<InstanceConfig> {
|
|
|
300
296
|
tips?: boolean | "dm";
|
|
301
297
|
/** #2246 step 3: the task board's fleet-level settings. */
|
|
302
298
|
task_board?: {
|
|
303
|
-
/**
|
|
304
|
-
summary_at?:
|
|
299
|
+
/** #2804: the task board's daily summary is gone; a value written before is accepted and ignored. */
|
|
300
|
+
summary_at?: unknown;
|
|
305
301
|
};
|
|
306
302
|
webhooks?: WebhookConfig[];
|
|
307
303
|
}
|
|
@@ -530,9 +526,10 @@ export interface WebVerifiedAuthorityConfig {
|
|
|
530
526
|
*/
|
|
531
527
|
named_link?: boolean;
|
|
532
528
|
/**
|
|
533
|
-
* #1939 §0.3: sessions over the temporary public link (the quick tunnel `/web` opens) may be authorized too —
|
|
534
|
-
* default (the user's decision, 2026-10-
|
|
535
|
-
*
|
|
529
|
+
* #1939 §0.3: sessions over the temporary public link (the quick tunnel `/web` opens) may be authorized too — on by
|
|
530
|
+
* default (the user's decision, 2026-10-28; off before), and `false` turns it off. Each session still needs its
|
|
531
|
+
* account's Confirm in the DM. Turning it back on is confirmed in a General or on the host (never by the asking
|
|
532
|
+
* session); off applies at once and every receipt from a quick-link session reads as none.
|
|
536
533
|
*/
|
|
537
534
|
quick_link?: boolean;
|
|
538
535
|
}
|
|
@@ -556,7 +553,8 @@ export interface WebGuestsConfig {
|
|
|
556
553
|
*/
|
|
557
554
|
grants?: Record<string, {
|
|
558
555
|
name?: string;
|
|
559
|
-
instances: string[];
|
|
556
|
+
instances: string[]; /** #2855: "trusted" adds a read-only View and search; absent: chat. */
|
|
557
|
+
level?: "chat" | "trusted";
|
|
560
558
|
}>;
|
|
561
559
|
/** A guest session's limits: absolute 1–24 h (default 12), idle 15–720 min (default 120). */
|
|
562
560
|
session?: {
|
package/dist/ui/chat-ambient.js
CHANGED
|
@@ -252,13 +252,13 @@ export function ChatAmbient({ name, surface, part }) {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
/**
|
|
255
|
-
* The one-time note (the user's direction): the system asks for reduced motion and this chat's ambient
|
|
255
|
+
* The one-time note (the user's direction): the system asks for reduced motion and this chat's ambient plays anyway —
|
|
256
256
|
* say so once on this device, and turn it off right here (this device's switch: the same on the public link, where
|
|
257
|
-
* Settings is not). Shown only while an ambient
|
|
257
|
+
* Settings is not). Shown only while an ambient is playing.
|
|
258
258
|
*/
|
|
259
|
-
export function AmbientMotionNote({ name
|
|
259
|
+
export function AmbientMotionNote({ name }) {
|
|
260
260
|
const block = useAmbientBlock();
|
|
261
|
-
const shown =
|
|
261
|
+
const shown = !block && !!ambientFor(name);
|
|
262
262
|
const noteDue = motionNoteDue();
|
|
263
263
|
const [open, setOpen] = useState(false);
|
|
264
264
|
useEffect(() => {
|
package/dist/ui/chat-commands.js
CHANGED
|
@@ -24,10 +24,11 @@ const BY_NAME = new Map(CHAT_COMMANDS.map((c) => [c.name, c]));
|
|
|
24
24
|
* The palette for a draft: null when it is not one (no leading "/", or past the command's name), else the commands
|
|
25
25
|
* whose name starts with what was typed (possibly none: then it goes as a message).
|
|
26
26
|
*/
|
|
27
|
-
export function paletteFor(draft) {
|
|
27
|
+
export function paletteFor(draft, allowed) {
|
|
28
28
|
const m = /^\/([a-z]*)$/.exec(draft || "");
|
|
29
29
|
if (!m) return null;
|
|
30
|
-
|
|
30
|
+
// #2855: a guest's palette — only the commands the fleet says it may run on this agent (its status frame's `commands`).
|
|
31
|
+
return CHAT_COMMANDS.filter((c) => c.name.startsWith(m[1]) && (!allowed || allowed.includes(c.name)));
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/** `/name args` for a known command → { command, args }; anything else (unknown, not a command) → null. */
|
package/dist/ui/chat-store.js
CHANGED
|
@@ -43,7 +43,7 @@ const COMPACT_PAGE_LIMIT_MS = 11 * 60_000;
|
|
|
43
43
|
export function createChatStore(deps) {
|
|
44
44
|
const s = {
|
|
45
45
|
msgs: {}, drafts: {}, replies: {}, pendingFiles: {}, sending: {}, outgoing: {}, instanceStatus: {}, waking: {},
|
|
46
|
-
prompts: {}, workingSince: {}, stopping: {}, cancelling: {}, scrollMemo: {}, historyRead: new Set(), rbBusy: new Set(),
|
|
46
|
+
prompts: {}, workingSince: {}, stopping: {}, cancelling: {}, scrollMemo: {}, historyRead: new Set(), allHidden: new Set(), rbBusy: new Set(),
|
|
47
47
|
pollMine: readPollMine(),
|
|
48
48
|
// #1823 (#1828 review): the server's clock minus this device's. A poll's deadline is the server's; a page whose clock
|
|
49
49
|
// is a few seconds off would count a 10 s poll wrong. Only the server's explicit `clock` sets it (#1830 review): a
|
|
@@ -166,6 +166,8 @@ export function createChatStore(deps) {
|
|
|
166
166
|
if (signal?.aborted) { s.historyRead.delete(name); return false; }
|
|
167
167
|
if (!r || !Array.isArray(r.messages)) { s.historyRead.delete(name); return true; }
|
|
168
168
|
// Kept even when the person has moved on: the store is page-lived, and the answer belongs to `name`.
|
|
169
|
+
// #2848: a guest's chat whose every message is hidden from it (between agents): its empty chat says so.
|
|
170
|
+
if (r.allHidden === true) s.allHidden.add(name); else s.allHidden.delete(name);
|
|
169
171
|
for (const m of r.messages) liveReplies.message(m);
|
|
170
172
|
s.msgs[name] = R().mergeMessages(s.msgs[name], r.messages, 500);
|
|
171
173
|
settleOutgoing(name);
|
|
@@ -575,5 +577,6 @@ export function createChatStore(deps) {
|
|
|
575
577
|
uploadFile, send, retryOutgoing, deleteOutgoing, putBackOutgoing, threadRows, addFiles, removeFile, attachPastedText, fileBackAsText, isPasted, setDraft,
|
|
576
578
|
startReply, clearReply, findQuoted,
|
|
577
579
|
cancelReply, isUser, runCommand, dismissCommand, commandFree,
|
|
580
|
+
allHidden: (name) => s.allHidden.has(name),
|
|
578
581
|
};
|
|
579
582
|
}
|
package/dist/ui/chat-strings.js
CHANGED
|
@@ -17,26 +17,7 @@ register("chat", {
|
|
|
17
17
|
reply: "Reply", replyingTo: "Replying to {0}", replyCancel: "Cancel the reply (Esc)", replyHidden: "an earlier message", replyPhoto: "[Photo]", replyFile: "[File]",
|
|
18
18
|
replyGone: "That message is no longer in this chat.", replyJump: "Show the message this replies to", copyText: "Copy text", copyLink: "Copy link", msgMenu: "Message",
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
effectTrialReason_localAdmin: "Sign in as an admin outside the public link to Try.",
|
|
22
|
-
effectTrialReason_chatChanged: "Open the chat that offered this trial.",
|
|
23
|
-
effectTrialReason_busy: "Stop the current trial before starting another.",
|
|
24
|
-
effectTrialReason_safe: "Turn off safe mode to Try.",
|
|
25
|
-
effectTrialReason_effectsOff: "Turn on effects to Try.",
|
|
26
|
-
effectTrialReason_reducedMotion: "Effects follow this device’s reduced-motion setting.",
|
|
27
|
-
effectTrialReason_saveData: "Your device requests reduced data use.",
|
|
28
|
-
effectTrialReason_transport: "The isolated effect player is unavailable. Reload this page.",
|
|
29
|
-
effectTrialReason_unsupported: "Canvas Worker playback is unavailable in this browser.",
|
|
30
|
-
effectTrialReason_inactive: "Return to this page to Try.",
|
|
31
|
-
effectTrialReason_dialog: "Close the other menu or dialog to Try.",
|
|
32
|
-
effectTrialReason_expired: "This trial offer has expired.",
|
|
33
|
-
effectTrialSignIn: "Sign in here",
|
|
34
|
-
effectTrialStopOther: "Stop current trial",
|
|
35
|
-
effectTrialSettings: "Open playback settings",
|
|
36
|
-
effectTrialPlayMotion: "Play effects anyway",
|
|
37
|
-
effectTrial: "Effect trial", effectTrialLocal: "A sample on this page. Nothing is applied or saved.",
|
|
38
|
-
effectTrialStopped: "Try stopped", effectTrialStart: "Try", effectTrialExpired: "This trial offer has expired.", effectTrialUnavailable: "This trial is no longer available.",
|
|
39
|
-
cmdConfirm: "Clear", cmdConfirmBackend: "Switch and restart", cmdRunning: "Running /{0}…", cmdNotCommand: "Not a command here — Enter sends it as a message.", cmdDismiss: "Dismiss", cmdCommands: "Commands",
|
|
20
|
+
cmdConfirm: "Clear", cmdConfirmBackend: "Switch and restart", cmdRunning: "Running /{0}…", cmdNotCommand: "Not a command here — Enter sends it as a message.", cmdNotGuests: "Not one a guest can run here.", cmdDismiss: "Dismiss", cmdCommands: "Commands",
|
|
40
21
|
compactRunning: "Compacting…", compactDone: "✅ Conversation compacted", compactUnknown: "This backend does not report when compaction ends.",
|
|
41
22
|
compactTimeout: "No sign that compaction finished within {0} minutes — check the agent's own chat.",
|
|
42
23
|
compactLost: "Can't follow this compaction: the command did not reach the agent, or the agent stopped or changed backend.",
|
|
@@ -57,13 +38,14 @@ register("chat", {
|
|
|
57
38
|
stopping: "Stopping {0}…", awaiting: "{0} is waiting for your input", approxNote: "Read from the terminal, so approximate", elapsedTitle: "Time since this page saw it start (approximate)",
|
|
58
39
|
dropHere: "Drop files to attach them", asText: "As text", pasteAttached: "A long paste ({0} characters) was attached as a text file", pasteKeptAsText: "No room for another attachment: the long paste stays as text",
|
|
59
40
|
send: "Send", composerPlaceholder: "Message {0}…", composerHint: "Enter to send · Shift+Enter for a new line", composerHintTouch: "Return adds a line · tap Send to send", composerMore: "/ for commands · Esc stops the reply", guestMore: "Esc stops the reply",
|
|
60
|
-
guestNote: "You're a guest: the agent sees your messages as a guest's (recognition only).", guestNoCommands: "Guests can't
|
|
41
|
+
guestNote: "You're a guest: the agent sees your messages as a guest's (recognition only).", guestNoCommands: "Guests can't send that — send it without the leading /.", guestCommandNotAllowed: "{0} isn't available to guests. Only this channel's admins can run it.", attachTitle: "Attach files (any type — or paste / drop them)",
|
|
61
42
|
pvPreview: "Preview", pvStop: "Stop", pvDownload: "Download", pvMenu: "Preview options", pvHtml: "HTML",
|
|
62
43
|
pvAllowButton: "Allow previews", pvAllow: "Allow HTML previews — they may be able to send data out", pvDisallow: "Stop allowing HTML previews",
|
|
63
44
|
pvConfirm: "Allow HTML previews?\n\nThis applies on every device where you are signed in. A preview runs the agent's HTML in an isolated frame. It cannot use your login, but it may be able to send data out, and it can slow or freeze this tab. You still click Preview each time.",
|
|
64
45
|
pvNever: "Never preview HTML on this device", pvNeverUndo: "Let this device preview HTML again", pvStarting: "Starting the preview…",
|
|
65
46
|
pvChanged: "Preview stopped — the message changed. Preview again.", pvTruncated: "Truncated — ask the agent to send it as a .html file.",
|
|
66
|
-
pvLoading: "Reading the file…", pvAttOver: "This file is over
|
|
47
|
+
pvLoading: "Reading the file…", pvAttOver: "This file is over 50 MB; it is not previewed. Download it to open it.",
|
|
48
|
+
pvLarge: "This file is large ({0}). Preview anyway?", pvAnyway: "Preview anyway",
|
|
67
49
|
pvAttGone: "This file is no longer available here (it changed, or the fleet restarted). Ask the agent to send it again.",
|
|
68
50
|
pvAttFailed: "Could not read this file. Try again.",
|
|
69
51
|
pvBannerAck: "I understand", pvBannerAckTitle: "Hide this notice until you sign in again",
|
|
@@ -83,7 +65,7 @@ register("chat", {
|
|
|
83
65
|
pvWhyNever: "Previews are switched off on this device for this session.",
|
|
84
66
|
pvWhyOrigin: "Previews are off: this page is at {0}, but the fleet believes it is at {1} (a proxy that rewrites Host). Pass the external Host through, or set web.preview_origin.",
|
|
85
67
|
pvUnknownAddress: "an unknown address", pvWhyServer: "Previews are not available here.",
|
|
86
|
-
pvHtmlOver: "This HTML is over
|
|
68
|
+
pvHtmlOver: "This HTML is over 50 MB; it is not previewed. Download it to open it.",
|
|
87
69
|
pvNoAnswer: "Preview unavailable: the preview did not answer within 3 s. If an earlier preview froze, it may still be running — open the dashboard in a new tab. Over SSH, forward the preview port too.",
|
|
88
70
|
pvStoppedAnswering: "The preview stopped answering, so it was closed.", pvSwitchedOff: "Previews were switched off on this device.",
|
|
89
71
|
pvAnother: "Another preview started.", pvWrongBoot: "Preview unavailable: something else answered on the preview port.",
|
|
@@ -115,6 +97,7 @@ register("chat", {
|
|
|
115
97
|
working: "{0} is working…", stuck: "{0} looks stuck", stopReply: "Stop reply", stopReplyTitle: "Stop the current reply (like Esc) and drop the messages still waiting. The instance keeps running.", stopSent: "Stopped",
|
|
116
98
|
file_empty: "empty file", file_too_large: "over {0} MB", file_too_large_public: "over {0} MB — the most the public link carries in one upload", file_too_many: "at most {0} files per message", file_too_much: "the files together would be over {0} MB", removeFile: "Remove", putBack: "Put back",
|
|
117
99
|
noMessages: "Type a task below.",
|
|
100
|
+
guestAllHidden: "Nothing here you can see yet", guestAllHiddenHint: "This agent's recent activity is between agents, which guests don't see. Its chat appears here when someone talks in its channel.",
|
|
118
101
|
pick: "Choose an agent to start chatting.", noAgents: "Create an agent to start chatting.", newAgent: "New agent", notFound: "No instance called “{0}”", notFoundHint: "It may have been deleted or renamed.", backToList: "Choose an agent",
|
|
119
102
|
details: "Instance details", fullWidth: "Full width", start: "Start instance", stopInstance: "Stop instance", restart: "Restart instance", delete: "Delete instance…",
|
|
120
103
|
started: "{0} started", stoppedInst: "{0} stopped", restarted: "{0} restarted", instanceDeleted: "{0} was deleted",
|
|
@@ -158,26 +141,7 @@ register("chat", {
|
|
|
158
141
|
reply: "回覆", replyingTo: "回覆 {0}", replyCancel: "取消回覆(Esc)", replyHidden: "之前的一則訊息", replyPhoto: "[圖片]", replyFile: "[檔案]",
|
|
159
142
|
replyGone: "那則訊息已不在這個聊天裡。", replyJump: "顯示被回覆的訊息", copyText: "複製文字", copyLink: "複製連結", msgMenu: "訊息",
|
|
160
143
|
|
|
161
|
-
|
|
162
|
-
effectTrialReason_localAdmin: "請在公開連結以外的儀表板以管理員登入後試播。",
|
|
163
|
-
effectTrialReason_chatChanged: "請開啟發出試播邀請的聊天。",
|
|
164
|
-
effectTrialReason_busy: "請先停止目前的試播。",
|
|
165
|
-
effectTrialReason_safe: "請先關閉安全模式。",
|
|
166
|
-
effectTrialReason_effectsOff: "請先開啟效果。",
|
|
167
|
-
effectTrialReason_reducedMotion: "效果跟隨這台裝置的「減少動態效果」設定。",
|
|
168
|
-
effectTrialReason_saveData: "裝置目前要求節省數據。",
|
|
169
|
-
effectTrialReason_transport: "隔離效果播放器目前無法使用。請重新載入頁面。",
|
|
170
|
-
effectTrialReason_unsupported: "此瀏覽器無法播放 Canvas Worker 效果。",
|
|
171
|
-
effectTrialReason_inactive: "請回到本頁後試播。",
|
|
172
|
-
effectTrialReason_dialog: "請先關閉其他選單或對話框。",
|
|
173
|
-
effectTrialReason_expired: "試播邀請已過期。",
|
|
174
|
-
effectTrialSignIn: "在此登入",
|
|
175
|
-
effectTrialStopOther: "停止目前試播",
|
|
176
|
-
effectTrialSettings: "開啟播放設定",
|
|
177
|
-
effectTrialPlayMotion: "仍然播放效果",
|
|
178
|
-
effectTrial: "效果試播", effectTrialLocal: "僅在本頁試播,不會套用或儲存。",
|
|
179
|
-
effectTrialStopped: "試播已停止", effectTrialStart: "試播", effectTrialExpired: "試播邀請已過期。", effectTrialUnavailable: "此試播已無法使用。",
|
|
180
|
-
cmdConfirm: "清空", cmdConfirmBackend: "切換並重新啟動", cmdRunning: "執行 /{0} 中…", cmdNotCommand: "這裡沒有這個指令——按 Enter 會當成一般訊息送出。", cmdDismiss: "關閉", cmdCommands: "指令",
|
|
144
|
+
cmdConfirm: "清空", cmdConfirmBackend: "切換並重新啟動", cmdRunning: "執行 /{0} 中…", cmdNotCommand: "這裡沒有這個指令——按 Enter 會當成一般訊息送出。", cmdNotGuests: "訪客在這裡不能使用這個指令。", cmdDismiss: "關閉", cmdCommands: "指令",
|
|
181
145
|
compactRunning: "壓縮中…", compactDone: "✅ 對話已壓縮", compactUnknown: "這個後端不會回報壓縮何時完成。",
|
|
182
146
|
compactTimeout: "{0} 分鐘內沒有看到壓縮完成的紀錄,請到代理自己的對話確認。",
|
|
183
147
|
compactLost: "無法再追蹤這次壓縮:指令沒有送到代理,或代理已停止、換了後端。",
|
|
@@ -198,13 +162,14 @@ register("chat", {
|
|
|
198
162
|
stopping: "正在中止 {0}…", awaiting: "{0} 正在等你回應", approxNote: "從終端畫面判讀,僅供參考", elapsedTitle: "從這個頁面看到它開始工作起算(約略)",
|
|
199
163
|
dropHere: "放開即可附加檔案", asText: "改為文字", pasteAttached: "貼上的長文字({0} 個字元)已改為文字檔附加", pasteKeptAsText: "附件已滿,貼上的長文字保留為一般文字",
|
|
200
164
|
send: "送出", composerPlaceholder: "傳訊息給 {0}…", composerHint: "Enter 送出 · Shift+Enter 換行", composerHintTouch: "Return 換行 · 按「送出」傳送", composerMore: "/ 叫出指令 · Esc 中止回覆", guestMore: "Esc 中止回覆",
|
|
201
|
-
guestNote: "你是訪客:agent 會把你的訊息視為訪客的訊息(僅供辨識)。", guestNoCommands: "
|
|
165
|
+
guestNote: "你是訪客:agent 會把你的訊息視為訪客的訊息(僅供辨識)。", guestNoCommands: "訪客不能這樣送出,請去掉開頭的 / 再送出。", guestCommandNotAllowed: "訪客不能使用 {0},只有這個頻道的管理員可以執行。", attachTitle: "附加檔案(任何類型,也可以貼上或拖曳)",
|
|
202
166
|
pvPreview: "預覽", pvStop: "停止", pvDownload: "下載", pvMenu: "預覽選項", pvHtml: "HTML",
|
|
203
167
|
pvAllowButton: "允許預覽", pvAllow: "允許預覽 HTML(預覽可能把資料傳出去)", pvDisallow: "不再允許預覽 HTML",
|
|
204
168
|
pvConfirm: "要允許預覽 HTML 嗎?\n\n這會套用到你登入的每一台裝置。預覽會在隔離的框架裡執行 agent 的 HTML。它無法使用你的登入,但可能把資料傳出去,也可能讓這個分頁變慢或卡住。每次仍需要你按「預覽」。",
|
|
205
169
|
pvNever: "這台裝置永不預覽 HTML", pvNeverUndo: "讓這台裝置再次可以預覽 HTML", pvStarting: "正在啟動預覽…",
|
|
206
170
|
pvChanged: "預覽已停止——訊息內容變了。請再預覽一次。", pvTruncated: "內容被截斷——請 agent 改用 .html 檔案傳送。",
|
|
207
|
-
pvLoading: "正在讀取檔案…", pvAttOver: "這個檔案超過
|
|
171
|
+
pvLoading: "正在讀取檔案…", pvAttOver: "這個檔案超過 50 MB,不提供預覽,請下載後開啟。",
|
|
172
|
+
pvLarge: "這個檔案比較大({0}),仍要預覽嗎?", pvAnyway: "仍要預覽",
|
|
208
173
|
pvAttGone: "這裡已無法取得這個檔案(檔案已變更,或艦隊已重新啟動)。請 agent 再傳一次。",
|
|
209
174
|
pvAttFailed: "無法讀取這個檔案,請再試一次。",
|
|
210
175
|
pvBannerAck: "我知道了", pvBannerAckTitle: "隱藏這則提醒,直到下次登入",
|
|
@@ -222,7 +187,7 @@ register("chat", {
|
|
|
222
187
|
pvWhyNever: "這台裝置在這個工作階段已關閉預覽。",
|
|
223
188
|
pvWhyOrigin: "預覽已關閉:這個頁面位於 {0},但艦隊認為它位於 {1}(有會改寫 Host 的代理)。請讓外部 Host 原樣傳入,或設定 web.preview_origin。",
|
|
224
189
|
pvUnknownAddress: "未知的網址", pvWhyServer: "這裡無法使用預覽。",
|
|
225
|
-
pvHtmlOver: "這段 HTML 超過
|
|
190
|
+
pvHtmlOver: "這段 HTML 超過 50 MB,不提供預覽,請下載後開啟。",
|
|
226
191
|
pvNoAnswer: "無法預覽:預覽在 3 秒內沒有回應。如果先前的預覽卡住了,它可能還在執行——請在新分頁開啟儀表板。透過 SSH 使用時,也要轉送預覽的連接埠。",
|
|
227
192
|
pvStoppedAnswering: "預覽沒有回應,已將它關閉。", pvSwitchedOff: "這台裝置已關閉預覽。",
|
|
228
193
|
pvAnother: "另一個預覽已開始。", pvWrongBoot: "無法預覽:預覽連接埠上回應的不是這個艦隊。",
|
|
@@ -254,6 +219,7 @@ register("chat", {
|
|
|
254
219
|
working: "{0} 處理中…", stuck: "{0} 似乎卡住了", stopReply: "中止回覆", stopReplyTitle: "中止目前的回覆(同 Esc),並取消還在排隊的訊息。instance 會繼續運行。", stopSent: "已中止",
|
|
255
220
|
file_empty: "空檔案", file_too_large: "超過 {0} MB", file_too_large_public: "超過 {0} MB,這是公開連結單次上傳的上限", file_too_many: "每則訊息最多 {0} 個檔案", file_too_much: "檔案合計會超過 {0} MB", removeFile: "移除", putBack: "放回輸入框",
|
|
256
221
|
noMessages: "直接在下方輸入任務。",
|
|
222
|
+
guestAllHidden: "這裡還沒有你能看到的訊息", guestAllHiddenHint: "這個 agent 最近只和其他 agent 往來,訪客看不到這些。有人在它的頻道說話後,對話會出現在這裡。",
|
|
257
223
|
pick: "選一個 Agent 開始聊天。", noAgents: "先建立一個 Agent,再開始聊天。", newAgent: "新增 Agent", notFound: "沒有叫「{0}」的 instance", notFoundHint: "它可能已被刪除或改名。", backToList: "選擇 Agent",
|
|
258
224
|
details: "Instance 詳細資料", fullWidth: "全寬", start: "啟動 instance", stopInstance: "停止 instance", restart: "重新啟動 instance", delete: "刪除 instance…",
|
|
259
225
|
started: "{0} 已啟動", stoppedInst: "{0} 已停止", restarted: "{0} 已重新啟動", instanceDeleted: "{0} 已刪除",
|
package/dist/ui/chat-thread.js
CHANGED
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
// Unrelated updates (a new message, another message's tick) stop nothing (#1306 §6.2, #1408 §4).
|
|
9
9
|
import "./chat-render.js";
|
|
10
10
|
import "./preview.js";
|
|
11
|
-
import {
|
|
12
|
-
import { loadHtmlAttachment } from "./html-attachment.js";
|
|
11
|
+
import { HTML_PREVIEW_MAX, loadHtmlAttachment, sizeLabel } from "./html-attachment.js";
|
|
13
12
|
import { chatTime, chatTimeFull, onDayChange } from "./chat-time.js";
|
|
14
13
|
import { textLinkSegments } from "/assets/app-route.js";
|
|
15
14
|
|
|
@@ -24,6 +23,12 @@ export const TEXT_PREVIEW_LINES = 200;
|
|
|
24
23
|
export const TEXT_PREVIEW_NODES = 4000;
|
|
25
24
|
/** A csv/tsv wider than this is shown as text, as Markdown tables are capped at 20 columns. */
|
|
26
25
|
export const TEXT_PREVIEW_COLUMNS = 50;
|
|
26
|
+
/**
|
|
27
|
+
* #2863: the most a text card reads (bytes). It stays 1 MiB while an HTML preview goes to 8 MiB (and 50 MiB on
|
|
28
|
+
* "Preview anyway"): a text card reads, parses and formats the file on this page's own thread (Markdown, highlighting,
|
|
29
|
+
* a CSV table; Show all draws every line), where an HTML preview runs in its own frame. A bigger file is a download.
|
|
30
|
+
*/
|
|
31
|
+
export const TEXT_CARD_MAX = 1024 * 1024;
|
|
27
32
|
const P = () => globalThis.AgendPreview;
|
|
28
33
|
/** #1672: a status line longer than this (lines, or characters) is folded until it is opened. */
|
|
29
34
|
export const STATUS_FOLD_LINES = 6;
|
|
@@ -120,7 +125,7 @@ export function createThread(list, scroller, opts) {
|
|
|
120
125
|
if (el.textContent !== v) el.textContent = v;
|
|
121
126
|
}
|
|
122
127
|
// #1770: "today" ends at the fleet's midnight; the labels are rewritten then (and on every render), while there are any.
|
|
123
|
-
let offDay = null
|
|
128
|
+
let offDay = null;
|
|
124
129
|
function armDay() {
|
|
125
130
|
if (nodes.size && !offDay) offDay = onDayChange(() => { for (const v of nodes.values()) timeLabel(v.node); });
|
|
126
131
|
else if (!nodes.size && offDay) { offDay(); offDay = null; }
|
|
@@ -133,8 +138,6 @@ export function createThread(list, scroller, opts) {
|
|
|
133
138
|
// is kept by: it is written into the node (timeLabels) — crossing midnight relabels in place and reloads no preview.
|
|
134
139
|
const time = x.ts ? `<span class="time" data-ts="${escAttr(x.ts)}" title="${escAttr(chatTimeFull(x.ts))}"></span>` : `<span class="time"></span>`;
|
|
135
140
|
if (x.outgoing) return outgoingHtml(x);
|
|
136
|
-
const trial = readCanvasTrialMessage(x);
|
|
137
|
-
if (trial) return canvasWorkerEnabled() ? trialHtml(trial, time, x) : "";
|
|
138
141
|
if (x.role === "status") return statusHtml(x, time);
|
|
139
142
|
const u = opts.isUser(x);
|
|
140
143
|
// renderMarkdown escapes the whole text before it adds any tag of its own (chat-render.js).
|
|
@@ -213,26 +216,7 @@ export function createThread(list, scroller, opts) {
|
|
|
213
216
|
? `<button type="button" class="click-link" data-act="showButtons" data-arg="${escAttr(of)}" title="${escAttr(tr("chat.clickShow"))}">${inner}</button>`
|
|
214
217
|
: `<span class="click-text">${inner}</span>`}</div>`;
|
|
215
218
|
}
|
|
216
|
-
|
|
217
|
-
const trialReasons = new Set(["checking", "localAdmin", "chatChanged", "busy", "safe", "effectsOff", "reducedMotion", "saveData", "unsupported", "transport", "inactive", "dialog", "expired"]);
|
|
218
|
-
function trialStatus(message) {
|
|
219
|
-
const reason = opts.effectTrialStatus?.(message);
|
|
220
|
-
return reason === "ready" || trialReasons.has(reason) ? reason : opts.canTryEffect?.(message) === true ? "ready" : "localAdmin";
|
|
221
|
-
}
|
|
222
|
-
function trialHtml(offer, time, message) {
|
|
223
|
-
const reason = trialNow() >= offer.expiresAt ? "expired" : PUBLIC_LINK() ? "localAdmin" : trialStatus(message);
|
|
224
|
-
const rawFailure = opts.effectTrialFailure?.(message), failure = typeof rawFailure === "string" ? rawFailure.replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 80) : null;
|
|
225
|
-
const available = reason === "ready", fix = !PUBLIC_LINK() && !available && reason !== "expired" && reason !== "checking" && typeof opts.fixEffectTrial === "function";
|
|
226
|
-
const label = available ? "chat.effectTrialStart" : reason === "busy" ? "chat.effectTrialStopOther" : reason === "localAdmin" ? "chat.effectTrialSignIn" : reason === "reducedMotion" ? "chat.effectTrialPlayMotion" : "chat.effectTrialSettings";
|
|
227
|
-
const button = available || fix ? `<button type="button" class="btn btn-sm effect-trial-start" data-act="effectTrial" data-arg="${escAttr(msgKey(message))}">${escAttr(tr(label))}</button>` : "";
|
|
228
|
-
return `<div class="msg status-line"><div class="meta">${time}</div><div class="body"><div class="effect-trial-offer" data-trust="thread-control"><strong>${escAttr(tr("chat.effectTrial"))}: ${escAttr(offer.title)}</strong><div>${escAttr(tr(available ? "chat.effectTrialLocal" : "chat.effectTrialReason_" + reason))}</div>${failure ? `<div class="effect-trial-failure" role="status">${escAttr(tr("chat.effectTrialStopped"))}: ${escAttr(failure)}</div>` : ""}${button}</div></div></div>`;
|
|
229
|
-
}
|
|
230
|
-
function armTrials() {
|
|
231
|
-
if (trialTimer !== null) clearTimeout(trialTimer); trialTimer = null;
|
|
232
|
-
if (!canvasWorkerEnabled()) return;
|
|
233
|
-
const now = trialNow(), next = msgs.map(x => readCanvasTrialMessage(x)).filter(x => x && x.expiresAt > now).reduce((n, x) => Math.min(n, x.expiresAt), Infinity);
|
|
234
|
-
if (Number.isFinite(next)) trialTimer = setTimeout(() => { trialTimer = null; render(msgs); }, Math.max(1, Math.min(2147483647, next - now)));
|
|
235
|
-
}
|
|
219
|
+
|
|
236
220
|
/**
|
|
237
221
|
* #1672: a status line (another instance's message, a daemon notice) is muted, read-only plain text — never Markdown,
|
|
238
222
|
* a preview card, a button or a person's bubble. Checked before isUser, which reads the sender: a fleet name need not
|
|
@@ -428,7 +412,7 @@ export function createThread(list, scroller, opts) {
|
|
|
428
412
|
if (reading) return;
|
|
429
413
|
if (text !== null) { body.hidden = !body.hidden; show.textContent = tr(body.hidden ? "chat.tcShow" : "chat.tcHide"); return; }
|
|
430
414
|
const mine = reading = ++reads; note.textContent = tr("chat.pvLoading");
|
|
431
|
-
const r = await loadHtmlAttachment({ id: att.id, name: att.name, size: att.size });
|
|
415
|
+
const r = await loadHtmlAttachment({ id: att.id, name: att.name, size: att.size }, undefined, { ask: TEXT_CARD_MAX, max: TEXT_CARD_MAX });
|
|
432
416
|
if (reading !== mine) return; // dropped (its chat left meanwhile): a new click reads again
|
|
433
417
|
reading = 0;
|
|
434
418
|
if (!ph.isConnected) return; // the card left the page while it was read: nothing to draw
|
|
@@ -484,6 +468,8 @@ export function createThread(list, scroller, opts) {
|
|
|
484
468
|
const head = el("div", "pv-head"); head.setAttribute("data-trust", "thread-control");
|
|
485
469
|
const label = el("span", "pv-label", att ? `${tr("chat.pvHtml")} · ${att.name}` : tr("chat.pvHtml"));
|
|
486
470
|
const run = el("button", "btn btn-sm pv-run", tr("chat.pvPreview")); run.type = "button";
|
|
471
|
+
// #2863: a large file (over 8 MB) is previewed only on this second click, in the card or the panel as first asked.
|
|
472
|
+
const anywayB = el("button", "btn btn-sm pv-anyway", tr("chat.pvAnyway")); anywayB.type = "button"; anywayB.hidden = true;
|
|
487
473
|
const stopB = el("button", "btn btn-sm pv-stop", tr("chat.pvStop")); stopB.type = "button"; stopB.hidden = true;
|
|
488
474
|
// An attachment already has its download link (the file itself) right above the card.
|
|
489
475
|
const dl = att ? null : el("button", "btn btn-sm btn-ghost pv-dl", tr("chat.pvDownload"));
|
|
@@ -496,7 +482,7 @@ export function createThread(list, scroller, opts) {
|
|
|
496
482
|
const optB = el("button", "chip-btn pv-opt"); optB.type = "button";
|
|
497
483
|
const neverB = el("button", "chip-btn pv-never"); neverB.type = "button";
|
|
498
484
|
menu.append(sum, optB, neverB);
|
|
499
|
-
head.append(label, run, stopB, ...(toPanel ? [toPanel] : []), ...(dl ? [dl] : []), menu);
|
|
485
|
+
head.append(label, run, anywayB, stopB, ...(toPanel ? [toPanel] : []), ...(dl ? [dl] : []), menu);
|
|
500
486
|
const note = el("div", "pv-note"); note.setAttribute("data-trust", "thread-control");
|
|
501
487
|
// #1568: the banner, with its "I understand" (hidden until the next sign-in; the frame's border stays).
|
|
502
488
|
const banner = el("div", "pv-banner"); banner.setAttribute("data-trust", "thread-control"); banner.hidden = true;
|
|
@@ -508,45 +494,64 @@ export function createThread(list, scroller, opts) {
|
|
|
508
494
|
// Reading an attachment: one read per card at a time (a second click while it reads does nothing), and a read
|
|
509
495
|
// whose card was stopped, replaced or left meanwhile is dropped (`reading` moved on, or the card left the page).
|
|
510
496
|
let reading = 0, reads = 0;
|
|
497
|
+
// #2863: where "Preview anyway" runs it ("card" | "panel") and what the card says meanwhile; null: not asked.
|
|
498
|
+
// `tooBig`: over the 50 MB ceiling (listed, or read) — the card says so and offers only the file's download.
|
|
499
|
+
let large = null, largeNote = "", tooBig = !!att && typeof att.size === "number" && att.size > HTML_PREVIEW_MAX;
|
|
511
500
|
const refresh = (reason) => {
|
|
512
501
|
const a = P().availability();
|
|
513
502
|
const going = state === "starting" || state === "running";
|
|
514
503
|
const inPanel = !!panel && panel.shown() === key; // #1481: the panel shows this block; the card points there
|
|
515
|
-
|
|
516
|
-
if (
|
|
504
|
+
if (going || reading) large = null;
|
|
505
|
+
if (reason == null && large) reason = largeNote;
|
|
506
|
+
if (reason == null && tooBig) reason = tr("chat.pvAttOver");
|
|
507
|
+
run.hidden = !a.ok || going || inPanel || !!reading || !!large || tooBig;
|
|
508
|
+
anywayB.hidden = !a.ok || !large;
|
|
509
|
+
if (toPanel) toPanel.hidden = inPanel || !!reading || tooBig;
|
|
517
510
|
stopB.hidden = !going && !reading;
|
|
518
511
|
banner.hidden = !going || P().bannerAcked();
|
|
519
512
|
note.textContent = reason != null ? reason : reading ? tr("chat.pvLoading") : going ? (state === "starting" ? tr("chat.pvStarting") : "") : inPanel ? tr("chat.pvInPanel") : a.ok ? "" : a.reason;
|
|
520
513
|
optB.textContent = P().optedIn() ? tr("chat.pvDisallow") : tr("chat.pvAllow");
|
|
521
514
|
neverB.textContent = P().never() ? tr("chat.pvNeverUndo") : tr("chat.pvNever");
|
|
522
515
|
};
|
|
523
|
-
/**
|
|
524
|
-
const
|
|
516
|
+
/** Over 8 MB: the card asks, and "Preview anyway" runs it where `target` ("card" | "panel") says. */
|
|
517
|
+
const askLarge = (target, reason) => { large = target; largeNote = reason; refresh(reason); };
|
|
518
|
+
/**
|
|
519
|
+
* The HTML, then `then(code)`: at once for a fence or an attachment already read; otherwise read it first — a large
|
|
520
|
+
* one only once `anyway` (its listed size asks before anything is fetched).
|
|
521
|
+
*/
|
|
522
|
+
const withCode = async (then, target = "card", anyway = false) => {
|
|
525
523
|
if (code != null) { then(code); return; }
|
|
526
524
|
if (reading) return;
|
|
527
525
|
const mine = reading = ++reads;
|
|
528
526
|
refresh();
|
|
529
|
-
const r = await loadHtmlAttachment(att);
|
|
527
|
+
const r = await loadHtmlAttachment(att, undefined, { anyway });
|
|
530
528
|
if (reading !== mine || !ph.isConnected) return;
|
|
531
529
|
reading = 0;
|
|
530
|
+
if (!r.ok && r.reason === "large") { askLarge(target, trf("chat.pvLarge", sizeLabel(r.size))); return; }
|
|
531
|
+
if (!r.ok && r.reason === "over") { tooBig = true; refresh(); return; }
|
|
532
532
|
if (!r.ok) { refresh(attReason(r.reason)); return; }
|
|
533
533
|
code = r.code;
|
|
534
534
|
refresh();
|
|
535
535
|
then(code);
|
|
536
536
|
};
|
|
537
|
-
const ui = { state: (name, reason) => {
|
|
537
|
+
const ui = { state: (name, reason) => {
|
|
538
|
+
state = name === "starting" || name === "running" ? name : "idle";
|
|
539
|
+
if (name === "large") { askLarge("card", reason || ""); return; }
|
|
540
|
+
large = null; refresh(reason || null);
|
|
541
|
+
} };
|
|
538
542
|
// Nothing is read for Preview on a device that does not allow previews: the button is not even shown there.
|
|
539
543
|
// A Preview click is newer than any Open in panel still reading (#1704): it claims the panel's turn too — and, its
|
|
540
544
|
// own HTML read, starts only if no newer click claimed meanwhile and no preview was started since (the panel's own
|
|
541
545
|
// Preview): a late read never undoes a newer choice. A close is neither, so it does not drop this click.
|
|
542
|
-
|
|
546
|
+
const preview = (anyway) => {
|
|
543
547
|
if (!P().availability().ok || reading) return; // this card already reading: that click stays the one
|
|
544
548
|
const mine = panel ? (panel.claim(), panel.claims()) : 0, started = P().startCount();
|
|
545
549
|
withCode((c) => {
|
|
546
550
|
if ((panel && panel.claims() !== mine) || P().startCount() !== started) { refresh(); return; }
|
|
547
|
-
P().start(key, holder, c, ui);
|
|
548
|
-
});
|
|
551
|
+
if (anyway) P().start(key, holder, c, ui, { anyway: true }); else P().start(key, holder, c, ui);
|
|
552
|
+
}, "card", anyway);
|
|
549
553
|
};
|
|
554
|
+
run.onclick = () => preview(false);
|
|
550
555
|
stopB.onclick = () => { if (reading) { reading = 0; refresh(); } else P().stop(key, "stopped", ""); };
|
|
551
556
|
// #1704: this click runs it in the panel, as Preview there would — a running preview moves (it stops here and
|
|
552
557
|
// starts there), an idle one starts there. Whether it can run is the panel's to say: a device that has not allowed
|
|
@@ -554,15 +559,18 @@ export function createThread(list, scroller, opts) {
|
|
|
554
559
|
// An attachment's HTML is read first. The click claims the panel at once, so a newer click (even one still reading)
|
|
555
560
|
// wins: if the panel changed (another click, block, close) or any preview started meanwhile, this one is dropped —
|
|
556
561
|
// a late read never undoes a newer click.
|
|
557
|
-
|
|
562
|
+
const openInPanel = (anyway) => {
|
|
558
563
|
if (reading) return; // this card already reading: that click stays the one
|
|
559
564
|
if (P().running(key)) P().stop(key, "stopped", "");
|
|
560
565
|
const at = panel.claim(), started = P().startCount();
|
|
561
566
|
withCode((c) => {
|
|
562
567
|
if (panel.version() !== at || P().startCount() !== started) { refresh(); return; }
|
|
563
|
-
|
|
564
|
-
|
|
568
|
+
large = null; refresh();
|
|
569
|
+
panel.open({ key, instance: x.instance, msgKey: msgKey(x), ...(att ? { att } : { n: source.n }), code: c, sender: x.sender, ts: x.ts, ...(anyway ? { anyway: true } : {}) }, { run: true });
|
|
570
|
+
}, "panel", anyway);
|
|
565
571
|
};
|
|
572
|
+
if (toPanel) toPanel.onclick = () => openInPanel(false);
|
|
573
|
+
anywayB.onclick = () => { const where = large; large = null; if (where === "panel" && toPanel) openInPanel(true); else preview(true); };
|
|
566
574
|
if (dl) dl.onclick = () => opts.download(code);
|
|
567
575
|
ack.onclick = () => P().ackBanner(); // every card and the panel hear it (onChange)
|
|
568
576
|
optB.onclick = () => { menu.open = false; opts.setPreviewOptIn(!P().optedIn()); };
|
|
@@ -668,7 +676,6 @@ export function createThread(list, scroller, opts) {
|
|
|
668
676
|
function render(next, renderOpts = {}) {
|
|
669
677
|
const stick = pinned || nearBottom();
|
|
670
678
|
msgs = next || [];
|
|
671
|
-
armTrials();
|
|
672
679
|
if (!msgs.length) {
|
|
673
680
|
for (const v of nodes.values()) stopIn(v.node);
|
|
674
681
|
nodes.clear();
|
|
@@ -693,11 +700,7 @@ export function createThread(list, scroller, opts) {
|
|
|
693
700
|
}
|
|
694
701
|
/** Put the messages from startIndex() on in the list (nodes reused when unchanged). Returns how many are new. */
|
|
695
702
|
function draw(drawOpts) {
|
|
696
|
-
const shown = msgs.slice(startIndex())
|
|
697
|
-
// Volatile host offer records are hidden off and while their on-only parser is loading.
|
|
698
|
-
const hostOffer = message?.role === "status" && message.sender === "agend" && Object.hasOwn(message, "effectTrial") && message.effectTrial != null;
|
|
699
|
-
return !hostOffer || canvasWorkerEnabled() && readCanvasTrialMessage(message) !== undefined;
|
|
700
|
-
});
|
|
703
|
+
const shown = msgs.slice(startIndex());
|
|
701
704
|
const keep = new Set(shown.map(msgKey));
|
|
702
705
|
for (const [k, v] of nodes) if (!keep.has(k)) { stopIn(v.node); v.node.remove(); nodes.delete(k); }
|
|
703
706
|
let prev = null, added = 0;
|
|
@@ -711,7 +714,7 @@ export function createThread(list, scroller, opts) {
|
|
|
711
714
|
const stopped = have ? stopIn(have.node) : [];
|
|
712
715
|
const node = msgNode(html, x, stopped);
|
|
713
716
|
if (have) have.node.replaceWith(node); else added++;
|
|
714
|
-
have = { html, node, x
|
|
717
|
+
have = { html, node, x }; nodes.set(key, have);
|
|
715
718
|
} else { have.x = x; timeLabel(have.node); }
|
|
716
719
|
const want = prev ? prev.nextSibling : list.firstChild;
|
|
717
720
|
// A node already in the list is being moved: its preview stops first. A new node (still in its template) has none.
|
|
@@ -811,13 +814,6 @@ export function createThread(list, scroller, opts) {
|
|
|
811
814
|
else if (act === "replyButton") {
|
|
812
815
|
const m = /^([0-9a-f]{32}):(\d{1,2})$/.exec(el.dataset.arg || "");
|
|
813
816
|
if (m && opts.clickReplyButton) opts.clickReplyButton(m[1], Number(m[2]));
|
|
814
|
-
} else if (act === "effectTrial") {
|
|
815
|
-
// Only the current host-produced keyed card and a real local click can request admission. No token is read from DOM.
|
|
816
|
-
const key = el.dataset.arg, row = msgs.find(x => msgKey(x) === key), owner = nodes.get(key), node = owner?.node, offer = readCanvasTrialMessage(row);
|
|
817
|
-
if (PUBLIC_LINK() || e.defaultPrevented || e.isTrusted !== true || owner?.trialButton !== el || el.className !== "btn btn-sm effect-trial-start" || !node?.contains(el) || el.closest(".effect-trial-offer")?.getAttribute("data-trust") !== "thread-control"
|
|
818
|
-
|| !offer || trialNow() >= offer.expiresAt) return;
|
|
819
|
-
if (trialStatus(row) === "ready" && opts.canTryEffect?.(row) === true) opts.startEffectTrial?.(row);
|
|
820
|
-
else opts.fixEffectTrial?.(row, trialStatus(row));
|
|
821
817
|
} else if (act === "showButtons") { const x = msgs.find(y => y.buttons && y.buttons.id === el.dataset.arg); if (x) reveal(msgKey(x)); }
|
|
822
818
|
else if (act === "reply") { const x = msgs.find(y => msgKey(y) === el.dataset.arg); if (x) opts.startReply?.(x); }
|
|
823
819
|
else if (act === "jumpQuote") void jumpTo(el.dataset.arg);
|
|
@@ -841,7 +837,7 @@ export function createThread(list, scroller, opts) {
|
|
|
841
837
|
/** The thread goes (the chat left, or another instance opened): every preview in it stops first. */
|
|
842
838
|
/**
|
|
843
839
|
* #2053: kept for a later visit — the chat left as it always did (every preview stops: "leave"), but its drawn nodes
|
|
844
|
-
* stay. Nothing of it runs meanwhile: no timer (day labels, polls,
|
|
840
|
+
* stay. Nothing of it runs meanwhile: no timer (day labels, polls, filling in), no size observer; the
|
|
845
841
|
* caller drops its subscriptions. Shown again: attach, then render — only what changed is drawn.
|
|
846
842
|
*/
|
|
847
843
|
function park() {
|
|
@@ -850,7 +846,6 @@ export function createThread(list, scroller, opts) {
|
|
|
850
846
|
if (P()) P().stopAll("leave");
|
|
851
847
|
for (const node of list.querySelectorAll(".html-card[data-att], .text-card[data-att]")) { const f = cardDrop.get(node); if (f) f(); }
|
|
852
848
|
if (ro) { ro.disconnect(); ro = null; }
|
|
853
|
-
if (trialTimer !== null) clearTimeout(trialTimer); trialTimer = null;
|
|
854
849
|
if (growFrame !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(growFrame);
|
|
855
850
|
if (growTimer !== null) clearTimeout(growTimer);
|
|
856
851
|
growTimer = growFrame = null;
|
|
@@ -868,12 +863,9 @@ export function createThread(list, scroller, opts) {
|
|
|
868
863
|
if (ro) { ro.observe(list); ro.observe(sc); }
|
|
869
864
|
}
|
|
870
865
|
/** `own`: only this thread's previews stop (a thread let go while another chat is in view); else every one, as leaving. */
|
|
871
|
-
const redrawFeature = () => { if (!disposed && !parked) render(msgs); };
|
|
872
|
-
const featureOff = onCanvasWorkerChange(redrawFeature), metadataOff = onCanvasMetadataChange(redrawFeature);
|
|
873
866
|
function dispose(own = false) {
|
|
874
|
-
disposed = true;
|
|
867
|
+
disposed = true;
|
|
875
868
|
if (!parked) watchReader(scroller, false);
|
|
876
|
-
if (trialTimer !== null) clearTimeout(trialTimer); trialTimer = null;
|
|
877
869
|
if (ro) ro.disconnect();
|
|
878
870
|
if (P()) { if (own) P().stopIn(list); else P().stopAll("leave"); }
|
|
879
871
|
nodes.clear();
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
// @property {(ctx, item, active, ms, env) => void} [drawFurniture] zones: one furniture item (active: activeWhen holds)
|
|
28
28
|
// @property {(ctx, L, env) => void} [drawForeground] zones: a pack's foreground over the whole 1280×720 scene, above
|
|
29
29
|
// the people, furniture and items in the air, below the crowd counts, name tags and bubbles
|
|
30
|
-
// @property {(ctx, x, y, look, env) => void} [drawTag] zones: a name tag under feet at (x, y)
|
|
30
|
+
// @property {(ctx, x, y, look, env, compact?) => void} [drawTag] zones: a name tag under feet at (x, y) (compact: #2860)
|
|
31
31
|
// @property {(ctx, area, n, env) => void} [drawCrowd] zones: an area's "+n" (who found no spot in it)
|
|
32
32
|
// @property {(ctx, desk, look, ms, env) => void} drawCharacter the occupant in its pose at time `ms` (0: still); in
|
|
33
33
|
// zones `desk` is the character's box at its current position (its feet at desk.seat); walking, `look.heading` is
|
|
@@ -293,21 +293,44 @@ function drawBubble(ctx, x, y, text, env, lift = 0) {
|
|
|
293
293
|
/** A zones name tag's widest text (logical units): longer names are cut with an ellipsis. */
|
|
294
294
|
export const TAG_TEXT_W = 84;
|
|
295
295
|
const TAG_FONT = "600 10px system-ui, sans-serif";
|
|
296
|
+
/**
|
|
297
|
+
* #2860: the compact tag a crowded area keeps on (it used to show tags on hover only, #2513): a smaller font, a smaller
|
|
298
|
+
* plate, a shorter cut, the same level badge.
|
|
299
|
+
*/
|
|
300
|
+
const COMPACT = { font: "500 9px system-ui, sans-serif", textW: 48, pad: 6, top: 2, h: 11 };
|
|
301
|
+
const NORMAL = { font: TAG_FONT, textW: TAG_TEXT_W, pad: 10, top: 3, h: 14 };
|
|
296
302
|
/** The box a name tag under feet at (x, y) takes (what drawTag draws; bubbles keep clear of it, #2513). */
|
|
297
|
-
export function tagBox(ctx, x, y, label) {
|
|
303
|
+
export function tagBox(ctx, x, y, label, compact = false) {
|
|
304
|
+
const k = compact ? COMPACT : NORMAL;
|
|
305
|
+
ctx.save();
|
|
306
|
+
ctx.font = k.font;
|
|
307
|
+
const t = fitText(ctx, label, k.textW), w = Math.ceil((ctx.measureText ? ctx.measureText(t).width : t.length * 6) + k.pad);
|
|
308
|
+
ctx.restore();
|
|
309
|
+
return { x: Math.round(x - w / 2), y: y + k.top, w, h: k.h, text: t };
|
|
310
|
+
}
|
|
311
|
+
/** #2860: what a tag covers with its level badge: on a full tag's top-left corner (half outside); left of a compact one. */
|
|
312
|
+
export function tagFootprint(ctx, box, badge, compact = false) {
|
|
313
|
+
if (!badge) return box;
|
|
314
|
+
if (compact) { const w = badgeWidth(ctx, badge) + 1; return { x: box.x - w, y: box.y, w: box.w + w, h: box.h }; }
|
|
315
|
+
return { x: box.x - 10, y: box.y - 7, w: box.w + 10, h: box.h + 7 };
|
|
316
|
+
}
|
|
317
|
+
function badgeWidth(ctx, badge) {
|
|
318
|
+
if (badge.mark) return 8;
|
|
298
319
|
ctx.save();
|
|
299
|
-
ctx.font =
|
|
300
|
-
const
|
|
320
|
+
ctx.font = BADGE_FONT;
|
|
321
|
+
const w = Math.max(12, Math.ceil((ctx.measureText ? ctx.measureText(badge.text).width : badge.text.length * 5) + 6));
|
|
301
322
|
ctx.restore();
|
|
302
|
-
return
|
|
323
|
+
return w;
|
|
303
324
|
}
|
|
304
325
|
/**
|
|
305
326
|
* #2661: a level badge on a name tag's top-left corner (x, y: the tag's corner), overlapping its edge like an app's
|
|
306
327
|
* badge — it takes none of the tag's width. `badge`: { text, tier } (fleet-office-levels.js badgeOf), or { mark } for a
|
|
307
328
|
* pinned title that hides the number: a small diamond.
|
|
308
329
|
*/
|
|
309
|
-
export function drawBadge(ctx, x, y, badge, pal) {
|
|
330
|
+
export function drawBadge(ctx, x, y, badge, pal, inline = false) {
|
|
310
331
|
if (!badge) return;
|
|
332
|
+
// #2860 inline (a compact tag): (x, y) is the tag's left edge and middle; the badge sits just left of it, whole.
|
|
333
|
+
if (inline) { const w = badgeWidth(ctx, badge); x = x - 1 - w + (badge.mark ? w / 2 : w / 2 - 3); y = y + (badge.mark ? 0 : 1); }
|
|
311
334
|
const c = tierColours(badge.tier, pal);
|
|
312
335
|
ctx.save();
|
|
313
336
|
ctx.globalAlpha = 1;
|
|
@@ -331,18 +354,18 @@ export function drawBadge(ctx, x, y, badge, pal) {
|
|
|
331
354
|
}
|
|
332
355
|
const BADGE_FONT = "700 8px system-ui, sans-serif";
|
|
333
356
|
|
|
334
|
-
/** Zones: a name tag under someone's feet at (x, y). */
|
|
335
|
-
function drawTag(ctx, x, y, look, env) {
|
|
357
|
+
/** Zones: a name tag under someone's feet at (x, y); `compact` (#2860): the smaller one a crowded area keeps on. */
|
|
358
|
+
function drawTag(ctx, x, y, look, env, compact = false) {
|
|
336
359
|
const { pal } = env;
|
|
360
|
+
const b = tagBox(ctx, x, y, look.label, compact);
|
|
337
361
|
ctx.save();
|
|
338
362
|
if (look.dim) ctx.globalAlpha = 0.35;
|
|
339
|
-
ctx.font = TAG_FONT;
|
|
340
|
-
|
|
341
|
-
ctx.
|
|
342
|
-
ctx.
|
|
343
|
-
ctx.fillStyle = pal.text; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText(t, x, y + 10.5);
|
|
363
|
+
ctx.font = compact ? COMPACT.font : TAG_FONT;
|
|
364
|
+
ctx.fillStyle = pal.surface; ctx.fillRect(b.x, b.y, b.w, b.h);
|
|
365
|
+
ctx.strokeStyle = look.match ? pal.focus : pal.border; ctx.lineWidth = look.match ? 2 : 1; ctx.strokeRect(b.x + 0.5, b.y + 0.5, b.w - 1, b.h - 1);
|
|
366
|
+
ctx.fillStyle = pal.text; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText(b.text, x, b.y + b.h / 2 + 0.5);
|
|
344
367
|
ctx.restore();
|
|
345
|
-
if (look.badge) drawBadge(ctx,
|
|
368
|
+
if (look.badge) compact ? drawBadge(ctx, b.x, b.y + b.h / 2, look.badge, pal, true) : drawBadge(ctx, b.x, b.y, look.badge, pal);
|
|
346
369
|
}
|
|
347
370
|
|
|
348
371
|
/**
|