@songsid/agend 2.3.0-beta.8 → 2.3.0
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 +16 -8
- package/README.zh-TW.md +16 -8
- package/dist/adapter-world.js.map +1 -1
- package/dist/agend-home.d.ts +5 -0
- package/dist/agend-home.js +7 -0
- package/dist/agend-home.js.map +1 -0
- package/dist/agent-cli-instructions.md +9 -2
- package/dist/agent-cli.js +44 -0
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +9 -0
- package/dist/agent-endpoint.js +23 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.js +1 -1
- package/dist/agent-file-read.js.map +1 -1
- package/dist/agent-whats-new.d.ts +16 -0
- package/dist/agent-whats-new.js +54 -11
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/apply-job.js.map +1 -1
- package/dist/atomic-write.js.map +1 -1
- package/dist/auth-api.d.ts +12 -0
- package/dist/auth-api.js +77 -22
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/authority-state.d.ts +4 -0
- package/dist/authority/authority-state.js +17 -8
- package/dist/authority/authority-state.js.map +1 -1
- package/dist/authority/session-authorizations.js.map +1 -1
- package/dist/authority/web-authority.d.ts +16 -8
- package/dist/authority/web-authority.js +19 -5
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/antigravity.d.ts +2 -2
- package/dist/backend/antigravity.js +2 -1
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.js +13 -4
- 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-package.d.ts +30 -0
- package/dist/backend/codex-package.js +133 -0
- package/dist/backend/codex-package.js.map +1 -0
- package/dist/backend/codex-session-lookup.js.map +1 -1
- package/dist/backend/codex.d.ts +2 -0
- package/dist/backend/codex.js +25 -5
- 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/effort-metadata.js.map +1 -1
- package/dist/backend/grok.js +58 -3
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro-engine-ledger.js.map +1 -1
- package/dist/backend/kiro-kas-store.js.map +1 -1
- package/dist/backend/kiro-v2-store.js.map +1 -1
- package/dist/backend/kiro-v3-identity.js.map +1 -1
- package/dist/backend/kiro.d.ts +9 -1
- package/dist/backend/kiro.js +102 -1
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/launch-effort.js.map +1 -1
- package/dist/backend/mock.js.map +1 -1
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/opencode-permission.js +1 -1
- package/dist/backend/opencode-permission.js.map +1 -1
- package/dist/backend/opencode.js +2 -1
- package/dist/backend/opencode.js.map +1 -1
- package/dist/backend/session-signals.js.map +1 -1
- package/dist/backend-availability.js.map +1 -1
- package/dist/backend-command.d.ts +2 -0
- package/dist/backend-command.js +3 -1
- package/dist/backend-command.js.map +1 -1
- package/dist/backend-outage.js.map +1 -1
- package/dist/binary-probe.js +1 -1
- package/dist/binary-probe.js.map +1 -1
- package/dist/bug-report-cli.d.ts +30 -0
- package/dist/bug-report-cli.js +139 -0
- package/dist/bug-report-cli.js.map +1 -0
- package/dist/bug-report.d.ts +47 -0
- package/dist/bug-report.js +137 -0
- package/dist/bug-report.js.map +1 -0
- package/dist/bundled-skills.d.ts +18 -0
- package/dist/bundled-skills.js +38 -0
- package/dist/bundled-skills.js.map +1 -0
- package/dist/cache-service.js +1 -1
- 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 +4 -0
- package/dist/channel/adapters/discord.js +57 -12
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +6 -0
- package/dist/channel/adapters/telegram.js +54 -14
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-server.js +21 -4
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +3 -1
- package/dist/channel/mcp-tools.js +43 -6
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/message-queue.js.map +1 -1
- package/dist/channel/sticker-download.js.map +1 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/child-process.d.ts +21 -0
- package/dist/child-process.js +54 -0
- package/dist/child-process.js.map +1 -0
- package/dist/classic-channel-manager.js +3 -2
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli-entry.js.map +1 -1
- package/dist/cli-flags.js.map +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +443 -311
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +1 -1
- package/dist/command-table.js +1 -1
- package/dist/command-table.js.map +1 -1
- package/dist/compact-watch.js.map +1 -1
- package/dist/completion-install.js.map +1 -1
- package/dist/completion.js.map +1 -1
- package/dist/config-validator.d.ts +6 -0
- package/dist/config-validator.js +81 -8
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +15 -3
- package/dist/config.js +41 -10
- package/dist/config.js.map +1 -1
- package/dist/connection-secrets.js.map +1 -1
- package/dist/context-guardian.js.map +1 -1
- package/dist/coredump-filter.js.map +1 -1
- package/dist/cpu-profile.js.map +1 -1
- package/dist/cross-instance-envelope.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 +39 -1
- package/dist/daemon.js +234 -15
- package/dist/daemon.js.map +1 -1
- package/dist/daily-summary.js.map +1 -1
- package/dist/darwin-memory.js +1 -1
- package/dist/darwin-memory.js.map +1 -1
- package/dist/dashboard-live.d.ts +8 -0
- package/dist/dashboard-live.js +35 -0
- package/dist/dashboard-live.js.map +1 -0
- package/dist/dashboard-permissions.d.ts +69 -0
- package/dist/dashboard-permissions.js +138 -0
- package/dist/dashboard-permissions.js.map +1 -0
- 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-consumed-watch.js.map +1 -1
- package/dist/delivery-outbox.js +5 -0
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-outbox.test.js.map +1 -1
- package/dist/delivery-reconciliation.test.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/doctor.d.ts +8 -0
- package/dist/doctor.js +52 -0
- package/dist/doctor.js.map +1 -1
- package/dist/e2e-isolation.js.map +1 -1
- package/dist/event-log.js.map +1 -1
- package/dist/export-import.js +7 -5
- package/dist/export-import.js.map +1 -1
- package/dist/fleet-control-audit.js.map +1 -1
- package/dist/fleet-label.js.map +1 -1
- package/dist/fleet-level-config.d.ts +1 -1
- package/dist/fleet-level-config.js +2 -0
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-lock.js +3 -2
- package/dist/fleet-lock.js.map +1 -1
- package/dist/fleet-manager.d.ts +258 -15
- package/dist/fleet-manager.js +1605 -304
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +18 -0
- package/dist/fleet-process-handlers.js +70 -0
- package/dist/fleet-process-handlers.js.map +1 -0
- package/dist/fleet-startup.d.ts +14 -0
- package/dist/fleet-startup.js +30 -0
- package/dist/fleet-startup.js.map +1 -0
- package/dist/fleet-traffic.d.ts +36 -0
- package/dist/fleet-traffic.js +100 -0
- package/dist/fleet-traffic.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +0 -20
- package/dist/forged-envelope-scan.js +3 -2
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/full-restart.d.ts +5 -5
- package/dist/full-restart.js +5 -5
- package/dist/full-restart.js.map +1 -1
- package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +52 -11
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +5 -1
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +3 -1
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
- 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.canvas-worker-off.md +321 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +28 -4
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +553 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +170 -35
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/general-knowledge/steering/core-rules.md +1 -1
- package/dist/host-memory.js.map +1 -1
- package/dist/idle-gate-log.d.ts +19 -0
- package/dist/idle-gate-log.js +15 -0
- package/dist/idle-gate-log.js.map +1 -0
- package/dist/instance-config-impact.js +25 -4
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +10 -1
- package/dist/instance-lifecycle.js +86 -25
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +12 -6
- package/dist/instructions.js +19 -10
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-compact-pane.js.map +1 -1
- package/dist/kiro-db-reader.js.map +1 -1
- package/dist/kiro-engine-status.js.map +1 -1
- package/dist/kiro-log-gate.js.map +1 -1
- package/dist/kiro-transcript-lane.js.map +1 -1
- package/dist/locale.js +428 -20
- package/dist/locale.js.map +1 -1
- package/dist/log-service.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/logger.js +3 -2
- package/dist/logger.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/login-flows.js +1 -1
- package/dist/login-manager.js.map +1 -1
- package/dist/login-shell.js +3 -1
- package/dist/login-shell.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 +83 -4
- package/dist/ls-rows.js.map +1 -1
- package/dist/memory-pressure.js.map +1 -1
- package/dist/muse-usage-relay.js.map +1 -1
- package/dist/needs-you-hub.d.ts +98 -1
- package/dist/needs-you-hub.js +313 -44
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +5 -2
- package/dist/needs-you-live.js +6 -3
- package/dist/needs-you-live.js.map +1 -1
- package/dist/needs-you.d.ts +68 -3
- package/dist/needs-you.js +38 -4
- package/dist/needs-you.js.map +1 -1
- package/dist/network-family.js.map +1 -1
- package/dist/operator-control-paths.js +3 -4
- package/dist/operator-control-paths.js.map +1 -1
- package/dist/outbound-handlers.d.ts +3 -0
- package/dist/outbound-handlers.js +76 -19
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +112 -64
- package/dist/outbound-schemas.js +39 -12
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/outbox-open-error.js.map +1 -1
- package/dist/pane-context-cache.js.map +1 -1
- package/dist/paths.js.map +1 -1
- package/dist/private-dir.js.map +1 -1
- package/dist/probe-worker-pool.js.map +1 -1
- package/dist/profile-control.js.map +1 -1
- package/dist/prompt-file-ref.js.map +1 -1
- package/dist/provider-probe.js.map +1 -1
- package/dist/provider-secret-registry.d.ts +5 -3
- package/dist/provider-secret-registry.js +8 -2
- package/dist/provider-secret-registry.js.map +1 -1
- package/dist/public-link-auto-open.d.ts +32 -0
- package/dist/public-link-auto-open.js +86 -0
- package/dist/public-link-auto-open.js.map +1 -0
- package/dist/public-link-owner.d.ts +10 -0
- package/dist/public-link-owner.js +36 -0
- package/dist/public-link-owner.js.map +1 -0
- package/dist/public-link-progress.d.ts +12 -1
- package/dist/public-link-progress.js +5 -10
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-preview.js.map +1 -1
- package/dist/public-tunnel-config.d.ts +11 -0
- package/dist/public-tunnel-config.js +68 -0
- package/dist/public-tunnel-config.js.map +1 -0
- package/dist/public-web-gateway.d.ts +2 -0
- package/dist/public-web-gateway.js +19 -6
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +48 -3
- package/dist/public-web-link.js +177 -51
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.d.ts +9 -0
- package/dist/quickstart-api.js +82 -0
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +5 -0
- package/dist/quickstart.js +40 -25
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/reply-dedup.js.map +1 -1
- package/dist/resource-report.js +1 -1
- package/dist/resource-report.js.map +1 -1
- package/dist/restart-guard.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.js.map +1 -1
- package/dist/runtime-cpu-profile.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/scheduler.js.map +1 -1
- package/dist/scheduler/task-board-text.d.ts +26 -0
- package/dist/scheduler/task-board-text.js +140 -0
- package/dist/scheduler/task-board-text.js.map +1 -0
- package/dist/scheduler/task-board.d.ts +730 -0
- package/dist/scheduler/task-board.js +2179 -0
- package/dist/scheduler/task-board.js.map +1 -0
- package/dist/scheduler/types.d.ts +6 -1
- package/dist/sd-notify.js +2 -1
- package/dist/sd-notify.js.map +1 -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/secret-file.js.map +1 -1
- package/dist/secret-store.d.ts +2 -0
- package/dist/secret-store.js +21 -0
- package/dist/secret-store.js.map +1 -1
- package/dist/service-installer.d.ts +75 -0
- package/dist/service-installer.js +206 -0
- package/dist/service-installer.js.map +1 -1
- package/dist/service-owner.d.ts +44 -0
- package/dist/service-owner.js +48 -0
- package/dist/service-owner.js.map +1 -0
- package/dist/service-plan.d.ts +39 -2
- package/dist/service-plan.js +188 -6
- package/dist/service-plan.js.map +1 -1
- package/dist/session-oom.d.ts +21 -0
- package/dist/session-oom.js +139 -0
- package/dist/session-oom.js.map +1 -0
- package/dist/settings-api.d.ts +13 -0
- package/dist/settings-api.js +73 -12
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-baseline.js.map +1 -1
- package/dist/settings-change.d.ts +5 -0
- package/dist/settings-change.js +167 -6
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +9 -1
- package/dist/settings-confirmation.js +18 -8
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-control.js +2 -1
- package/dist/settings-control.js.map +1 -1
- package/dist/settings-effect.js +29 -4
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +13 -0
- package/dist/settings-http-confirmation.js +15 -3
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/settings-instance-patch.js +13 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/settings-request-capability.d.ts +4 -1
- package/dist/settings-request-capability.js +11 -3
- package/dist/settings-request-capability.js.map +1 -1
- package/dist/settings-transaction.js.map +1 -1
- package/dist/setup-auth.d.ts +1 -0
- package/dist/setup-auth.js +2 -1
- package/dist/setup-auth.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/setup-host.d.ts +6 -1
- package/dist/setup-host.js +15 -4
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +6 -3
- package/dist/setup-wizard.js.map +1 -1
- package/dist/spawn-gate.d.ts +5 -0
- package/dist/spawn-gate.js +28 -8
- package/dist/spawn-gate.js.map +1 -1
- package/dist/start-attempt.d.ts +1 -0
- package/dist/start-attempt.js +18 -0
- package/dist/start-attempt.js.map +1 -0
- package/dist/start-failure-notice.d.ts +4 -0
- package/dist/start-failure-notice.js +20 -0
- package/dist/start-failure-notice.js.map +1 -0
- package/dist/start-failure.d.ts +147 -0
- package/dist/start-failure.js +281 -0
- package/dist/start-failure.js.map +1 -0
- package/dist/startup-memory-deadline.d.ts +23 -0
- package/dist/startup-memory-deadline.js +55 -0
- package/dist/startup-memory-deadline.js.map +1 -0
- package/dist/statusline-watcher.js.map +1 -1
- package/dist/storm-window.js.map +1 -1
- package/dist/systemd-peer-bus.js.map +1 -1
- package/dist/target-queue-worker.js.map +1 -1
- package/dist/task-board-summary.d.ts +101 -0
- package/dist/task-board-summary.js +177 -0
- package/dist/task-board-summary.js.map +1 -0
- package/dist/task-board-tool.d.ts +25 -0
- package/dist/task-board-tool.js +155 -0
- package/dist/task-board-tool.js.map +1 -0
- package/dist/task-board-waker.d.ts +51 -0
- package/dist/task-board-waker.js +141 -0
- package/dist/task-board-waker.js.map +1 -0
- package/dist/tips.js.map +1 -1
- package/dist/tmux-control.js +1 -1
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-exec-helper.d.ts +104 -0
- package/dist/tmux-exec-helper.js +412 -0
- package/dist/tmux-exec-helper.js.map +1 -0
- package/dist/tmux-manager.d.ts +1 -0
- package/dist/tmux-manager.js +29 -13
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-read.js +2 -2
- package/dist/tmux-read.js.map +1 -1
- package/dist/tool-permissions.js +9 -42
- package/dist/tool-permissions.js.map +1 -1
- package/dist/tool-progress.js.map +1 -1
- package/dist/topic-archiver.js.map +1 -1
- package/dist/topic-commands.d.ts +13 -0
- package/dist/topic-commands.js +56 -33
- package/dist/topic-commands.js.map +1 -1
- package/dist/topic-link.js.map +1 -1
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/transcript-jsonl.js.map +1 -1
- package/dist/transcript-monitor.js +5 -0
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +2 -0
- package/dist/transcript-sources.js +4 -0
- package/dist/transcript-sources.js.map +1 -1
- package/dist/tunnel/cloudflared-install.js +3 -1
- package/dist/tunnel/cloudflared-install.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +7 -16
- package/dist/tunnel/cloudflared.js +100 -13
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/lease.js +3 -2
- package/dist/tunnel/lease.js.map +1 -1
- package/dist/tunnel/manager.js.map +1 -1
- package/dist/tunnel/named-diagnostics.d.ts +13 -0
- package/dist/tunnel/named-diagnostics.js +52 -0
- package/dist/tunnel/named-diagnostics.js.map +1 -0
- package/dist/tunnel/public-fetch.js.map +1 -1
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/tunnel/types.d.ts +4 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/types.d.ts +55 -2
- package/dist/ui/app-effects.js +27 -5
- package/dist/ui/app.html +2 -0
- package/dist/ui/backend-signin.js +297 -0
- package/dist/ui/chat-effects.js +15 -7
- package/dist/ui/chat-msg-actions.js +176 -0
- package/dist/ui/chat-render.js +67 -20
- package/dist/ui/chat-store.js +218 -48
- package/dist/ui/chat-strings.js +42 -10
- package/dist/ui/chat-thread.js +249 -23
- package/dist/ui/effect-trial-controller.js +13 -8
- package/dist/ui/effect-trial-offer.js +2 -31
- package/dist/ui/effects-waker.js +2 -0
- package/dist/ui/fleet-canvas-layout.js +13 -4
- package/dist/ui/fleet-canvas.js +120 -43
- package/dist/ui/fleet-office-editor.js +149 -0
- package/dist/ui/fleet-office-model.js +358 -0
- package/dist/ui/fleet-office-pack.js +199 -0
- package/dist/ui/fleet-office-skin.js +474 -0
- package/dist/ui/fleet-office-store.js +49 -0
- package/dist/ui/fleet-office-zones.js +177 -0
- package/dist/ui/fleet-office.js +434 -0
- package/dist/ui/fleet-org.js +21 -8
- package/dist/ui/fleet-route-scene.js +272 -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 +482 -0
- package/dist/ui/fleet-task-work.js +107 -0
- package/dist/ui/fleet-tasks.js +569 -0
- package/dist/ui/fleet-traffic.js +227 -45
- package/dist/ui/fleet-usage.js +36 -2
- package/dist/ui/guest-refused.html +41 -0
- package/dist/ui/icons/icon-192.png +0 -0
- package/dist/ui/icons/icon-512.png +0 -0
- package/dist/ui/image-lightbox.js +45 -1
- package/dist/ui/image-zoom.js +242 -0
- package/dist/ui/panel-chat.js +282 -89
- package/dist/ui/panel-details.js +2 -0
- package/dist/ui/panel-fleet.js +32 -71
- package/dist/ui/panel-needs.js +23 -6
- package/dist/ui/panel-settings.js +158 -32
- package/dist/ui/preview-panel.js +2 -1
- package/dist/ui/search-dialog.js +350 -0
- package/dist/ui/settings-appearance.js +170 -10
- package/dist/ui/settings-apply.js +3 -3
- package/dist/ui/settings-confirm.js +7 -2
- package/dist/ui/settings-dialogs.js +46 -21
- package/dist/ui/settings-discord.js +6 -2
- package/dist/ui/settings-guests.js +2 -1
- package/dist/ui/settings-learn.js +1 -0
- package/dist/ui/settings-model.js +51 -18
- package/dist/ui/settings-mods.js +8 -3
- package/dist/ui/settings-owner-effects.js +6 -4
- package/dist/ui/settings-strings.js +180 -6
- package/dist/ui/settings-token.js +3 -1
- package/dist/ui/settings-web-authority.js +13 -5
- package/dist/ui/settings-wizard.js +13 -7
- package/dist/ui/shared/agend-auth.js +3 -1
- package/dist/ui/shared/app-i18n.js +12 -5
- package/dist/ui/shared/app-needs.js +2 -2
- package/dist/ui/shared/app-prefs.js +15 -0
- package/dist/ui/shared/app-route.js +18 -0
- package/dist/ui/shared/app-shell.js +172 -28
- package/dist/ui/shared/app-store.js +3 -2
- package/dist/ui/shared/app-stream.js +7 -2
- package/dist/ui/shared/app-themes.js +116 -1
- package/dist/ui/shared/app.css +681 -54
- package/dist/ui/shared/app.js +9 -1
- package/dist/ui/shared/card-strings.js +4 -0
- package/dist/ui/shared/effect-app-runtime.js +7 -5
- package/dist/ui/shared/effect-chat-runtime.js +2 -7
- package/dist/ui/shared/effect-cursor.js +3 -2
- package/dist/ui/shared/effect-display-metadata.js +39 -0
- package/dist/ui/shared/effect-owner-source.js +8 -1
- package/dist/ui/shared/effect-policy.js +2 -2
- package/dist/ui/shared/effect-registry.js +30 -11
- package/dist/ui/shared/effect-runtime-loader.js +3 -1
- package/dist/ui/shared/effect-stock-snapshot.js +9 -0
- package/dist/ui/shared/effect-stock-trust.js +40 -9
- package/dist/ui/shared/effect-trial-source.js +1 -1
- package/dist/ui/shared/effect-trial-stage.js +27 -21
- package/dist/ui/shared/effect-trial.css +1 -1
- package/dist/ui/shared/feature-flags.js +127 -0
- package/dist/ui/shared/guest-refused.js +35 -0
- package/dist/ui/shared/header-tools.js +2 -2
- package/dist/ui/shared/identity-card.js +26 -8
- package/dist/ui/shared/identity-color.js +17 -10
- package/dist/ui/shared/instance-nav.js +183 -28
- package/dist/ui/shared/owner-css.js +30 -1
- package/dist/ui/shared/panel-view.js +14 -29
- package/dist/ui/shared/text-undo.js +210 -0
- package/dist/ui/shared/tokens.css +13 -3
- package/dist/ui/shared/ui-dialog.js +5 -4
- package/dist/ui/shared/ui-icons.js +4 -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 +206 -16
- package/dist/ui/shared/view-strings.js +68 -4
- package/dist/ui/shared/web-authorize.js +50 -1
- package/dist/ui/signin.html +2 -0
- package/dist/ui/web-terminal/terminal.css +4 -4
- package/dist/ui/web-terminal/terminal.html +10 -10
- package/dist/ui/web-terminal/terminal.js +58 -12
- package/dist/update-check.js.map +1 -1
- package/dist/update-dispatch.js +1 -1
- package/dist/update-dispatch.js.map +1 -1
- package/dist/update-install.js.map +1 -1
- package/dist/update-launch.d.ts +10 -1
- package/dist/update-launch.js +39 -14
- package/dist/update-launch.js.map +1 -1
- package/dist/update-marker.js.map +1 -1
- package/dist/update-preflight.js +1 -1
- package/dist/update-preflight.js.map +1 -1
- package/dist/update-progress.d.ts +3 -1
- package/dist/update-progress.js +3 -1
- package/dist/update-progress.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 +89 -2
- package/dist/usage/providers.js +247 -41
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/statusline-usage.js.map +1 -1
- package/dist/usage/usage-api.d.ts +5 -1
- package/dist/usage/usage-api.js +185 -58
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/usage-report.js.map +1 -1
- package/dist/usage-rollup.js +1 -1
- package/dist/usage-rollup.js.map +1 -1
- 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 +7 -0
- package/dist/view-api.js +16 -4
- package/dist/view-api.js.map +1 -1
- package/dist/wake-coordinator.js.map +1 -1
- package/dist/web-ambient.js +9 -2
- package/dist/web-ambient.js.map +1 -1
- package/dist/web-api.d.ts +58 -10
- package/dist/web-api.js +1104 -71
- package/dist/web-api.js.map +1 -1
- package/dist/web-app-icon-worker.d.ts +1 -0
- package/dist/web-app-icon-worker.js +16 -0
- package/dist/web-app-icon-worker.js.map +1 -0
- package/dist/web-app-icon.d.ts +109 -0
- package/dist/web-app-icon.js +257 -0
- package/dist/web-app-icon.js.map +1 -0
- package/dist/web-appearance-policy.js.map +1 -1
- package/dist/web-appearance-tools.d.ts +1 -0
- package/dist/web-appearance-tools.js +7 -3
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-appearance.d.ts +4 -10
- package/dist/web-appearance.js +7 -4
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-auth.d.ts +8 -4
- package/dist/web-auth.js +33 -21
- 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.js.map +1 -1
- package/dist/web-channel-echo.js.map +1 -1
- package/dist/web-chat-history.d.ts +118 -8
- package/dist/web-chat-history.js +220 -25
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +5 -1
- package/dist/web-commands.js +1 -1
- package/dist/web-commands.js.map +1 -1
- package/dist/web-cookie-names.d.ts +5 -0
- package/dist/web-cookie-names.js +12 -0
- package/dist/web-cookie-names.js.map +1 -0
- package/dist/web-effect-bundle.d.ts +2 -2
- package/dist/web-effect-library.js.map +1 -1
- package/dist/web-effect-playback.js.map +1 -1
- package/dist/web-effect-profiles.d.ts +16 -16
- package/dist/web-effect-profiles.js +3 -2
- package/dist/web-effect-profiles.js.map +1 -1
- package/dist/web-effect-service.js.map +1 -1
- package/dist/web-effect-tools.js.map +1 -1
- package/dist/web-effect-trials.js.map +1 -1
- package/dist/web-effect-upload.js.map +1 -1
- package/dist/web-effect.d.ts +6 -6
- package/dist/web-effect.js.map +1 -1
- package/dist/web-experimental-http.d.ts +2 -0
- package/dist/web-experimental-http.js +12 -0
- package/dist/web-experimental-http.js.map +1 -0
- package/dist/web-experimental.d.ts +11 -0
- package/dist/web-experimental.js +49 -0
- package/dist/web-experimental.js.map +1 -0
- package/dist/web-guest-access.d.ts +4 -2
- package/dist/web-guest-access.js +22 -10
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-guest-rooms.js.map +1 -1
- 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-icons.d.ts +33 -1
- package/dist/web-icons.js +83 -11
- package/dist/web-icons.js.map +1 -1
- package/dist/web-identity-color.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-images.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.js.map +1 -1
- package/dist/web-mentions.js.map +1 -1
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-mod-store.d.ts +2 -0
- package/dist/web-mod-store.js +10 -0
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-office-store.d.ts +104 -0
- package/dist/web-office-store.js +236 -0
- package/dist/web-office-store.js.map +1 -0
- 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-owner-css.js.map +1 -1
- package/dist/web-png.d.ts +33 -0
- package/dist/web-png.js +329 -0
- package/dist/web-png.js.map +1 -0
- package/dist/web-prefs.d.ts +6 -0
- package/dist/web-prefs.js +29 -3
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +2 -0
- package/dist/web-preview.js +2 -0
- package/dist/web-preview.js.map +1 -1
- package/dist/web-profile.js.map +1 -1
- package/dist/web-reactions.d.ts +35 -0
- package/dist/web-reactions.js +47 -0
- package/dist/web-reactions.js.map +1 -0
- package/dist/web-request-context.d.ts +5 -0
- package/dist/web-request-context.js.map +1 -1
- package/dist/web-returning-device.d.ts +4 -2
- package/dist/web-returning-device.js +13 -6
- package/dist/web-returning-device.js.map +1 -1
- package/dist/web-schedules.js.map +1 -1
- package/dist/web-send-dedupe.d.ts +36 -0
- package/dist/web-send-dedupe.js +69 -0
- package/dist/web-send-dedupe.js.map +1 -0
- package/dist/web-session-authorization.js.map +1 -1
- package/dist/web-session.js +1 -1
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +3 -1
- package/dist/web-settings-patch.js +11 -5
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +6 -0
- package/dist/web-settings-tools.js +52 -17
- package/dist/web-settings-tools.js.map +1 -1
- package/dist/web-terminal-http.js +15 -2
- package/dist/web-terminal-http.js.map +1 -1
- package/dist/web-terminal.js +1 -1
- package/dist/web-terminal.js.map +1 -1
- package/dist/web-theme-store.d.ts +2 -2
- package/dist/web-theme-store.js +6 -3
- package/dist/web-theme-store.js.map +1 -1
- package/dist/web-theme.d.ts +29 -0
- package/dist/web-theme.js +89 -1
- package/dist/web-theme.js.map +1 -1
- package/dist/web-upload.d.ts +18 -1
- package/dist/web-upload.js +45 -7
- package/dist/web-upload.js.map +1 -1
- package/dist/web-widget.js.map +1 -1
- package/dist/webhook-emitter.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/ws-server.js.map +1 -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 +828 -0
- package/launcher/install-admission.cjs +4 -39
- package/launcher/postinstall.cjs +14 -12
- package/launcher/private-home.cjs +43 -0
- package/package.json +16 -13
- package/scripts/preinstall-guard.cjs +2 -5
- package/templates/windows-shortcuts.ps1 +181 -0
- package/launcher/old-updater-note.cjs +0 -48
package/dist/ui/chat-strings.js
CHANGED
|
@@ -3,6 +3,20 @@ import { register } from "/assets/app-i18n.js";
|
|
|
3
3
|
|
|
4
4
|
register("chat", {
|
|
5
5
|
en: {
|
|
6
|
+
waking: "Waking {0}…", retrySend: "Retry send",
|
|
7
|
+
// A message being sent (its own bubble at once) and its files' uploads.
|
|
8
|
+
you: "You", sending: "Sending…", uploadingFile: "Uploading {0}", uploadWaiting: "waiting", uploadFailed: "failed",
|
|
9
|
+
uploadNoConnection: "the upload was cut off — check the connection", sendNoConnection: "it did not reach AgEnD — check the connection", notSentBecause: "Not sent: {0}", deleteUnsent: "Delete",
|
|
10
|
+
sendFailure_wake_capacity: "No slot is free to wake this instance. Retry when another instance is idle.",
|
|
11
|
+
sendFailure_wake_credentials: "The instance could not sign in. Check its account on the host, then retry.",
|
|
12
|
+
sendFailure_wake_timeout: "The instance did not become ready in time. Retry, or check its status on the host.",
|
|
13
|
+
sendFailure_instance_stopped: "This instance was stopped or removed. Start it on the host before retrying.",
|
|
14
|
+
sendFailure_delivery_unavailable: "The instance could not receive this message. Check its status on the host, then retry.",
|
|
15
|
+
sendFailure_delivery_changed: "The session or instance changed before this message was sent. Sign in again if needed, then retry.",
|
|
16
|
+
sendFailure_reply_gone: "The message you replied to is no longer in this chat. Your text is still here: send it without the reply, or reply to another message.",
|
|
17
|
+
reply: "Reply", replyingTo: "Replying to {0}", replyCancel: "Cancel the reply (Esc)", replyHidden: "an earlier message", replyPhoto: "[Photo]", replyFile: "[File]",
|
|
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
|
+
|
|
6
20
|
effectTrialReason_checking: "Checking this session…",
|
|
7
21
|
effectTrialReason_localAdmin: "Sign in as an admin outside the public link to Try.",
|
|
8
22
|
effectTrialReason_chatChanged: "Open the chat that offered this trial.",
|
|
@@ -21,13 +35,13 @@ register("chat", {
|
|
|
21
35
|
effectTrialSettings: "Open playback settings",
|
|
22
36
|
effectTrialPlayMotion: "Play effects anyway",
|
|
23
37
|
effectTrial: "Effect trial", effectTrialLocal: "A sample on this page. Nothing is applied or saved.",
|
|
24
|
-
effectTrialStart: "Try", effectTrialExpired: "This trial offer has expired.", effectTrialUnavailable: "This trial is no longer available.",
|
|
38
|
+
effectTrialStopped: "Try stopped", effectTrialStart: "Try", effectTrialExpired: "This trial offer has expired.", effectTrialUnavailable: "This trial is no longer available.",
|
|
25
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",
|
|
26
40
|
compactRunning: "Compacting…", compactDone: "✅ Conversation compacted", compactUnknown: "This backend does not report when compaction ends.",
|
|
27
41
|
compactTimeout: "No sign that compaction finished within {0} minutes — check the agent's own chat.",
|
|
28
42
|
compactLost: "Can't follow this compaction: the command did not reach the agent, or the agent stopped or changed backend.",
|
|
29
43
|
compactNotCompacted: "kiro did not compact the conversation: it was too short, or the compaction was stopped.",
|
|
30
|
-
cmdChoose: "Choose", cmdCurrent: "current", chipCompact: "Compact", chipClear: "Clear…", chipContext: "Context {0}% used",
|
|
44
|
+
cmdChoose: "Choose", cmdCurrent: "current", cmdSignIn: "Sign in", cmdSignInTo: "Sign in to {0}", chipCompact: "Compact", chipClear: "Clear…", chipContext: "Context {0}% used",
|
|
31
45
|
chipModel: "Model: {0} — choose another", chipEffort: "Effort: {0} — choose another",
|
|
32
46
|
cmd_ctx: "Context use, model and effort", cmd_compact: "Compact the conversation", cmd_clear: "Clear the conversation (asks first)",
|
|
33
47
|
cmd_model: "Show or switch the model", cmd_backend: "Switch the CLI backend, then model and effort (restarts)", cmd_effort: "Show or set the reasoning effort", cmd_cancel: "Stop the current reply",
|
|
@@ -42,7 +56,7 @@ register("chat", {
|
|
|
42
56
|
a11yWorking: "{0} started working", a11yIdle: "{0} finished", a11yReplied: "{0} replied", conversationWith: "Conversation with {0}",
|
|
43
57
|
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)",
|
|
44
58
|
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",
|
|
45
|
-
send: "Send", composerPlaceholder: "Message {0}…", composerHint: "Enter to send · Shift+Enter for a new line", composerMore: "/ for commands · Esc stops the reply", guestMore: "Esc stops the reply",
|
|
59
|
+
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",
|
|
46
60
|
guestNote: "You're a guest: the agent sees your messages as a guest's (recognition only).", guestNoCommands: "Guests can't run commands — send it without the leading /.", attachTitle: "Attach files (any type — or paste / drop them)",
|
|
47
61
|
pvPreview: "Preview", pvStop: "Stop", pvDownload: "Download", pvMenu: "Preview options", pvHtml: "HTML",
|
|
48
62
|
pvAllowButton: "Allow previews", pvAllow: "Allow HTML previews — they may be able to send data out", pvDisallow: "Stop allowing HTML previews",
|
|
@@ -61,6 +75,8 @@ register("chat", {
|
|
|
61
75
|
pvPage: "Page", pvCode: "Code", pvReload: "Reload", pvClose: "Close the panel", pvBack: "Back to the chat", pvResize: "Resize the preview panel",
|
|
62
76
|
pvNewer: "A newer version is in the reply from {0}.", pvNewerShow: "Show it", pvPanelIdle: "Click Preview to run it here.",
|
|
63
77
|
lbLabel: "Image: {0}", lbLabelNoName: "Image", lbClose: "Close", lbOpenOriginal: "Open original", lbPrev: "Previous image", lbNext: "Next image", lbCount: "{0} / {1}",
|
|
78
|
+
// #2333: zoom in the lightbox.
|
|
79
|
+
lbZoomIn: "Zoom in (+)", lbZoomOut: "Zoom out (−)", lbZoomLevel: "{0}% — click for fit or actual size (0 / 1)", lbFitWidth: "Fit width (W)",
|
|
64
80
|
// #1554: preview.js's words (its English is the fallback there), and the server's reasons by code.
|
|
65
81
|
pvWhyOptin: "HTML previews are off. Allow them from this card's ⋯ menu or Settings → Preferences.",
|
|
66
82
|
pvWhyOptinPanel: "HTML previews are off.",
|
|
@@ -94,10 +110,10 @@ register("chat", {
|
|
|
94
110
|
previews: "Allow HTML previews",
|
|
95
111
|
clicked: "Clicked:", clickShow: "Show the message these buttons were on",
|
|
96
112
|
copy: "Copy", copyMessage: "Copy this reply", copied: "Copied", copyFailed: "Copy failed", wrap: "Wrap", showAll: "Show all {0} lines", showMore: "Show more", showLess: "Show less", jumpLatest: "Latest", newBelow: "{0} new",
|
|
97
|
-
disconnected: "disconnected", tick_queued: "Waiting behind another message", tick_processing: "Handed to the agent", tick_delivered: "The agent has it", tick_failed: "Not delivered", tick_cancelled: "Dropped by Stop",
|
|
113
|
+
disconnected: "disconnected", tick_queued: "Waiting behind another message", tick_processing: "Handed to the agent", tick_delivered: "The agent has it", tick_failed: "Not delivered", tick_cancelled: "Dropped by Stop", reactedBy: "{0} reacted",
|
|
98
114
|
promptAnswering: "Answering…", promptGone: "This prompt is no longer open", promptFor: "{0}: {1}",
|
|
99
115
|
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",
|
|
100
|
-
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",
|
|
116
|
+
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",
|
|
101
117
|
noMessages: "Type a task below.",
|
|
102
118
|
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",
|
|
103
119
|
details: "Instance details", start: "Start instance", stopInstance: "Stop instance", restart: "Restart instance", delete: "Delete instance…",
|
|
@@ -114,6 +130,7 @@ register("chat", {
|
|
|
114
130
|
dNoActivity: "No activity in the last hour.", dWorking: "Working…",
|
|
115
131
|
// #1629: a person's control over an agent's own web theme.
|
|
116
132
|
themeLock: "Lock theme", themeUnlock: "Unlock theme", themeReset: "Reset theme…", themeResetGo: "Reset",
|
|
133
|
+
pageColours: "Page colours", pageAgentOn: "The agent's choice (on)", pageAgentOff: "The agent's choice (off)", pageWhole: "On the whole page", pageChatOnly: "Only its chat",
|
|
117
134
|
themeResetConfirm: "Reset {0}'s theme to the default? Its colours, picture and working label go; a lock stays.",
|
|
118
135
|
themeResetDone: "{0}'s theme was reset.", themeLocked: "{0}'s theme is locked: the agent can't change it.", themeUnlocked: "{0}'s theme is unlocked.",
|
|
119
136
|
themeFailed: "The theme was not changed ({0}).",
|
|
@@ -128,6 +145,19 @@ register("chat", {
|
|
|
128
145
|
configured: "(configured)", fleetDefault: "(fleet default)",
|
|
129
146
|
},
|
|
130
147
|
"zh-TW": {
|
|
148
|
+
waking: "正在喚醒 {0}…", retrySend: "重試傳送",
|
|
149
|
+
you: "你", sending: "傳送中…", uploadingFile: "正在上傳 {0}", uploadWaiting: "等待中", uploadFailed: "失敗",
|
|
150
|
+
uploadNoConnection: "上傳中斷了,請檢查網路連線", sendNoConnection: "沒有送到 AgEnD,請檢查網路連線", notSentBecause: "沒有送出:{0}", deleteUnsent: "刪除",
|
|
151
|
+
sendFailure_wake_capacity: "目前沒有空位可喚醒這個實例。請等其他實例閒置後重試。",
|
|
152
|
+
sendFailure_wake_credentials: "實例無法登入。請先在主機檢查它的帳號,再重試。",
|
|
153
|
+
sendFailure_wake_timeout: "實例未能及時就緒。請重試,或在主機檢查它的狀態。",
|
|
154
|
+
sendFailure_instance_stopped: "這個實例已停止或移除。請先在主機啟動它,再重試。",
|
|
155
|
+
sendFailure_delivery_unavailable: "實例目前無法接收這則訊息。請在主機檢查它的狀態,再重試。",
|
|
156
|
+
sendFailure_delivery_changed: "訊息送出前,登入或實例狀態已改變。必要時請重新登入,再重試。",
|
|
157
|
+
sendFailure_reply_gone: "你回覆的訊息已不在這個聊天裡。內容還在:可以不帶回覆直接送出,或改回覆其他訊息。",
|
|
158
|
+
reply: "回覆", replyingTo: "回覆 {0}", replyCancel: "取消回覆(Esc)", replyHidden: "之前的一則訊息", replyPhoto: "[圖片]", replyFile: "[檔案]",
|
|
159
|
+
replyGone: "那則訊息已不在這個聊天裡。", replyJump: "顯示被回覆的訊息", copyText: "複製文字", copyLink: "複製連結", msgMenu: "訊息",
|
|
160
|
+
|
|
131
161
|
effectTrialReason_checking: "正在確認工作階段…",
|
|
132
162
|
effectTrialReason_localAdmin: "請在公開連結以外的儀表板以管理員登入後試播。",
|
|
133
163
|
effectTrialReason_chatChanged: "請開啟發出試播邀請的聊天。",
|
|
@@ -146,13 +176,13 @@ register("chat", {
|
|
|
146
176
|
effectTrialSettings: "開啟播放設定",
|
|
147
177
|
effectTrialPlayMotion: "仍然播放效果",
|
|
148
178
|
effectTrial: "效果試播", effectTrialLocal: "僅在本頁試播,不會套用或儲存。",
|
|
149
|
-
effectTrialStart: "試播", effectTrialExpired: "試播邀請已過期。", effectTrialUnavailable: "此試播已無法使用。",
|
|
179
|
+
effectTrialStopped: "試播已停止", effectTrialStart: "試播", effectTrialExpired: "試播邀請已過期。", effectTrialUnavailable: "此試播已無法使用。",
|
|
150
180
|
cmdConfirm: "清空", cmdConfirmBackend: "切換並重新啟動", cmdRunning: "執行 /{0} 中…", cmdNotCommand: "這裡沒有這個指令——按 Enter 會當成一般訊息送出。", cmdDismiss: "關閉", cmdCommands: "指令",
|
|
151
181
|
compactRunning: "壓縮中…", compactDone: "✅ 對話已壓縮", compactUnknown: "這個後端不會回報壓縮何時完成。",
|
|
152
182
|
compactTimeout: "{0} 分鐘內沒有看到壓縮完成的紀錄,請到代理自己的對話確認。",
|
|
153
183
|
compactLost: "無法再追蹤這次壓縮:指令沒有送到代理,或代理已停止、換了後端。",
|
|
154
184
|
compactNotCompacted: "kiro 沒有壓縮對話:對話太短,或壓縮被中止了。",
|
|
155
|
-
cmdChoose: "選擇", cmdCurrent: "目前", chipCompact: "壓縮", chipClear: "清空…", chipContext: "已用 {0}% 的 context",
|
|
185
|
+
cmdChoose: "選擇", cmdCurrent: "目前", cmdSignIn: "登入", cmdSignInTo: "登入 {0}", chipCompact: "壓縮", chipClear: "清空…", chipContext: "已用 {0}% 的 context",
|
|
156
186
|
chipModel: "模型:{0}——選擇其他", chipEffort: "推理強度:{0}——選擇其他",
|
|
157
187
|
cmd_ctx: "context 用量、模型與推理強度", cmd_compact: "壓縮對話", cmd_clear: "清空對話(會先確認)",
|
|
158
188
|
cmd_model: "查看或切換模型", cmd_backend: "切換 CLI backend,再選模型和推理強度(會重新啟動)", cmd_effort: "查看或設定推理強度", cmd_cancel: "停止目前的回覆",
|
|
@@ -167,7 +197,7 @@ register("chat", {
|
|
|
167
197
|
a11yWorking: "{0} 開始工作", a11yIdle: "{0} 已完成", a11yReplied: "{0} 已回覆", conversationWith: "與 {0} 的對話",
|
|
168
198
|
stopping: "正在中止 {0}…", awaiting: "{0} 正在等你回應", approxNote: "從終端畫面判讀,僅供參考", elapsedTitle: "從這個頁面看到它開始工作起算(約略)",
|
|
169
199
|
dropHere: "放開即可附加檔案", asText: "改為文字", pasteAttached: "貼上的長文字({0} 個字元)已改為文字檔附加", pasteKeptAsText: "附件已滿,貼上的長文字保留為一般文字",
|
|
170
|
-
send: "送出", composerPlaceholder: "傳訊息給 {0}…", composerHint: "Enter 送出 · Shift+Enter 換行", composerMore: "/ 叫出指令 · Esc 中止回覆", guestMore: "Esc 中止回覆",
|
|
200
|
+
send: "送出", composerPlaceholder: "傳訊息給 {0}…", composerHint: "Enter 送出 · Shift+Enter 換行", composerHintTouch: "Return 換行 · 按「送出」傳送", composerMore: "/ 叫出指令 · Esc 中止回覆", guestMore: "Esc 中止回覆",
|
|
171
201
|
guestNote: "你是訪客:agent 會把你的訊息視為訪客的訊息(僅供辨識)。", guestNoCommands: "訪客不能執行指令,請去掉開頭的 / 再送出。", attachTitle: "附加檔案(任何類型,也可以貼上或拖曳)",
|
|
172
202
|
pvPreview: "預覽", pvStop: "停止", pvDownload: "下載", pvMenu: "預覽選項", pvHtml: "HTML",
|
|
173
203
|
pvAllowButton: "允許預覽", pvAllow: "允許預覽 HTML(預覽可能把資料傳出去)", pvDisallow: "不再允許預覽 HTML",
|
|
@@ -186,6 +216,7 @@ register("chat", {
|
|
|
186
216
|
pvPage: "頁面", pvCode: "程式碼", pvReload: "重新載入", pvClose: "關閉面板", pvBack: "回到對話", pvResize: "調整預覽面板寬度",
|
|
187
217
|
pvNewer: "{0} 的回覆裡有較新的版本。", pvNewerShow: "顯示", pvPanelIdle: "按「預覽」在這裡執行。",
|
|
188
218
|
lbLabel: "圖片:{0}", lbLabelNoName: "圖片", lbClose: "關閉", lbOpenOriginal: "開啟原圖", lbPrev: "上一張", lbNext: "下一張", lbCount: "{0} / {1}",
|
|
219
|
+
lbZoomIn: "放大(+)", lbZoomOut: "縮小(−)", lbZoomLevel: "{0}%:點一下切換「符合視窗」與「實際大小」(0 / 1)", lbFitWidth: "符合寬度(W)",
|
|
189
220
|
pvWhyOptin: "還沒允許 HTML 預覽。可從這張卡片的 ⋯ 選單或「設定 → 偏好設定」允許。",
|
|
190
221
|
pvWhyOptinPanel: "還沒允許 HTML 預覽。",
|
|
191
222
|
pvWhyNever: "這台裝置在這個工作階段已關閉預覽。",
|
|
@@ -218,10 +249,10 @@ register("chat", {
|
|
|
218
249
|
previews: "允許預覽 HTML",
|
|
219
250
|
clicked: "點選了:", clickShow: "顯示這些按鈕所在的訊息",
|
|
220
251
|
copy: "複製", copyMessage: "複製這則回覆", copied: "已複製", copyFailed: "複製失敗", wrap: "換行", showAll: "展開全部 {0} 行", showMore: "顯示更多", showLess: "收合", jumpLatest: "最新", newBelow: "{0} 則新訊息",
|
|
221
|
-
disconnected: "已斷線", tick_queued: "排在前一則訊息之後", tick_processing: "已交給 agent", tick_delivered: "agent 已收到", tick_failed: "未送達", tick_cancelled: "已被中止取消",
|
|
252
|
+
disconnected: "已斷線", tick_queued: "排在前一則訊息之後", tick_processing: "已交給 agent", tick_delivered: "agent 已收到", tick_failed: "未送達", tick_cancelled: "已被中止取消", reactedBy: "{0} 的回應",
|
|
222
253
|
promptAnswering: "回覆中…", promptGone: "這個提示已經結束", promptFor: "{0}:{1}",
|
|
223
254
|
working: "{0} 處理中…", stuck: "{0} 似乎卡住了", stopReply: "中止回覆", stopReplyTitle: "中止目前的回覆(同 Esc),並取消還在排隊的訊息。instance 會繼續運行。", stopSent: "已中止",
|
|
224
|
-
file_empty: "空檔案", file_too_large: "超過 {0} MB", file_too_large_public: "超過 {0} MB,這是公開連結單次上傳的上限", file_too_many: "每則訊息最多 {0} 個檔案", file_too_much: "檔案合計會超過 {0} MB", removeFile: "移除",
|
|
255
|
+
file_empty: "空檔案", file_too_large: "超過 {0} MB", file_too_large_public: "超過 {0} MB,這是公開連結單次上傳的上限", file_too_many: "每則訊息最多 {0} 個檔案", file_too_much: "檔案合計會超過 {0} MB", removeFile: "移除", putBack: "放回輸入框",
|
|
225
256
|
noMessages: "直接在下方輸入任務。",
|
|
226
257
|
pick: "選一個 Agent 開始聊天。", noAgents: "先建立一個 Agent,再開始聊天。", newAgent: "新增 Agent", notFound: "沒有叫「{0}」的 instance", notFoundHint: "它可能已被刪除或改名。", backToList: "選擇 Agent",
|
|
227
258
|
details: "Instance 詳細資料", start: "啟動 instance", stopInstance: "停止 instance", restart: "重新啟動 instance", delete: "刪除 instance…",
|
|
@@ -236,6 +267,7 @@ register("chat", {
|
|
|
236
267
|
dEditInSettings: "到設定編輯", dPause: "暫停", dWake: "喚醒", dPaused: "{0} 已暫停", dWoken: "{0} 正在喚醒", dActionFailed: "沒有成功,請再試一次。",
|
|
237
268
|
dNoActivity: "最近一小時沒有活動。", dWorking: "處理中…",
|
|
238
269
|
themeLock: "鎖定主題", themeUnlock: "解除主題鎖定", themeReset: "重設主題…", themeResetGo: "重設",
|
|
270
|
+
pageColours: "頁面配色", pageAgentOn: "依 agent 的設定(開)", pageAgentOff: "依 agent 的設定(關)", pageWhole: "整個頁面", pageChatOnly: "只在它的聊天",
|
|
239
271
|
themeResetConfirm: "要把 {0} 的主題重設為預設嗎?顏色、圖片和處理中文字都會移除;鎖定會保留。",
|
|
240
272
|
themeResetDone: "已重設 {0} 的主題。", themeLocked: "已鎖定 {0} 的主題:agent 無法變更。", themeUnlocked: "已解除 {0} 的主題鎖定。",
|
|
241
273
|
themeFailed: "主題沒有變更({0})。",
|
package/dist/ui/chat-thread.js
CHANGED
|
@@ -8,7 +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 {
|
|
11
|
+
import { canvasWorkerEnabled, onCanvasWorkerChange, onCanvasMetadataChange, readCanvasTrialMessage } from "/assets/feature-flags.js";
|
|
12
12
|
import { loadHtmlAttachment } from "./html-attachment.js";
|
|
13
13
|
import { chatTime, chatTimeFull, onDayChange } from "./chat-time.js";
|
|
14
14
|
import { textLinkSegments } from "/assets/app-route.js";
|
|
@@ -28,6 +28,7 @@ const P = () => globalThis.AgendPreview;
|
|
|
28
28
|
/** #1672: a status line longer than this (lines, or characters) is folded until it is opened. */
|
|
29
29
|
export const STATUS_FOLD_LINES = 6;
|
|
30
30
|
export const STATUS_FOLD_CHARS = 600;
|
|
31
|
+
const REPLY = '<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 14 4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 0 11H11"/></svg>';
|
|
31
32
|
const COPY = '<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
|
|
32
33
|
|
|
33
34
|
/** Escapes & " ' < >: safe for text and inside a quoted attribute. */
|
|
@@ -39,6 +40,41 @@ export const msgKey = (x) => `${x.boot}-${x.id}`;
|
|
|
39
40
|
*/
|
|
40
41
|
export const THREAD_TAIL = 24;
|
|
41
42
|
export const THREAD_CHUNK = 40;
|
|
43
|
+
/** #2158: a reader's scroll (smooth, momentum) is theirs until it has been this quiet since their last input or scroll. */
|
|
44
|
+
export const READER_QUIET_MS = 250;
|
|
45
|
+
const SCROLL_KEYS = new Set(["PageUp", "PageDown", "ArrowUp", "ArrowDown", "Home", "End", " "]);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* #2053: a message's rendered Markdown, kept across renders and chat switches. A draw compares each message's html with
|
|
49
|
+
* its node's, so every render of a thread rendered every drawn message's Markdown again (~320 calls per 200-message
|
|
50
|
+
* switch). renderMarkdown's output depends only on the text, whether its HTML cards are on (an agent's message), and —
|
|
51
|
+
* for a text that has them — whether the page knows each server-emoji id and the name it has for each mention: the key
|
|
52
|
+
* holds exactly those, so a cached html is always what renderMarkdown would return now. Bounded: least recently used out.
|
|
53
|
+
*/
|
|
54
|
+
export const MD_CACHE_MAX = 4000;
|
|
55
|
+
const mdCache = new Map();
|
|
56
|
+
const EMOJI_IDS = /<a?:[A-Za-z0-9_]{2,32}:(\d{15,25})>/g;
|
|
57
|
+
const MENTION_IDS = /<(@!?|@&|#)(\d{15,25})>/g;
|
|
58
|
+
const MENTION_KINDS = { "@": "u", "@!": "u", "@&": "r", "#": "c" };
|
|
59
|
+
export function renderedMarkdown(text, cards, emojis, mentions) {
|
|
60
|
+
const src = typeof text === "string" ? text : String(text == null ? "" : text);
|
|
61
|
+
let sig = cards ? "c" : "-";
|
|
62
|
+
if (src.includes("<")) {
|
|
63
|
+
// Read as renderMarkdown reads it: it drops NUL first (its placeholder mark), so "<@\0id>" is a mention there too.
|
|
64
|
+
const seen = src.includes("\u0000") ? src.replace(/\u0000/g, "") : src;
|
|
65
|
+
for (const m of seen.matchAll(EMOJI_IDS)) sig += `|e${m[1]}${emojis && emojis(m[1]) ? 1 : 0}`;
|
|
66
|
+
for (const m of seen.matchAll(MENTION_IDS)) { const name = mentions ? mentions(MENTION_KINDS[m[1]], m[2]) : null; sig += `|m${m[1]}${m[2]}=${typeof name === "string" ? name.length + ":" + name : "-"}`; }
|
|
67
|
+
}
|
|
68
|
+
const key = `${sig}\u0000${src}`;
|
|
69
|
+
let html = mdCache.get(key);
|
|
70
|
+
if (html === undefined) html = R().renderMarkdown(src, { htmlCards: cards, emojis, mentions });
|
|
71
|
+
else mdCache.delete(key);
|
|
72
|
+
mdCache.set(key, html);
|
|
73
|
+
while (mdCache.size > MD_CACHE_MAX) mdCache.delete(mdCache.keys().next().value);
|
|
74
|
+
return html;
|
|
75
|
+
}
|
|
76
|
+
/** Tests only: forget every rendered Markdown. */
|
|
77
|
+
export function clearRenderedMarkdown() { mdCache.clear(); }
|
|
42
78
|
|
|
43
79
|
/**
|
|
44
80
|
* Bind a renderer to `list` (the thread element) inside `scroller`. opts: { t, tf, isUser(x), onJump({show, unseen}),
|
|
@@ -47,6 +83,17 @@ export const THREAD_CHUNK = 40;
|
|
|
47
83
|
*/
|
|
48
84
|
export function createThread(list, scroller, opts) {
|
|
49
85
|
const nodes = new Map(); // key → { html, node }
|
|
86
|
+
// A server emoji's picture that does not load reads `:name:` (its alt) instead of an empty box (error does not bubble:
|
|
87
|
+
// caught on the way down).
|
|
88
|
+
list.addEventListener("error", (e) => {
|
|
89
|
+
const img = e.target;
|
|
90
|
+
if (!img || img.tagName !== "IMG" || !img.classList || !img.classList.contains("emoji")) return;
|
|
91
|
+
const span = list.ownerDocument.createElement("span");
|
|
92
|
+
span.className = "emoji-text";
|
|
93
|
+
span.textContent = img.getAttribute("alt") || "";
|
|
94
|
+
span.title = img.getAttribute("title") || span.textContent;
|
|
95
|
+
img.replaceWith(span);
|
|
96
|
+
}, true);
|
|
50
97
|
let msgs = [];
|
|
51
98
|
let unseen = 0;
|
|
52
99
|
// The reader is at the newest message. While pinned, content that grows after it was drawn — an image loading, a
|
|
@@ -54,12 +101,15 @@ export function createThread(list, scroller, opts) {
|
|
|
54
101
|
// Only a move UP unpins: the browser's own scroll anchoring also fires scroll events when content grows (the view
|
|
55
102
|
// moves down or stays), and those must not count as the reader leaving the bottom. Reaching the bottom pins again.
|
|
56
103
|
let pinned = true;
|
|
57
|
-
|
|
104
|
+
// Where the view was (and how tall it was) at the last scroll the page saw or made: a move up from there unpins.
|
|
105
|
+
let lastTop = 0, lastView = 0;
|
|
106
|
+
const mark = () => { lastTop = scroller.scrollTop; lastView = scroller.clientHeight; };
|
|
58
107
|
// The oldest message drawn (by key): everything after it is drawn, so new messages never push the window. Null: none
|
|
59
108
|
// drawn yet — the next render draws the newest THREAD_TAIL and the rest follows (grow).
|
|
60
109
|
let firstKey = null;
|
|
61
|
-
let growTimer = null, growFrame = null, disposed = false;
|
|
110
|
+
let growTimer = null, growFrame = null, disposed = false, parked = false;
|
|
62
111
|
const cardRefresh = new WeakMap(); // card node → re-read availability (weak: a card that left takes its source with it)
|
|
112
|
+
const cardDrop = new WeakMap(); // card node → drop the HTML read it is waiting on (the chat left: park)
|
|
63
113
|
const tr = opts.t, trf = opts.tf;
|
|
64
114
|
const stopIn = (node) => (P() ? P().stopIn(node) : []);
|
|
65
115
|
/** #1770: write a message node's time label for now; unchanged text is not touched. */
|
|
@@ -82,8 +132,9 @@ export function createThread(list, scroller, opts) {
|
|
|
82
132
|
// #1770: the label ("17:38", "Yesterday 17:38", "10/11 17:38") depends on today, so it is not part of the html a node
|
|
83
133
|
// is kept by: it is written into the node (timeLabels) — crossing midnight relabels in place and reloads no preview.
|
|
84
134
|
const time = x.ts ? `<span class="time" data-ts="${escAttr(x.ts)}" title="${escAttr(chatTimeFull(x.ts))}"></span>` : `<span class="time"></span>`;
|
|
85
|
-
|
|
86
|
-
|
|
135
|
+
if (x.outgoing) return outgoingHtml(x);
|
|
136
|
+
const trial = readCanvasTrialMessage(x);
|
|
137
|
+
if (trial) return canvasWorkerEnabled() ? trialHtml(trial, time, x) : "";
|
|
87
138
|
if (x.role === "status") return statusHtml(x, time);
|
|
88
139
|
const u = opts.isUser(x);
|
|
89
140
|
// renderMarkdown escapes the whole text before it adds any tag of its own (chat-render.js).
|
|
@@ -92,7 +143,64 @@ export function createThread(list, scroller, opts) {
|
|
|
92
143
|
const buttons = x.role === "agent" ? replyButtonsHtml(x.buttons) : "";
|
|
93
144
|
// A person's click on a reply button shows as the button's label, never the line the agent was given (its value).
|
|
94
145
|
const clicked = x.role === "user" && x.click && typeof x.click.label === "string";
|
|
95
|
-
|
|
146
|
+
// #2272: reply to it — a hover strip at its top right (phones: swipe left or long-press; R on a focused message).
|
|
147
|
+
const key = msgKey(x);
|
|
148
|
+
const act = opts.canReply?.() === false ? "" : `<div data-trust="thread-control" class="msg-actions"><button type="button" class="chip-btn icon-only" data-act="reply" data-arg="${escAttr(key)}" title="${escAttr(tr("chat.reply"))}" aria-label="${escAttr(tr("chat.reply"))}">${REPLY}</button></div>`;
|
|
149
|
+
return `<div class="msg ${u ? "user" : "agent"}" data-key="${escAttr(key)}" tabindex="-1">${act}<div class="meta"><span class="sender">${escAttr(x.sender)}</span>${time}${ticks}</div>${quoteHtml(x.replyTo)}<div class="body">${clicked ? clickHtml(x.click) : `<div class="md">${renderedMarkdown(x.text, x.role === "agent", opts.emojis, opts.mentions)}</div>`}${R().attachmentsHtml(x.attachments, { htmlCards: x.role === "agent", goneTitle: tr("chat.attGone"), goneLabel: tr("chat.attUnavailable"), inlinePreviews: !PUBLIC_LINK() })}${buttons}</div>${R().reactionsHtml(x.reactions, tr("chat.reactedBy", x.instance || ""))}${tools}</div>`;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A message this page is sending (chat-store.js): its own bubble at once, dimmed with "Sending…" until the server
|
|
153
|
+
* takes it, then as sent until the server's copy replaces it; failed: marked, with Retry and Delete. Each file shows
|
|
154
|
+
* its upload — a picture as itself (a local preview), anything else by name — with its own bar, moved in place by
|
|
155
|
+
* progress() (the html does not hold the numbers, so a moving bar never redraws the bubble). No data-key: it is no
|
|
156
|
+
* message yet (nothing replies to it, links to it or copies it).
|
|
157
|
+
*/
|
|
158
|
+
function outgoingHtml(x) {
|
|
159
|
+
const st = x.outgoing.state, going = st === "queued" || st === "sending";
|
|
160
|
+
const files = (x.files || []).map((f, i) => {
|
|
161
|
+
const pic = f.url ? `<img class="out-pic" src="${escAttr(f.url)}" alt="${escAttr(f.name)}">` : `<span class="out-doc" aria-hidden="true"></span>`;
|
|
162
|
+
return `<div class="out-file" data-i="${escAttr(i)}">${pic}<div class="out-file-info"><span class="out-name">${escAttr(f.name)}</span>`
|
|
163
|
+
+ `<span class="out-bar" role="progressbar" aria-label="${escAttr(trf("chat.uploadingFile", f.name))}" aria-valuemin="0" aria-valuemax="100"><span class="out-fill"></span></span>`
|
|
164
|
+
+ `<span class="out-pct"></span></div></div>`;
|
|
165
|
+
}).join("");
|
|
166
|
+
const failed = st === "failed" ? `<div data-trust="thread-control" class="out-note lbar" role="alert"><span class="out-error">${escAttr(trf("chat.notSentBecause", x.outgoing.error || ""))}</span>`
|
|
167
|
+
+ `<span class="out-actions"><button type="button" class="btn btn-sm btn-primary" data-act="retryOut" data-arg="${escAttr(x.clientId)}">${escAttr(tr("chat.retrySend"))}</button>`
|
|
168
|
+
+ `<button type="button" class="btn btn-sm" data-act="putBackOut" data-arg="${escAttr(x.clientId)}">${escAttr(tr("chat.putBack"))}</button>`
|
|
169
|
+
+ `<button type="button" class="btn btn-sm" data-act="deleteOut" data-arg="${escAttr(x.clientId)}">${escAttr(tr("chat.deleteUnsent"))}</button></span></div>` : "";
|
|
170
|
+
const state = going ? `<span class="out-state" role="status"><span class="out-spin" aria-hidden="true"></span>${escAttr(tr("chat.sending"))}</span>` : "";
|
|
171
|
+
return `<div class="msg user out out-${st}" data-out="${escAttr(x.clientId)}"${going ? ' aria-busy="true"' : ""} tabindex="-1"><div class="meta"><span class="sender">${escAttr(x.sender)}</span>${state}</div>`
|
|
172
|
+
+ `${quoteHtml(x.replyTo)}<div class="body">${x.text ? `<div class="md">${renderedMarkdown(x.text, false, opts.emojis, opts.mentions)}</div>` : ""}`
|
|
173
|
+
+ `${files ? `<div class="out-files">${files}</div>` : ""}</div>${failed}</div>`;
|
|
174
|
+
}
|
|
175
|
+
/** The pending bubbles' upload bars and percentages, as their files stand now (in place: CSSOM, no redraw). */
|
|
176
|
+
function progress() {
|
|
177
|
+
for (const v of nodes.values()) {
|
|
178
|
+
const x = v.x;
|
|
179
|
+
if (!x || !x.outgoing || !x.files || !x.files.length) continue;
|
|
180
|
+
for (const el of v.node.querySelectorAll(".out-file[data-i]")) {
|
|
181
|
+
const f = x.files[Number(el.dataset.i)];
|
|
182
|
+
if (!f) continue;
|
|
183
|
+
const pct = f.state === "done" ? 100 : f.total > 0 ? Math.min(100, Math.floor((f.loaded / f.total) * 100)) : 0;
|
|
184
|
+
el.dataset.state = f.state;
|
|
185
|
+
const bar = el.querySelector(".out-bar"), fill = el.querySelector(".out-fill"), label = el.querySelector(".out-pct");
|
|
186
|
+
if (bar) bar.setAttribute("aria-valuenow", String(pct));
|
|
187
|
+
if (fill) fill.style.transform = `scaleX(${pct / 100})`;
|
|
188
|
+
if (label) { const text = f.state === "failed" ? tr("chat.uploadFailed") : f.state === "waiting" ? tr("chat.uploadWaiting") : `${pct}%`; if (label.textContent !== text) label.textContent = text; }
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* #2272: what a reply quotes, above its body — the quoted sender and first words (or that it had files), as the server
|
|
195
|
+
* read them when it was sent; a button that shows that message. A guest that may not see it gets only "an earlier
|
|
196
|
+
* message". Text only: everything is escaped.
|
|
197
|
+
*/
|
|
198
|
+
function quoteHtml(q) {
|
|
199
|
+
if (!q || typeof q !== "object" || typeof q.boot !== "string" || typeof q.id !== "number") return "";
|
|
200
|
+
const words = q.hidden ? tr("chat.replyHidden")
|
|
201
|
+
: (typeof q.text === "string" && q.text) || (q.media === "photo" ? tr("chat.replyPhoto") : q.media === "document" ? tr("chat.replyFile") : "");
|
|
202
|
+
const who = !q.hidden && typeof q.sender === "string" && q.sender ? `<span class="quote-sender">${escAttr(q.sender)}</span> ` : "";
|
|
203
|
+
return `<button type="button" data-trust="thread-control" class="msg-quote" data-act="jumpQuote" data-arg="${escAttr(`${q.boot}-${q.id}`)}" title="${escAttr(tr("chat.replyJump"))}"><span class="quote-mark">${REPLY}</span> ${who}<span class="quote-text">${escAttr(words)}</span></button>`;
|
|
96
204
|
}
|
|
97
205
|
/**
|
|
98
206
|
* A button click as a chip: 🔘 and the label (escaped: the label is the agent's text). With `of` (live, while its
|
|
@@ -113,14 +221,16 @@ export function createThread(list, scroller, opts) {
|
|
|
113
221
|
}
|
|
114
222
|
function trialHtml(offer, time, message) {
|
|
115
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;
|
|
116
225
|
const available = reason === "ready", fix = !PUBLIC_LINK() && !available && reason !== "expired" && reason !== "checking" && typeof opts.fixEffectTrial === "function";
|
|
117
226
|
const label = available ? "chat.effectTrialStart" : reason === "busy" ? "chat.effectTrialStopOther" : reason === "localAdmin" ? "chat.effectTrialSignIn" : reason === "reducedMotion" ? "chat.effectTrialPlayMotion" : "chat.effectTrialSettings";
|
|
118
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>` : "";
|
|
119
|
-
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>${button}</div></div></div>`;
|
|
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>`;
|
|
120
229
|
}
|
|
121
230
|
function armTrials() {
|
|
122
231
|
if (trialTimer !== null) clearTimeout(trialTimer); trialTimer = null;
|
|
123
|
-
|
|
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);
|
|
124
234
|
if (Number.isFinite(next)) trialTimer = setTimeout(() => { trialTimer = null; render(msgs); }, Math.max(1, Math.min(2147483647, next - now)));
|
|
125
235
|
}
|
|
126
236
|
/**
|
|
@@ -276,7 +386,7 @@ export function createThread(list, scroller, opts) {
|
|
|
276
386
|
const note = el("div", "pv-note"); note.setAttribute("data-trust", "thread-control");
|
|
277
387
|
const body = el("div", "tc-body"); body.hidden = true;
|
|
278
388
|
ph.append(head, note, body);
|
|
279
|
-
let text = null, reading =
|
|
389
|
+
let text = null, reading = 0, reads = 0, all = false;
|
|
280
390
|
const draw = () => {
|
|
281
391
|
body.textContent = "";
|
|
282
392
|
const lines = text.split(/\r?\n/);
|
|
@@ -312,12 +422,15 @@ export function createThread(list, scroller, opts) {
|
|
|
312
422
|
body.append(more);
|
|
313
423
|
}
|
|
314
424
|
};
|
|
425
|
+
// #2053: as an HTML card's read (cardDrop), one still waiting when the chat left is dropped, the card not left Loading.
|
|
426
|
+
cardDrop.set(ph, () => { if (reading) { reading = 0; note.textContent = ""; } });
|
|
315
427
|
show.onclick = async () => {
|
|
316
428
|
if (reading) return;
|
|
317
429
|
if (text !== null) { body.hidden = !body.hidden; show.textContent = tr(body.hidden ? "chat.tcShow" : "chat.tcHide"); return; }
|
|
318
|
-
reading =
|
|
430
|
+
const mine = reading = ++reads; note.textContent = tr("chat.pvLoading");
|
|
319
431
|
const r = await loadHtmlAttachment({ id: att.id, name: att.name, size: att.size });
|
|
320
|
-
reading
|
|
432
|
+
if (reading !== mine) return; // dropped (its chat left meanwhile): a new click reads again
|
|
433
|
+
reading = 0;
|
|
321
434
|
if (!ph.isConnected) return; // the card left the page while it was read: nothing to draw
|
|
322
435
|
if (!r.ok) { note.textContent = r.reason === "over" ? tr("chat.tcOver") : attReason(r.reason); return; }
|
|
323
436
|
note.textContent = "";
|
|
@@ -455,6 +568,10 @@ export function createThread(list, scroller, opts) {
|
|
|
455
568
|
optB.onclick = () => { menu.open = false; opts.setPreviewOptIn(!P().optedIn()); };
|
|
456
569
|
neverB.onclick = () => { menu.open = false; P().setNever(!P().never()); refreshCards(); };
|
|
457
570
|
cardRefresh.set(ph, refresh);
|
|
571
|
+
// #2053: a kept card is shown again later. A read still waiting when its chat left is dropped then: its answer —
|
|
572
|
+
// whenever it comes — starts nothing (no preview, no panel without a new click), and the card is not left Loading
|
|
573
|
+
// (shown again, it is refreshed: refreshCards).
|
|
574
|
+
cardDrop.set(ph, () => { reading = 0; });
|
|
458
575
|
refresh(stoppedKeys.includes(key) ? tr("chat.pvChanged") : null);
|
|
459
576
|
}
|
|
460
577
|
/** Re-read this device's preview choice on every card in this thread. */
|
|
@@ -469,12 +586,45 @@ export function createThread(list, scroller, opts) {
|
|
|
469
586
|
// newest bubble clipped behind it, and the next growth past 48 px put the pill over it.
|
|
470
587
|
const atBottom = () => R().isNearBottom(scroller.scrollTop, scroller.clientHeight, scroller.scrollHeight, 1);
|
|
471
588
|
function reportJump() { opts.onJump({ show: !nearBottom(), unseen }); }
|
|
472
|
-
function toBottom() { scroller.scrollTop = scroller.scrollHeight; pinned = true;
|
|
589
|
+
function toBottom() { snap(); scroller.scrollTop = scroller.scrollHeight; pinned = true; mark(); }
|
|
590
|
+
/**
|
|
591
|
+
* #2184: a thread's height is rarely a whole number of pixels, and a pinned view's offset is: so each time older messages
|
|
592
|
+
* were drawn above, the whole view moved by the change in that fraction (0.6–0.7 px — the faint jitter of a chat
|
|
593
|
+
* opened cold). A sub-pixel margin above the list keeps the thread's height whole, so the bottom never moves.
|
|
594
|
+
*/
|
|
595
|
+
// #2188: one read (the list's box excludes its own margin, so nothing is reset first) and a write only on a change —
|
|
596
|
+
// a reset-then-measure laid a 200-message thread out twice on every pinned draw (2.3 s at 4× CPU on a kept chat).
|
|
597
|
+
let snapped = null;
|
|
598
|
+
function snap() {
|
|
599
|
+
const h = list.getBoundingClientRect().height, f = h - Math.floor(h);
|
|
600
|
+
const want = f > 0.001 && f < 0.999 ? (1 - f) + "px" : "0px";
|
|
601
|
+
if (want !== snapped) { snapped = want; list.style.setProperty("--thread-snap", want); }
|
|
602
|
+
}
|
|
473
603
|
// Sizes change without a scroll event (layout after the render, the dock under the thread): while pinned, the view
|
|
474
604
|
// stays flush with the bottom; a reader who scrolled up is never moved.
|
|
475
605
|
const resized = () => { if (pinned && !atBottom()) toBottom(); reportJump(); };
|
|
476
|
-
|
|
606
|
+
let ro = typeof ResizeObserver === "function" ? new ResizeObserver(resized) : null;
|
|
477
607
|
if (ro) { ro.observe(list); ro.observe(scroller); }
|
|
608
|
+
// #2158: the reader's own hand on the thread — a wheel, a touch, the scrollbar (a pointer held), a scrolling key
|
|
609
|
+
// outside a text field — and the scroll that follows it until it has been quiet READER_QUIET_MS.
|
|
610
|
+
let inputAt = -Infinity, held = false;
|
|
611
|
+
const touched = () => { inputAt = performance.now(); };
|
|
612
|
+
const hold = (on) => () => { held = on; touched(); };
|
|
613
|
+
const onKey = (ev) => {
|
|
614
|
+
const el = ev.target;
|
|
615
|
+
if (SCROLL_KEYS.has(ev.key) && !(el && (el.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName || "")))) touched();
|
|
616
|
+
};
|
|
617
|
+
const onScroller = [["wheel", touched], ["touchstart", hold(true)], ["touchend", hold(false)], ["touchcancel", hold(false)], ["pointerdown", hold(true)]];
|
|
618
|
+
const onDocument = [["pointerup", hold(false)], ["pointercancel", hold(false)], ["keydown", onKey]];
|
|
619
|
+
/** Listen for the reader's input on `sc` (and its document: a pointer let go anywhere, a key), or stop. */
|
|
620
|
+
function watchReader(sc, on) {
|
|
621
|
+
const doc = sc.ownerDocument, how = on ? "addEventListener" : "removeEventListener";
|
|
622
|
+
for (const [type, fn] of onScroller) sc[how](type, fn, { passive: true });
|
|
623
|
+
if (doc) for (const [type, fn] of onDocument) doc[how](type, fn, true);
|
|
624
|
+
if (!on) held = false;
|
|
625
|
+
}
|
|
626
|
+
const readerActive = () => held || performance.now() - inputAt < READER_QUIET_MS;
|
|
627
|
+
watchReader(scroller, true);
|
|
478
628
|
|
|
479
629
|
/** Where drawing starts in `msgs`: at the oldest drawn message, or (none yet) the newest THREAD_TAIL. */
|
|
480
630
|
function startIndex() {
|
|
@@ -488,14 +638,14 @@ export function createThread(list, scroller, opts) {
|
|
|
488
638
|
/** Draw the next chunk of older messages, keeping the reader where they were; then the next, until all are drawn. */
|
|
489
639
|
function grow() {
|
|
490
640
|
growTimer = growFrame = null;
|
|
491
|
-
if (disposed) return;
|
|
641
|
+
if (disposed || parked) return; // the chat left: nothing more is drawn (a kept one fills in when shown again)
|
|
492
642
|
const at = startIndex();
|
|
493
643
|
if (at <= 0) return;
|
|
494
644
|
firstKey = msgKey(msgs[Math.max(0, at - THREAD_CHUNK)]);
|
|
495
645
|
const fromBottom = scroller.scrollHeight - scroller.scrollTop;
|
|
496
646
|
draw({ older: true }); // drawn above the reader: never "new below" (render alone counts those)
|
|
497
647
|
if (pinned) toBottom();
|
|
498
|
-
else { scroller.scrollTop = scroller.scrollHeight - fromBottom;
|
|
648
|
+
else { scroller.scrollTop = scroller.scrollHeight - fromBottom; mark(); }
|
|
499
649
|
scheduleGrow();
|
|
500
650
|
}
|
|
501
651
|
/** After the next frame has painted (the click's own frame stays light), draw a chunk more. */
|
|
@@ -536,14 +686,18 @@ export function createThread(list, scroller, opts) {
|
|
|
536
686
|
if ("restore" in renderOpts) {
|
|
537
687
|
unseen = 0;
|
|
538
688
|
if (renderOpts.restore == null) toBottom();
|
|
539
|
-
else { scroller.scrollTop = renderOpts.restore; pinned = nearBottom();
|
|
689
|
+
else { scroller.scrollTop = renderOpts.restore; pinned = nearBottom(); mark(); }
|
|
540
690
|
} else if (stick) toBottom();
|
|
541
691
|
else unseen += added;
|
|
542
692
|
reportJump();
|
|
543
693
|
}
|
|
544
694
|
/** Put the messages from startIndex() on in the list (nodes reused when unchanged). Returns how many are new. */
|
|
545
695
|
function draw(drawOpts) {
|
|
546
|
-
const shown = msgs.slice(startIndex())
|
|
696
|
+
const shown = msgs.slice(startIndex()).filter(message => {
|
|
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
|
+
});
|
|
547
701
|
const keep = new Set(shown.map(msgKey));
|
|
548
702
|
for (const [k, v] of nodes) if (!keep.has(k)) { stopIn(v.node); v.node.remove(); nodes.delete(k); }
|
|
549
703
|
let prev = null, added = 0;
|
|
@@ -566,17 +720,40 @@ export function createThread(list, scroller, opts) {
|
|
|
566
720
|
}
|
|
567
721
|
armDay();
|
|
568
722
|
armPolls();
|
|
723
|
+
rove();
|
|
724
|
+
progress();
|
|
569
725
|
return added;
|
|
570
726
|
}
|
|
727
|
+
/**
|
|
728
|
+
* #2272 (review): one message in the thread is in the Tab order — the last one focused while it is still drawn, else
|
|
729
|
+
* the newest; ↑/↓ move between messages (chat-msg-actions.js). The rest are -1, so Tab passes the thread in one step.
|
|
730
|
+
*/
|
|
731
|
+
let roving = null;
|
|
732
|
+
function rove(key) {
|
|
733
|
+
if (key !== undefined) roving = key;
|
|
734
|
+
const at = (roving && nodes.has(roving) ? nodes.get(roving).node : null) || [...list.querySelectorAll(".msg[data-key]")].at(-1) || null;
|
|
735
|
+
for (const el of list.querySelectorAll('.msg[data-key][tabindex="0"]')) if (el !== at) el.setAttribute("tabindex", "-1");
|
|
736
|
+
if (at) at.setAttribute("tabindex", "0");
|
|
737
|
+
}
|
|
571
738
|
|
|
572
739
|
function onScroll() {
|
|
740
|
+
// #2158: the thread got shorter under a pinned view (text settling on a cold load, a card) and the browser clamped
|
|
741
|
+
// scrollTop to its new end — for the view as tall as it was then; the view got shorter too before WebKit sent that
|
|
742
|
+
// clamp's scroll event (it comes before the ResizeObserver). A view resting exactly at the bottom of the view as it
|
|
743
|
+
// was at the last mark, with no hand of the reader's on the thread, was put there by the browser: still pinned, back
|
|
744
|
+
// at the bottom. Geometry alone can't tell (a reader's move up by the dock's growth lands there too): any input of
|
|
745
|
+
// theirs, and the scroll after it, is theirs and unpins as before. The page's own scrolls (reveal) have no input but
|
|
746
|
+
// don't land there.
|
|
747
|
+
const reader = readerActive();
|
|
748
|
+
if (reader) touched(); // the reader's scroll goes on (smooth, momentum): still theirs while it does
|
|
749
|
+
else if (pinned && !atBottom() && Math.abs(scroller.scrollHeight - lastView - scroller.scrollTop) <= 1) toBottom();
|
|
573
750
|
const bottom = nearBottom(), top = scroller.scrollTop;
|
|
574
751
|
// #2087: pinned only at the exact bottom — a reader still wheeling through the last 48 px was pinned there, so
|
|
575
752
|
// the next resize (a picture, a card, the dock) pulled the view the rest of the way down under them. Near the bottom
|
|
576
753
|
// still counts for a new message (render follows it) and for the pill; nothing else moves a view the reader moves.
|
|
577
754
|
if (atBottom()) pinned = true;
|
|
578
755
|
else if (top < lastTop) pinned = false;
|
|
579
|
-
|
|
756
|
+
mark();
|
|
580
757
|
if (bottom) unseen = 0;
|
|
581
758
|
reportJump();
|
|
582
759
|
return bottom ? null : scroller.scrollTop;
|
|
@@ -636,24 +813,73 @@ export function createThread(list, scroller, opts) {
|
|
|
636
813
|
if (m && opts.clickReplyButton) opts.clickReplyButton(m[1], Number(m[2]));
|
|
637
814
|
} else if (act === "effectTrial") {
|
|
638
815
|
// Only the current host-produced keyed card and a real local click can request admission. No token is read from DOM.
|
|
639
|
-
const key = el.dataset.arg, row = msgs.find(x => msgKey(x) === key), owner = nodes.get(key), node = owner?.node, offer =
|
|
816
|
+
const key = el.dataset.arg, row = msgs.find(x => msgKey(x) === key), owner = nodes.get(key), node = owner?.node, offer = readCanvasTrialMessage(row);
|
|
640
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"
|
|
641
818
|
|| !offer || trialNow() >= offer.expiresAt) return;
|
|
642
819
|
if (trialStatus(row) === "ready" && opts.canTryEffect?.(row) === true) opts.startEffectTrial?.(row);
|
|
643
820
|
else opts.fixEffectTrial?.(row, trialStatus(row));
|
|
644
821
|
} else if (act === "showButtons") { const x = msgs.find(y => y.buttons && y.buttons.id === el.dataset.arg); if (x) reveal(msgKey(x)); }
|
|
822
|
+
else if (act === "reply") { const x = msgs.find(y => msgKey(y) === el.dataset.arg); if (x) opts.startReply?.(x); }
|
|
823
|
+
else if (act === "jumpQuote") void jumpTo(el.dataset.arg);
|
|
824
|
+
else if (act === "retryOut") opts.retryOutgoing?.(el.dataset.arg); // a failed send, again
|
|
825
|
+
else if (act === "putBackOut") opts.putBackOutgoing?.(el.dataset.arg); // back in the composer, to change it
|
|
826
|
+
else if (act === "deleteOut") opts.deleteOutgoing?.(el.dataset.arg);
|
|
645
827
|
}
|
|
828
|
+
/**
|
|
829
|
+
* #2272: show the message a reply quotes, flashed — drawn now, or after the chat reads back the longest history the
|
|
830
|
+
* server keeps; otherwise it says it is no longer there.
|
|
831
|
+
*/
|
|
832
|
+
async function jumpTo(key) {
|
|
833
|
+
if (typeof key !== "string" || !key) return;
|
|
834
|
+
if (reveal(key)) return;
|
|
835
|
+
const found = opts.findQuoted ? await opts.findQuoted(key) : false;
|
|
836
|
+
if (!found || !reveal(key)) opts.notice?.(tr("chat.replyGone"));
|
|
837
|
+
}
|
|
838
|
+
/** #2272: a drawn message's row (for the message menu and gestures), or undefined. */
|
|
839
|
+
function messageOf(key) { return msgs.find(y => msgKey(y) === key); }
|
|
646
840
|
|
|
647
841
|
/** The thread goes (the chat left, or another instance opened): every preview in it stops first. */
|
|
648
|
-
|
|
649
|
-
|
|
842
|
+
/**
|
|
843
|
+
* #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, effect trials, filling in), no size observer; the
|
|
845
|
+
* caller drops its subscriptions. Shown again: attach, then render — only what changed is drawn.
|
|
846
|
+
*/
|
|
847
|
+
function park() {
|
|
848
|
+
parked = true;
|
|
849
|
+
watchReader(scroller, false);
|
|
850
|
+
if (P()) P().stopAll("leave");
|
|
851
|
+
for (const node of list.querySelectorAll(".html-card[data-att], .text-card[data-att]")) { const f = cardDrop.get(node); if (f) f(); }
|
|
852
|
+
if (ro) { ro.disconnect(); ro = null; }
|
|
853
|
+
if (trialTimer !== null) clearTimeout(trialTimer); trialTimer = null;
|
|
854
|
+
if (growFrame !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(growFrame);
|
|
855
|
+
if (growTimer !== null) clearTimeout(growTimer);
|
|
856
|
+
growTimer = growFrame = null;
|
|
857
|
+
if (offDay) { offDay(); offDay = null; }
|
|
858
|
+
if (pollTick) { clearInterval(pollTick); pollTick = null; }
|
|
859
|
+
}
|
|
860
|
+
/** In view in `sc` (the view's scroller): sizes watched there from now on; the caller restores the position. */
|
|
861
|
+
function attach(sc) {
|
|
862
|
+
if (!parked) watchReader(scroller, false); // moved from the scroller it was made with
|
|
863
|
+
parked = false;
|
|
864
|
+
scroller = sc;
|
|
865
|
+
watchReader(sc, true);
|
|
866
|
+
if (ro) ro.disconnect();
|
|
867
|
+
ro = typeof ResizeObserver === "function" ? new ResizeObserver(resized) : null;
|
|
868
|
+
if (ro) { ro.observe(list); ro.observe(sc); }
|
|
869
|
+
}
|
|
870
|
+
/** `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
|
+
function dispose(own = false) {
|
|
874
|
+
disposed = true; featureOff(); metadataOff();
|
|
875
|
+
if (!parked) watchReader(scroller, false);
|
|
650
876
|
if (trialTimer !== null) clearTimeout(trialTimer); trialTimer = null;
|
|
651
877
|
if (ro) ro.disconnect();
|
|
652
|
-
if (P()) P().stopAll("leave");
|
|
878
|
+
if (P()) { if (own) P().stopIn(list); else P().stopAll("leave"); }
|
|
653
879
|
nodes.clear();
|
|
654
880
|
armDay();
|
|
655
881
|
armPolls();
|
|
656
882
|
}
|
|
657
883
|
|
|
658
|
-
return { render, onScroll, onClick, jumpLatest, reveal, refreshCards, dispose, nodes, get unseen() { return unseen; } };
|
|
884
|
+
return { render, progress, onScroll, onClick, jumpLatest, reveal, jumpTo, messageOf, rove, refreshCards, park, attach, dispose, nodes, get unseen() { return unseen; } };
|
|
659
885
|
}
|