@songsid/agend 2.3.0-beta.2 → 2.3.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/README.zh-TW.md +7 -1
- package/dist/agent-cli-instructions.md +9 -2
- package/dist/agent-cli.js +63 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +4 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.d.ts +4 -1
- package/dist/agent-file-read.js +189 -16
- package/dist/agent-file-read.js.map +1 -1
- package/dist/agent-whats-new.d.ts +11 -0
- package/dist/agent-whats-new.js +29 -5
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.d.ts +30 -1
- package/dist/auth-api.js +45 -13
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/authority-state.d.ts +38 -0
- package/dist/authority/authority-state.js +114 -0
- package/dist/authority/authority-state.js.map +1 -0
- package/dist/authority/session-authorizations.d.ts +43 -0
- package/dist/authority/session-authorizations.js +102 -0
- package/dist/authority/session-authorizations.js.map +1 -0
- package/dist/authority/web-authority.d.ts +120 -0
- package/dist/authority/web-authority.js +157 -0
- package/dist/authority/web-authority.js.map +1 -0
- package/dist/backend/claude-code.d.ts +2 -2
- package/dist/backend/claude-code.js +18 -8
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +8 -0
- package/dist/backend/codex-metadata.js +74 -17
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex.js +15 -2
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +2 -0
- package/dist/backend/credential-profile.js +2 -0
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/types.d.ts +6 -0
- package/dist/backend/types.js +15 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-availability.d.ts +120 -0
- package/dist/backend-availability.js +396 -0
- package/dist/backend-availability.js.map +1 -0
- package/dist/backend-command.d.ts +23 -3
- package/dist/backend-command.js +25 -4
- package/dist/backend-command.js.map +1 -1
- package/dist/bug-report-cli.d.ts +30 -0
- package/dist/bug-report-cli.js +138 -0
- package/dist/bug-report-cli.js.map +1 -0
- package/dist/bug-report.d.ts +47 -0
- package/dist/bug-report.js +136 -0
- package/dist/bug-report.js.map +1 -0
- package/dist/bundled-skills.d.ts +14 -0
- package/dist/bundled-skills.js +29 -0
- package/dist/bundled-skills.js.map +1 -0
- package/dist/cache-ledger.d.ts +16 -3
- package/dist/cache-ledger.js +33 -13
- package/dist/cache-ledger.js.map +1 -1
- package/dist/cache-service.d.ts +55 -3
- package/dist/cache-service.js +152 -16
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
- package/dist/channel/adapters/discord-client-retirement.js +57 -0
- package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +9 -0
- package/dist/channel/adapters/discord.js +49 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-tools.js +22 -11
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +6 -0
- package/dist/classic-channel-manager.d.ts +10 -5
- package/dist/classic-channel-manager.js +12 -9
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +224 -111
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.d.ts +6 -0
- package/dist/config-validator.js +129 -3
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +13 -1
- package/dist/config.js +14 -5
- package/dist/config.js.map +1 -1
- package/dist/cross-instance-notice.d.ts +7 -0
- package/dist/cross-instance-notice.js +10 -0
- package/dist/cross-instance-notice.js.map +1 -1
- package/dist/daemon.d.ts +24 -1
- package/dist/daemon.js +151 -19
- package/dist/daemon.js.map +1 -1
- package/dist/decision-list.d.ts +25 -0
- package/dist/decision-list.js +30 -0
- package/dist/decision-list.js.map +1 -0
- package/dist/delivery-outbox.d.ts +10 -0
- package/dist/delivery-outbox.js +17 -1
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/diagnostic-redaction.d.ts +10 -0
- package/dist/diagnostic-redaction.js +167 -0
- package/dist/diagnostic-redaction.js.map +1 -0
- package/dist/fleet-context.d.ts +10 -0
- package/dist/fleet-manager.d.ts +505 -15
- package/dist/fleet-manager.js +1870 -204
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +18 -0
- package/dist/fleet-process-handlers.js +69 -0
- package/dist/fleet-process-handlers.js.map +1 -0
- package/dist/fleet-traffic.d.ts +74 -0
- package/dist/fleet-traffic.js +196 -0
- package/dist/fleet-traffic.js.map +1 -0
- package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +17 -6
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +6 -1
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +2 -0
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +3 -2
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
- package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +190 -47
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +545 -0
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/human-delivery-receipts.d.ts +24 -1
- package/dist/human-delivery-receipts.js +64 -11
- package/dist/human-delivery-receipts.js.map +1 -1
- package/dist/instance-config-impact.js +7 -1
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +10 -1
- package/dist/instance-lifecycle.js +79 -18
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instance-names.d.ts +4 -0
- package/dist/instance-names.js +12 -0
- package/dist/instance-names.js.map +1 -0
- package/dist/instructions.d.ts +12 -1
- package/dist/instructions.js +13 -2
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +173 -12
- package/dist/locale.js.map +1 -1
- package/dist/log-steps.d.ts +1 -0
- package/dist/log-steps.js +15 -0
- package/dist/log-steps.js.map +1 -1
- package/dist/login-controller.d.ts +45 -0
- package/dist/login-controller.js +101 -5
- package/dist/login-controller.js.map +1 -1
- package/dist/ls-attach-resolve.d.ts +96 -0
- package/dist/ls-attach-resolve.js +180 -0
- package/dist/ls-attach-resolve.js.map +1 -0
- package/dist/ls-rows.d.ts +12 -0
- package/dist/ls-rows.js +82 -3
- package/dist/ls-rows.js.map +1 -1
- package/dist/memory-hogs.d.ts +27 -0
- package/dist/memory-hogs.js +124 -0
- package/dist/memory-hogs.js.map +1 -0
- package/dist/needs-you.d.ts +10 -0
- package/dist/needs-you.js +2 -1
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +11 -0
- package/dist/outbound-handlers.js +139 -11
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +200 -4
- package/dist/outbound-schemas.js +124 -11
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +17 -4
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +9 -0
- package/dist/public-web-link.js +8 -0
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.d.ts +19 -1
- package/dist/quickstart-api.js +94 -4
- package/dist/quickstart-api.js.map +1 -1
- package/dist/reply-buttons-controller.d.ts +4 -0
- package/dist/reply-buttons-controller.js +2 -2
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/restart-progress.d.ts +80 -1
- package/dist/restart-progress.js +306 -21
- package/dist/restart-progress.js.map +1 -1
- package/dist/rollout-index.d.ts +5 -0
- package/dist/rollout-index.js +26 -5
- package/dist/rollout-index.js.map +1 -1
- package/dist/scheduler/db.d.ts +40 -13
- package/dist/scheduler/db.js +123 -89
- package/dist/scheduler/db.js.map +1 -1
- package/dist/scheduler/task-board-text.d.ts +26 -0
- package/dist/scheduler/task-board-text.js +135 -0
- package/dist/scheduler/task-board-text.js.map +1 -0
- package/dist/scheduler/task-board.d.ts +650 -0
- package/dist/scheduler/task-board.js +1938 -0
- package/dist/scheduler/task-board.js.map +1 -0
- package/dist/scheduler/types.d.ts +6 -1
- package/dist/search/search-docs.d.ts +58 -0
- package/dist/search/search-docs.js +63 -0
- package/dist/search/search-docs.js.map +1 -0
- package/dist/search/search-index.d.ts +141 -0
- package/dist/search/search-index.js +440 -0
- package/dist/search/search-index.js.map +1 -0
- package/dist/search/search-store.d.ts +122 -0
- package/dist/search/search-store.js +236 -0
- package/dist/search/search-store.js.map +1 -0
- package/dist/search/search-worker.d.ts +1 -0
- package/dist/search/search-worker.js +163 -0
- package/dist/search/search-worker.js.map +1 -0
- package/dist/service-installer.js +12 -0
- package/dist/service-installer.js.map +1 -1
- package/dist/settings-api.d.ts +23 -0
- package/dist/settings-api.js +164 -3
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +104 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +3 -1
- package/dist/settings-confirmation.js +2 -0
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-effect.js +34 -3
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +11 -0
- package/dist/settings-http-confirmation.js +10 -0
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +23 -7
- package/dist/setup-form.js.map +1 -1
- package/dist/spawn-gate.d.ts +1 -0
- package/dist/spawn-gate.js +13 -3
- package/dist/spawn-gate.js.map +1 -1
- package/dist/task-board-tool.d.ts +25 -0
- package/dist/task-board-tool.js +154 -0
- package/dist/task-board-tool.js.map +1 -0
- package/dist/task-board-waker.d.ts +44 -0
- package/dist/task-board-waker.js +128 -0
- package/dist/task-board-waker.js.map +1 -0
- package/dist/tmux-exec-helper.d.ts +94 -0
- package/dist/tmux-exec-helper.js +407 -0
- package/dist/tmux-exec-helper.js.map +1 -0
- package/dist/tmux-manager.d.ts +5 -0
- package/dist/tmux-manager.js +42 -11
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tool-permissions.d.ts +0 -7
- package/dist/tool-permissions.js +44 -5
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +17 -1
- package/dist/topic-commands.js +45 -19
- package/dist/topic-commands.js.map +1 -1
- package/dist/tunnel/cloudflared.js +37 -2
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/types.d.ts +3 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/types.d.ts +63 -1
- package/dist/ui/app-effects.js +90 -32
- package/dist/ui/backend-signin.js +297 -0
- package/dist/ui/chat-ambient.js +307 -0
- package/dist/ui/chat-effect-posters.js +8 -8
- package/dist/ui/chat-effects.js +110 -15
- package/dist/ui/chat-msg-actions.js +176 -0
- package/dist/ui/chat-render.js +21 -3
- package/dist/ui/chat-store.js +64 -12
- package/dist/ui/chat-strings.js +85 -8
- package/dist/ui/chat-thread.js +204 -21
- package/dist/ui/effect-trial-controller.js +13 -8
- package/dist/ui/effect-trial-panel.js +19 -16
- package/dist/ui/effects-waker.js +70 -0
- package/dist/ui/fleet-canvas-layout.js +117 -0
- package/dist/ui/fleet-canvas.js +555 -0
- package/dist/ui/fleet-org.js +27 -12
- package/dist/ui/fleet-route-scene.js +207 -0
- package/dist/ui/fleet-route-worker.js +21 -0
- package/dist/ui/fleet-route.js +88 -0
- package/dist/ui/fleet-task-card.js +436 -0
- package/dist/ui/fleet-task-common.js +448 -0
- package/dist/ui/fleet-tasks.js +535 -0
- package/dist/ui/fleet-traffic.js +359 -0
- package/dist/ui/fleet-usage.js +435 -0
- package/dist/ui/panel-chat.js +264 -66
- package/dist/ui/panel-details.js +2 -1
- package/dist/ui/panel-fleet.js +65 -83
- package/dist/ui/panel-needs.js +4 -2
- package/dist/ui/panel-settings.js +56 -11
- package/dist/ui/preview.js +3 -2
- package/dist/ui/search-dialog.js +349 -0
- package/dist/ui/settings-appearance.js +44 -19
- package/dist/ui/settings-apply.js +3 -3
- package/dist/ui/settings-catalog.js +92 -0
- package/dist/ui/settings-confirm.js +7 -2
- package/dist/ui/settings-dialogs.js +40 -12
- package/dist/ui/settings-effects.js +4 -3
- package/dist/ui/settings-guests.js +117 -0
- package/dist/ui/settings-learn.js +25 -0
- package/dist/ui/settings-model.js +15 -6
- package/dist/ui/settings-mods.js +23 -9
- package/dist/ui/settings-owner-effects.js +15 -13
- package/dist/ui/settings-strings.js +122 -42
- package/dist/ui/settings-web-authority.js +91 -0
- package/dist/ui/shared/agend-auth.js +1 -1
- package/dist/ui/shared/app-i18n.js +11 -2
- package/dist/ui/shared/app-prefs.js +17 -4
- package/dist/ui/shared/app-route.js +19 -1
- package/dist/ui/shared/app-session.js +2 -0
- package/dist/ui/shared/app-shell.js +174 -30
- package/dist/ui/shared/app-store.js +26 -1
- package/dist/ui/shared/app-stream.js +5 -1
- package/dist/ui/shared/app-themes.js +140 -7
- package/dist/ui/shared/app.css +705 -20
- package/dist/ui/shared/app.js +26 -15
- package/dist/ui/shared/card-strings.js +8 -0
- package/dist/ui/shared/effect-app-runtime.js +68 -19
- package/dist/ui/shared/effect-chat-runtime.js +16 -3
- package/dist/ui/shared/effect-frame.js +26 -7
- package/dist/ui/shared/effect-geometry.js +24 -9
- package/dist/ui/shared/effect-owner-source.js +8 -1
- package/dist/ui/shared/effect-policy.js +21 -7
- package/dist/ui/shared/effect-profiler.js +31 -9
- package/dist/ui/shared/effect-registry.js +97 -50
- package/dist/ui/shared/effect-stock-snapshot.js +9 -0
- package/dist/ui/shared/effect-stock-trust.js +62 -10
- package/dist/ui/shared/effect-trial-shadow.js +62 -0
- package/dist/ui/shared/effect-trial-source.js +1 -1
- package/dist/ui/shared/effect-trial-stage.js +54 -31
- package/dist/ui/shared/effect-trial.css +40 -0
- package/dist/ui/shared/fx-motion.js +67 -0
- package/dist/ui/shared/identity-card.js +100 -11
- package/dist/ui/shared/identity-color.js +14 -10
- package/dist/ui/shared/instance-nav.js +179 -23
- package/dist/ui/shared/owner-css.js +30 -1
- package/dist/ui/shared/panel-view.js +24 -4
- package/dist/ui/shared/tokens.css +9 -3
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/shared/ui-menu.js +20 -7
- package/dist/ui/shared/ui-toast.js +16 -3
- package/dist/ui/shared/usage-dialog.js +34 -3
- package/dist/ui/shared/view-strings.js +72 -0
- package/dist/ui/shared/web-authorize.js +198 -0
- package/dist/ui/web-terminal/terminal.css +4 -4
- package/dist/ui/web-terminal/terminal.html +1 -1
- package/dist/update-launch.d.ts +9 -0
- package/dist/update-launch.js +38 -12
- package/dist/update-launch.js.map +1 -1
- package/dist/usage/format-rich.js +6 -3
- package/dist/usage/format-rich.js.map +1 -1
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +2 -1
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/i18n.d.ts +13 -1
- package/dist/usage/i18n.js +29 -0
- package/dist/usage/i18n.js.map +1 -1
- package/dist/usage/providers.d.ts +81 -2
- package/dist/usage/providers.js +240 -38
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/usage-api.d.ts +5 -1
- package/dist/usage/usage-api.js +184 -58
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/usage-report.d.ts +158 -0
- package/dist/usage-report.js +226 -0
- package/dist/usage-report.js.map +1 -0
- package/dist/usage-rollup.d.ts +51 -0
- package/dist/usage-rollup.js +168 -0
- package/dist/usage-rollup.js.map +1 -0
- package/dist/user-systemd.d.ts +24 -0
- package/dist/user-systemd.js +75 -0
- package/dist/user-systemd.js.map +1 -0
- package/dist/view-api.d.ts +39 -0
- package/dist/view-api.js +69 -6
- package/dist/view-api.js.map +1 -1
- package/dist/web-ambient.d.ts +72 -0
- package/dist/web-ambient.js +161 -0
- package/dist/web-ambient.js.map +1 -0
- package/dist/web-api.d.ts +98 -14
- package/dist/web-api.js +1027 -83
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-policy.d.ts +4 -6
- package/dist/web-appearance-policy.js +5 -12
- package/dist/web-appearance-policy.js.map +1 -1
- package/dist/web-appearance-tools.d.ts +3 -0
- package/dist/web-appearance-tools.js +22 -3
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance-view.d.ts +27 -2
- package/dist/web-appearance-view.js +129 -14
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-appearance.d.ts +17 -3
- package/dist/web-appearance.js +85 -8
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-asset-parts.d.ts +2 -2
- package/dist/web-asset-parts.js +3 -3
- package/dist/web-asset-parts.js.map +1 -1
- package/dist/web-auth.js +3 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-backend-login.d.ts +130 -0
- package/dist/web-backend-login.js +225 -0
- package/dist/web-backend-login.js.map +1 -0
- package/dist/web-card.d.ts +14 -0
- package/dist/web-card.js +40 -6
- package/dist/web-card.js.map +1 -1
- package/dist/web-channel-echo.d.ts +7 -1
- package/dist/web-channel-echo.js +6 -2
- package/dist/web-channel-echo.js.map +1 -1
- package/dist/web-chat-history.d.ts +83 -0
- package/dist/web-chat-history.js +137 -5
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +6 -1
- package/dist/web-commands.js +1 -1
- package/dist/web-commands.js.map +1 -1
- package/dist/web-effect-bootstrap.d.ts +12 -0
- package/dist/web-effect-bootstrap.js +49 -0
- package/dist/web-effect-bootstrap.js.map +1 -0
- package/dist/web-effect-bundle.js +46 -1
- package/dist/web-effect-bundle.js.map +1 -1
- package/dist/web-effect-playback.d.ts +30 -0
- package/dist/web-effect-playback.js +71 -0
- package/dist/web-effect-playback.js.map +1 -0
- package/dist/web-effect-profiles.d.ts +4 -4
- package/dist/web-effect-service.d.ts +11 -4
- package/dist/web-effect-service.js +25 -4
- package/dist/web-effect-service.js.map +1 -1
- package/dist/web-effect-tools.d.ts +1 -0
- package/dist/web-effect-tools.js +4 -4
- package/dist/web-effect-tools.js.map +1 -1
- package/dist/web-effect-trials.d.ts +2 -2
- package/dist/web-effect-trials.js +3 -3
- package/dist/web-effect-trials.js.map +1 -1
- package/dist/web-effect-upload.js +1 -1
- package/dist/web-effect-upload.js.map +1 -1
- package/dist/web-effect-worker.d.ts +1 -1
- package/dist/web-effect-worker.js +2 -2
- package/dist/web-effect-worker.js.map +1 -1
- package/dist/web-effect.d.ts +1 -1
- package/dist/web-guest-access.d.ts +126 -0
- package/dist/web-guest-access.js +238 -0
- package/dist/web-guest-access.js.map +1 -0
- package/dist/web-guest-rooms.d.ts +82 -0
- package/dist/web-guest-rooms.js +135 -0
- package/dist/web-guest-rooms.js.map +1 -0
- package/dist/web-host-guard.d.ts +11 -0
- package/dist/web-host-guard.js +11 -0
- package/dist/web-host-guard.js.map +1 -1
- package/dist/web-identity-color.d.ts +1 -1
- package/dist/web-identity-color.js +2 -2
- package/dist/web-identity-color.js.map +1 -1
- package/dist/web-identity-palette.d.ts +1 -1
- package/dist/web-identity-palette.js +2 -2
- package/dist/web-identity-palette.js.map +1 -1
- package/dist/web-image-meta.d.ts +13 -0
- package/dist/web-image-meta.js +62 -0
- package/dist/web-image-meta.js.map +1 -1
- package/dist/web-libavoid.d.ts +14 -0
- package/dist/web-libavoid.js +46 -0
- package/dist/web-libavoid.js.map +1 -0
- package/dist/web-login.d.ts +47 -0
- package/dist/web-login.js +115 -0
- package/dist/web-login.js.map +1 -1
- package/dist/web-mod-agent.d.ts +1 -1
- package/dist/web-mod-agent.js +7 -5
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-mod-bundle.d.ts +9 -1
- package/dist/web-mod-bundle.js +62 -3
- package/dist/web-mod-bundle.js.map +1 -1
- package/dist/web-mod-export.d.ts +9 -0
- package/dist/web-mod-export.js +21 -0
- package/dist/web-mod-export.js.map +1 -1
- package/dist/web-mod-store.d.ts +7 -1
- package/dist/web-mod-store.js +19 -6
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-owner-css-store.d.ts +44 -1
- package/dist/web-owner-css-store.js +70 -9
- package/dist/web-owner-css-store.js.map +1 -1
- package/dist/web-prefs.d.ts +14 -0
- package/dist/web-prefs.js +37 -4
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +6 -2
- package/dist/web-preview.js +4 -2
- package/dist/web-preview.js.map +1 -1
- package/dist/web-returning-device.d.ts +41 -0
- package/dist/web-returning-device.js +57 -5
- package/dist/web-returning-device.js.map +1 -1
- package/dist/web-session-authorization.d.ts +132 -0
- package/dist/web-session-authorization.js +193 -0
- package/dist/web-session-authorization.js.map +1 -0
- package/dist/web-session.d.ts +70 -10
- package/dist/web-session.js +137 -22
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +49 -2
- package/dist/web-settings-patch.js +145 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +94 -0
- package/dist/web-settings-tools.js +301 -0
- package/dist/web-settings-tools.js.map +1 -0
- package/dist/web-shell-routes.d.ts +1 -1
- package/dist/web-shell-routes.js +1 -1
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-terminal-http.js +15 -2
- package/dist/web-terminal-http.js.map +1 -1
- package/dist/web-theme-store.d.ts +39 -0
- package/dist/web-theme-store.js +122 -11
- package/dist/web-theme-store.js.map +1 -1
- package/dist/web-theme.d.ts +31 -0
- package/dist/web-theme.js +99 -2
- package/dist/web-theme.js.map +1 -1
- package/dist/web-upload.d.ts +13 -0
- package/dist/web-upload.js +39 -3
- package/dist/web-upload.js.map +1 -1
- package/dist/windows-shortcuts.d.ts +78 -0
- package/dist/windows-shortcuts.js +203 -0
- package/dist/windows-shortcuts.js.map +1 -0
- package/dist/workflow-templates/default.md +4 -1
- package/dist/yaml-shared-nodes.d.ts +25 -0
- package/dist/yaml-shared-nodes.js +185 -0
- package/dist/yaml-shared-nodes.js.map +1 -0
- package/launcher/agend-install.cjs +553 -0
- package/launcher/install-admission.cjs +4 -39
- package/launcher/postinstall.cjs +14 -12
- package/package.json +4 -2
- package/scripts/preinstall-guard.cjs +2 -5
- package/templates/windows-shortcuts.ps1 +181 -0
- package/launcher/old-updater-note.cjs +0 -48
package/dist/ui/panel-chat.js
CHANGED
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
// right, the agent's at full width, and one rounded composer pinned below with attach, Stop reply and Send inside it.
|
|
7
7
|
// The instance's own actions (details, start, stop, restart, delete) are in the header's ⋯ menu, and only the ones
|
|
8
8
|
// that apply to its state are offered (#1408 rough edges 4 and 7).
|
|
9
|
-
import { html, useEffect, useLayoutEffect, useRef, useState } from "/assets/app-html.js";
|
|
10
|
-
import { t } from "/assets/app-i18n.js";
|
|
11
|
-
import { appStore, useStore } from "/assets/app-store.js";
|
|
9
|
+
import { html, useCallback, useEffect, useLayoutEffect, useRef, useState } from "/assets/app-html.js";
|
|
10
|
+
import { lang, t } from "/assets/app-i18n.js";
|
|
11
|
+
import { appStore, createStore, guestPage, useStore } from "/assets/app-store.js";
|
|
12
|
+
import { ComposerAuth } from "/assets/web-authorize.js";
|
|
12
13
|
import { useLease } from "/assets/app-ctx.js";
|
|
13
|
-
import { namesOf, namesStore } from "/assets/instance-nav.js";
|
|
14
|
+
import { modelText, namesOf, namesStore, navStore as instanceNavStore } from "/assets/instance-nav.js";
|
|
14
15
|
import { PanelHeader, onPanelKey, setTitle, statusClass, statusLabel, openDrawer, requestNewInstance } from "/assets/app-shell.js";
|
|
15
16
|
import { detailsPath, textLinkSegments } from "/assets/app-route.js";
|
|
16
17
|
import { InstanceSwitch } from "/assets/instance-switch.js";
|
|
@@ -23,30 +24,49 @@ import { Icon } from "/assets/ui-icons.js";
|
|
|
23
24
|
import { toast } from "/assets/ui-toast.js";
|
|
24
25
|
import { confirmDialog } from "/assets/ui-confirm.js";
|
|
25
26
|
import { savePref } from "/assets/app-prefs.js";
|
|
26
|
-
import { applyTheme, resolvedMode, themeFor, themeImageUrl, themeMenuItems, themesStore } from "/assets/app-themes.js";
|
|
27
|
+
import { applyTheme, clearAmbient, resolvedMode, themeFor, themeImageUrl, themeMenuItems, themesStore } from "/assets/app-themes.js";
|
|
27
28
|
import { colorMenuItem } from "/assets/identity-color.js";
|
|
28
|
-
import { IdentityCard, useCard } from "/assets/identity-card.js";
|
|
29
|
+
import { brokenPictures, cardFoldable, IdentityCard, useCard } from "/assets/identity-card.js";
|
|
29
30
|
import { AgentWidget, instanceBinds, widgetFor } from "/assets/agent-widget.js";
|
|
30
31
|
|
|
31
|
-
// #1629 r4 §1: the identity card
|
|
32
|
+
// #1629 r4 §1: the identity card under the chat's header — hidden by default; shown or not is this device's choice.
|
|
33
|
+
// #2217 (the user, 2026-10-19): no row of its own; its picture and bio can be folded away (the banner stays) — this
|
|
34
|
+
// device's choice too, kept the same way. The user (2026-10-20): no control on the card — one card button in the header
|
|
35
|
+
// (a guest's and the public link's header too: they have no ⋯ menu), pressed-looking while the card is shown, opens a
|
|
36
|
+
// small menu of two checkboxes: Show card, and Show picture and bio (disabled while the card is hidden, or when it cannot
|
|
37
|
+
// fold: no banner, or nothing on its row).
|
|
32
38
|
const CHAT_CARD_KEY = "agend_chat_card";
|
|
33
|
-
const
|
|
39
|
+
const CHAT_CARD_ROW_KEY = "agend_chat_card_row";
|
|
40
|
+
const readKey = (k, v) => { try { return localStorage.getItem(k) === v; } catch { return false; } };
|
|
41
|
+
const writeKey = (k, v) => { try { if (v) localStorage.setItem(k, v); else localStorage.removeItem(k); } catch { /* this page only */ } };
|
|
42
|
+
/** Shared by the header's Show card and the card itself, so the two never disagree. */
|
|
43
|
+
export const chatCardPrefs = createStore({ open: readKey(CHAT_CARD_KEY, "open"), rowHidden: readKey(CHAT_CARD_ROW_KEY, "hidden") });
|
|
44
|
+
export const setChatCardOpen = (open) => { writeKey(CHAT_CARD_KEY, open ? "open" : null); chatCardPrefs.set((s) => ({ ...s, open })); };
|
|
45
|
+
export const setChatCardRowHidden = (rowHidden) => { writeKey(CHAT_CARD_ROW_KEY, rowHidden ? "hidden" : null); chatCardPrefs.set((s) => ({ ...s, rowHidden })); };
|
|
34
46
|
function ChatCard({ name, card }) {
|
|
35
|
-
const
|
|
36
|
-
if (!card) return null;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<button type="button" class="chat-card-toggle" aria-expanded=${open ? "true" : "false"} onClick=${toggle}>
|
|
40
|
-
<${Icon} name="chevron" size=${14} cls=${open ? "caret" : "caret flipped"} /><span>${t(open ? "card.hide" : "card.show")}</span>
|
|
41
|
-
${!open && card.tagline ? html`<span class="chat-card-peek">${card.tagline.text}</span>` : null}
|
|
42
|
-
</button>
|
|
43
|
-
${open ? html`<${IdentityCard} name=${name} card=${card} compact=${true} />` : null}
|
|
47
|
+
const prefs = useStore(chatCardPrefs);
|
|
48
|
+
if (!card || !prefs.open) return null;
|
|
49
|
+
return html`<div data-trust="card" class="chat-card open">
|
|
50
|
+
<${IdentityCard} name=${name} card=${card} compact=${true} rowHidden=${prefs.rowHidden} />
|
|
44
51
|
</div>`;
|
|
45
52
|
}
|
|
53
|
+
/** The header's card menu: ☑ Show card, ☑ Show picture and bio. */
|
|
54
|
+
function CardMenu({ card }) {
|
|
55
|
+
const prefs = useStore(chatCardPrefs);
|
|
56
|
+
useStore(brokenPictures); // a banner that failed to load: the card cannot fold, the item greys out
|
|
57
|
+
if (!card) return null;
|
|
58
|
+
const items = [
|
|
59
|
+
{ key: "card", checkbox: true, checked: prefs.open, label: t("card.show"), onSelect: () => setChatCardOpen(!prefs.open) },
|
|
60
|
+
{ key: "row", checkbox: true, checked: !prefs.rowHidden && cardFoldable(card), disabled: !prefs.open || !cardFoldable(card), label: t("card.showRow"),
|
|
61
|
+
onSelect: () => setChatCardRowHidden(!prefs.rowHidden) },
|
|
62
|
+
];
|
|
63
|
+
return html`<${Menu} items=${items} label=${t("card.menu")} icon="idcard" cls="chat-card-menu" active=${prefs.open} />`;
|
|
64
|
+
}
|
|
46
65
|
import "./chat-strings.js";
|
|
47
|
-
import { confirmedWrite } from "./settings-confirm.js";
|
|
66
|
+
import { confirmedWrite, selfConfirmed } from "./settings-confirm.js";
|
|
48
67
|
import { createChatStore } from "./chat-store.js";
|
|
49
68
|
import { createThread, msgKey } from "./chat-thread.js";
|
|
69
|
+
import { installMessageActions } from "./chat-msg-actions.js";
|
|
50
70
|
import { createEmojiIndex } from "./chat-emojis.js";
|
|
51
71
|
import { pollPublicPreview } from "./preview-status.js";
|
|
52
72
|
import { createMentionIndex } from "./chat-mentions.js";
|
|
@@ -56,7 +76,9 @@ import { installTour, refreshTourSpot } from "./chat-tour.js";
|
|
|
56
76
|
import { LightboxHost, openLightbox } from "./image-lightbox.js";
|
|
57
77
|
import { ChatEffectPosters } from "/ui/js/chat-effect-posters.js";
|
|
58
78
|
import { ChatEffects, chatEffectsMenuAvailable } from "./chat-effects.js";
|
|
59
|
-
import {
|
|
79
|
+
import { setFollowsReducedMotion } from "/assets/fx-motion.js";
|
|
80
|
+
import { AmbientMotionNote, ChatAmbient, ambientMenuItems } from "./chat-ambient.js";
|
|
81
|
+
import { startEffectsWaker, getAppEffects, wakeEffects, effectsLoaded, onEffectsAwake, chatHasEffects } from "./effects-waker.js";
|
|
60
82
|
|
|
61
83
|
const R = () => globalThis.AgendChatRender;
|
|
62
84
|
const P = () => globalThis.AgendPreview;
|
|
@@ -116,7 +138,9 @@ export function boot({ stream, boot: bootData, deps = {} }) {
|
|
|
116
138
|
}
|
|
117
139
|
// #1604: the preview opt-in and Tour live in Settings → This device now (and on each preview card's menu).
|
|
118
140
|
installTour();
|
|
119
|
-
|
|
141
|
+
// #2118: viewing current in-scope Chat effects needs no management or personal-slot authority. #2193: the runtime
|
|
142
|
+
// itself loads only when there is something to play (effects-waker.js).
|
|
143
|
+
startEffectsWaker({ store });
|
|
120
144
|
return store;
|
|
121
145
|
}
|
|
122
146
|
|
|
@@ -222,6 +246,9 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
|
222
246
|
const themeKey = JSON.stringify(theme);
|
|
223
247
|
const card = useCard(name, inst.card_v);
|
|
224
248
|
const [dialog, setDialog] = useState(null); // "delete" | null
|
|
249
|
+
const [canvasPlayback, setCanvasPlayback] = useState(null);
|
|
250
|
+
const publishCanvasPlayback = useCallback(value => setCanvasPlayback(previous =>
|
|
251
|
+
!previous && !value.playing || previous?.name === value.name && previous.playing === value.playing ? previous : value), []);
|
|
225
252
|
const [wrap, setWrap] = useState(codeWrap);
|
|
226
253
|
const view = useRef(null), split = useRef(null), thread = useRef(null), bg = useRef(null), effectSurface = useRef(null);
|
|
227
254
|
useLayoutEffect(() => { applyTheme(view.current, theme, mode); }, [themeKey, mode]);
|
|
@@ -231,7 +258,12 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
|
231
258
|
}, [themeKey]);
|
|
232
259
|
useEffect(() => { wrapListeners.add(setWrap); return () => wrapListeners.delete(setWrap); }, []);
|
|
233
260
|
// First visit to this instance's chat on this page: its history (a navigation — it counts as use). Back again: nothing.
|
|
234
|
-
|
|
261
|
+
// #2188: left before it answered (passing through on the way to another chat) — the read is aborted.
|
|
262
|
+
useEffect(() => {
|
|
263
|
+
const ac = typeof AbortController === "function" ? new AbortController() : null;
|
|
264
|
+
store.openHistory(name, lease, ac?.signal);
|
|
265
|
+
return () => ac?.abort();
|
|
266
|
+
}, [name]);
|
|
235
267
|
useEffect(() => { try { localStorage.setItem("agend_last_instance", name); } catch { /* none */ } }, [name]);
|
|
236
268
|
// Files dragged over the chat show where they go; a drop attaches them (counted, so moving over messages does not flicker).
|
|
237
269
|
useEffect(() => {
|
|
@@ -264,6 +296,8 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
|
264
296
|
else if (r && r.held) toast(r.message);
|
|
265
297
|
else toast(t(verb === "start" ? "chat.started" : verb === "stop" ? "chat.stoppedInst" : "chat.restarted", name));
|
|
266
298
|
};
|
|
299
|
+
// #2193: this chat's Canvas Worker placements (its status row's effect_chat_v): none, no effects code runs for it.
|
|
300
|
+
const fxHere = chatHasEffects(name);
|
|
267
301
|
const items = [
|
|
268
302
|
// #1523 N2: Details is a page now (the Fleet side of this instance), not a dialog.
|
|
269
303
|
{ key: "details", label: t("chat.details"), icon: "info", onSelect: () => navigate(detailsPath(name)) },
|
|
@@ -274,24 +308,32 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
|
274
308
|
colorMenuItem(name, inst),
|
|
275
309
|
// #1629: a person's control over this agent's theme — not over the public link (it only views themes).
|
|
276
310
|
...themeMenuItems(name),
|
|
311
|
+
// #2117: its ambient — why it is not showing here (with the way to change that), and a person's Clear.
|
|
312
|
+
...ambientMenuItems(name, { publicLink: document.body.dataset.publicLink === "1", clear: clearAmbient }),
|
|
277
313
|
chatEffectsMenuAvailable() ? { key: "effects", label: t("chatFx.title"), onSelect: () => setDialog("effects") } : null,
|
|
278
314
|
{ key: "delete", label: t("chat.delete"), icon: "trash", danger: true, onSelect: () => setDialog("delete") },
|
|
279
315
|
];
|
|
280
316
|
const cls = statusClass(inst, exec, awaiting);
|
|
317
|
+
// #1920 phase 3: a guest has this chat only — no Details, View or Log to switch to, no lifecycle, colour, theme,
|
|
318
|
+
// effect management or delete (a guest's status frame carries no model or effort either, so those chips do not show).
|
|
319
|
+
const guest = guestPage();
|
|
281
320
|
// #1269 quick actions: the model and effort it runs, each a way to /model or /effort (the same pick list).
|
|
282
321
|
const pick = (command) => store.runCommand(name, command, "", { alive: () => lease.current() });
|
|
283
322
|
const sub = html`<span class="status"><span class=${`dot ${cls}`} aria-hidden="true"></span>${statusLabel(inst, exec, awaiting)}</span>
|
|
284
|
-
${inst.model ? html`<button type="button" class="hd-chip" title=${t("chat.chipModel", inst
|
|
323
|
+
${inst.model ? html`<button type="button" class="hd-chip" title=${t("chat.chipModel", modelText(inst))} aria-label=${t("chat.chipModel", modelText(inst))} onClick=${() => pick("model")}>${modelText(inst)}</button>` : null}
|
|
285
324
|
${inst.effort ? html`<button type="button" class="hd-chip" title=${t("chat.chipEffort", inst.effort)} aria-label=${t("chat.chipEffort", inst.effort)} onClick=${() => pick("effort")}>${inst.effort}</button>` : null}`;
|
|
286
325
|
return html`<div class=${`panel p-chat${wrap ? " wrap-code" : ""}`} ref=${view}>
|
|
287
|
-
<${PanelHeader} title=${headerName(namesOf(inst || { name }, names.primary))} sub=${sub} nav=${html`<${InstanceSwitch} name=${name} current="chat" />`}
|
|
326
|
+
<${PanelHeader} title=${headerName(namesOf(inst || { name }, names.primary))} sub=${sub} nav=${guest ? null : html`<${InstanceSwitch} name=${name} current="chat" />`} notice=${html`<${ChatEffects} name=${name} lease=${lease} element=${effectSurface} store=${store} open=${dialog === "effects"} onPlayback=${publishCanvasPlayback} onClose=${() => setDialog(null)} active=${fxHere} />`}>${fxHere ? html`<${ChatEffectPosters} name=${name} lease=${lease} element=${effectSurface} />` : null}<${CardMenu} card=${card} /><${HeaderTools} navKey=${navKey} />${guest ? null : html`<${Menu} items=${items} label=${t("app.more")} />`}</${PanelHeader}>
|
|
288
327
|
<${ChatCard} key=${name} name=${name} card=${card} />
|
|
289
328
|
<${AgentWidget} slot="chat_header" widget=${widgetFor(name, "chat_header")} binds=${instanceBinds(inst, exec, awaiting)} />
|
|
290
329
|
<div class="chat-split" ref=${split}>
|
|
291
330
|
<div ref=${effectSurface} class=${`chat-main${theme && theme.background ? " has-th-bg" : ""}`}>
|
|
292
331
|
${theme && theme.background ? html`<img ref=${bg} class=${`th-bg th-bg-${theme.background.fit}`} src=${themeImageUrl(name, theme.background.image)} alt="" aria-hidden="true" decoding="async" />` : null}
|
|
332
|
+
<${ChatAmbient} name=${name} surface=${effectSurface} part="layer" />
|
|
333
|
+
<${AmbientMotionNote} name=${name} canvasPlaying=${canvasPlayback?.name === name && canvasPlayback.playing} />
|
|
293
334
|
<${Thread} name=${name} th=${thread} />
|
|
294
335
|
<${Dock} name=${name} inst=${inst} lease=${lease} exec=${exec} awaiting=${awaiting} workingLabel=${theme ? theme.workingLabel : undefined} />
|
|
336
|
+
<${ChatAmbient} name=${name} surface=${effectSurface} part="front" />
|
|
295
337
|
</div>
|
|
296
338
|
<${PreviewPanel} name=${name} split=${split} msgs=${() => store.state.msgs[name] || []} subscribe=${(fn) => store.subscribe(fn)}
|
|
297
339
|
keyOf=${msgKey} reveal=${(k) => thread.current && thread.current.reveal(k)} download=${downloadHtml} allow=${(commit) => setPreviewOptIn(true, commit)} />
|
|
@@ -302,61 +344,186 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
|
302
344
|
</div>`;
|
|
303
345
|
}
|
|
304
346
|
|
|
305
|
-
/**
|
|
347
|
+
/**
|
|
348
|
+
* #2053: the last THREAD_KEEP chats' threads are kept when their view leaves (the chat view is keyed by instance, so
|
|
349
|
+
* each switch built the thread again: a revisit was no faster than a first visit). A kept thread is its list element
|
|
350
|
+
* and its renderer, and nothing more: it leaves as a chat always did (previews stop), with no subscription or timer
|
|
351
|
+
* left; shown again, one render draws only what changed meanwhile, where the reader was. A new language, another
|
|
352
|
+
* document, or more than the budget lets one go.
|
|
353
|
+
*
|
|
354
|
+
* #2184: the budget (raised for people who switch among ~10 favourites): up to THREAD_KEEP threads on a wide screen and
|
|
355
|
+
* THREAD_KEEP_NARROW on a narrow one (a phone), and THREAD_KEEP_NODES drawn messages in all, so memory stays bounded
|
|
356
|
+
* however long the chats are. Over it, the least recently shown goes first — one that is not a favourite before a
|
|
357
|
+
* favourite; the chat on screen never goes.
|
|
358
|
+
*/
|
|
359
|
+
export const THREAD_KEEP = 12;
|
|
360
|
+
export const THREAD_KEEP_NARROW = 6;
|
|
361
|
+
export const THREAD_KEEP_NODES = 2400;
|
|
362
|
+
/**
|
|
363
|
+
* #2188: a chat shown for less than this, on the way to another (clicking down the sidebar), is not kept: it is let go
|
|
364
|
+
* as it leaves, so passing through chats never evicts the ones in use. One that was already kept stays kept.
|
|
365
|
+
*/
|
|
366
|
+
export const THREAD_PASS_MS = 1000;
|
|
367
|
+
const monotonic = () => (typeof performance === "object" && typeof performance.now === "function" ? performance.now() : Date.now());
|
|
368
|
+
let now = monotonic;
|
|
369
|
+
/** Tests only: the clock THREAD_PASS_MS is measured on (null: the page's monotonic clock). */
|
|
370
|
+
export function setThreadClock(fn) { now = typeof fn === "function" ? fn : monotonic; }
|
|
371
|
+
/**
|
|
372
|
+
* The kept threads to let go, in order. `kept`: [name, drawn messages], least recently shown first; `current`: the
|
|
373
|
+
* one on screen (never let go).
|
|
374
|
+
*/
|
|
375
|
+
export function threadsToLetGo(kept, current, { keep, maxNodes, favorites }) {
|
|
376
|
+
let count = kept.length, nodes = kept.reduce((n, [, d]) => n + d, 0);
|
|
377
|
+
const out = [];
|
|
378
|
+
const order = [...kept.filter(([n]) => n !== current && !favorites.has(n)), ...kept.filter(([n]) => n !== current && favorites.has(n))];
|
|
379
|
+
for (const [n, d] of order) {
|
|
380
|
+
if (count <= keep && nodes <= maxNodes) break;
|
|
381
|
+
out.push(n); count--; nodes -= d;
|
|
382
|
+
}
|
|
383
|
+
return out;
|
|
384
|
+
}
|
|
385
|
+
const narrowScreen = () => typeof matchMedia === "function" && matchMedia("(max-width: 899px)").matches;
|
|
386
|
+
/** Let go what the budget does not hold (after `current` was shown, or drew more). */
|
|
387
|
+
function trimKept(current) {
|
|
388
|
+
const kept = [...keptThreads].map(([n, e]) => [n, e.thread.nodes.size]);
|
|
389
|
+
const favorites = new Set(instanceNavStore.get().favorites);
|
|
390
|
+
for (const n of threadsToLetGo(kept, current, { keep: narrowScreen() ? THREAD_KEEP_NARROW : THREAD_KEEP, maxNodes: THREAD_KEEP_NODES, favorites })) {
|
|
391
|
+
letGo(keptThreads.get(n), true); keptThreads.delete(n);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const keptThreads = new Map(); // name → { thread, list, sink, lang }
|
|
395
|
+
/** Tests only: let every kept thread go. */
|
|
396
|
+
export function forgetKeptThreads() { for (const e of keptThreads.values()) letGo(e, true); keptThreads.clear(); }
|
|
397
|
+
function letGo(e, own) { e.thread.dispose(own); e.list.remove(); }
|
|
398
|
+
|
|
399
|
+
/** A chat's thread: its own list element and renderer, and a sink for the view that shows it. */
|
|
400
|
+
function threadEntry(name, doc) {
|
|
401
|
+
const list = doc.createElement("div");
|
|
402
|
+
list.className = "thread";
|
|
403
|
+
list.setAttribute("role", "log");
|
|
404
|
+
list.setAttribute("aria-live", "off");
|
|
405
|
+
list.setAttribute("aria-label", t("chat.conversationWith", name));
|
|
406
|
+
const e = { list, sink: null, lang: lang(), thread: null };
|
|
407
|
+
const thread = createThread(list, doc.createElement("div"), {
|
|
408
|
+
t, tf: t, isUser: (x) => store.isUser(x, name), onJump: (j) => e.sink?.setJump(j), onEmpty: (v) => e.sink?.setEmpty(v),
|
|
409
|
+
setPreviewOptIn, copyText, download: downloadHtml, toggleWrap,
|
|
410
|
+
// #2193: an offer shown while the effects runtime sleeps wakes it; until it answers, the offer is being checked.
|
|
411
|
+
effectTrialStatus: x => { const fx = getAppEffects(); if (fx) return fx.trialStatus(x); if (!effectsLoaded()) { void wakeEffects(); return "checking"; } return "localAdmin"; },
|
|
412
|
+
effectTrialFailure: x => getAppEffects()?.trialFailure(x),
|
|
413
|
+
fixEffectTrial: (x, reason) => {
|
|
414
|
+
if (reason === "reducedMotion") setFollowsReducedMotion(false);
|
|
415
|
+
else if (reason === "busy") getAppEffects()?.stopTrial();
|
|
416
|
+
else if (reason === "transport") location.reload();
|
|
417
|
+
else if (reason === "localAdmin") location.href = "/signin?next=" + encodeURIComponent(location.pathname + location.search);
|
|
418
|
+
else navigate("/settings/appearance");
|
|
419
|
+
},
|
|
420
|
+
canTryEffect: x => getAppEffects()?.canTry(x) === true,
|
|
421
|
+
startEffectTrial: x => { const seq = navStore.get().seq; void getAppEffects()?.startTrial(x).then(ok => { if (!ok && e.sink && navStore.get().seq === seq && document.hasFocus?.() === true && document.visibilityState === "visible") toast(t("chat.effectTrialUnavailable")); }); },
|
|
422
|
+
clickReplyButton: (id, index) => store.clickReplyButton(name, id, index), // #1266
|
|
423
|
+
// #2272: reply to a message (the bar above the composer), and show the one a reply quotes.
|
|
424
|
+
startReply: (x) => { store.startReply(name, x); doc.getElementById("msgIn")?.focus(); },
|
|
425
|
+
findQuoted: (key) => store.findQuoted(name, key),
|
|
426
|
+
notice: (text) => toast(text, false),
|
|
427
|
+
replyButtonBusy: (id) => store.state.rbBusy.has(id),
|
|
428
|
+
pollMine: (id) => store.state.pollMine[id], // #1823: this device's own vote
|
|
429
|
+
serverNow: () => Date.now() + store.state.clockSkew, // #1823: the deadline is the server's
|
|
430
|
+
panel: { shown: shownKey, open: (spec, o) => openPanel(spec, o), version: panelVersion, claim: claimPanel, claims: panelClaims }, // #1481, #1704
|
|
431
|
+
openImage: openLightbox, // an image, full size, in the page
|
|
432
|
+
emojis: (id) => !!emojiIndex && emojiIndex.known(id), // #1630: the fleet's server emoji
|
|
433
|
+
mentions: (kind, id) => (mentionIndex ? mentionIndex.name(kind, id) : null), // #1682: mention names
|
|
434
|
+
});
|
|
435
|
+
e.thread = thread;
|
|
436
|
+
return e;
|
|
437
|
+
}
|
|
438
|
+
/** While a thread is shown: what it follows. Returns what lets it all go. */
|
|
439
|
+
function follow(name, thread) {
|
|
440
|
+
// #1630: the server-emoji list is read once a message shows a tag; when it arrives, those messages are drawn again.
|
|
441
|
+
// #1682: the same for mention names — asked for the ids the messages carry; when names arrive, drawn again.
|
|
442
|
+
const wantEmojis = (msgs) => { if (emojiIndex && emojiIndex.wants(msgs)) emojiIndex.ensure(); if (mentionIndex) mentionIndex.ensure(msgs); };
|
|
443
|
+
const offs = [];
|
|
444
|
+
if (emojiIndex) offs.push(emojiIndex.subscribe(() => thread.render(store.state.msgs[name] || [])));
|
|
445
|
+
if (mentionIndex) offs.push(mentionIndex.subscribe(() => thread.render(store.state.msgs[name] || [])));
|
|
446
|
+
wantEmojis(store.state.msgs[name]);
|
|
447
|
+
offs.push(store.subscribe((instance, kind) => {
|
|
448
|
+
if (instance !== name) return;
|
|
449
|
+
if (kind === "msgs") { thread.render(store.state.msgs[name] || []); wantEmojis(store.state.msgs[name]); }
|
|
450
|
+
else if (kind === "sent") thread.jumpLatest();
|
|
451
|
+
}));
|
|
452
|
+
offs.push(P() ? P().onChange(() => thread.refreshCards()) : () => {});
|
|
453
|
+
// #2193: the runtime may start later (an offer shown wakes it): its trial updates are followed from then.
|
|
454
|
+
let trialOff = null;
|
|
455
|
+
const watchTrial = () => { trialOff = getAppEffects()?.subscribeTrial(() => thread.render(store.state.msgs[name] || [])) ?? null; };
|
|
456
|
+
watchTrial();
|
|
457
|
+
if (!trialOff) offs.push(onEffectsAwake(() => { watchTrial(); thread.render(store.state.msgs[name] || []); }));
|
|
458
|
+
offs.push(() => trialOff?.());
|
|
459
|
+
offs.push(panelStore.subscribe(() => thread.refreshCards())); // a card shows whether the panel has its block
|
|
460
|
+
return () => { for (const off of offs) off(); };
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** The thread's view: Preact owns the scroller and the jump pill; the kept list (chat-thread.js) is put inside it. */
|
|
306
464
|
function Thread({ name, th }) {
|
|
307
|
-
const scroller = useRef(null),
|
|
465
|
+
const scroller = useRef(null), host = useRef(null);
|
|
308
466
|
const [jump, setJump] = useState({ show: false, unseen: 0 });
|
|
309
467
|
const [empty, setEmpty] = useState(false);
|
|
310
468
|
useLayoutEffect(() => {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
469
|
+
const doc = host.current.ownerDocument;
|
|
470
|
+
let e = keptThreads.get(name);
|
|
471
|
+
// Kept only while it can be shown as it is: the same language, and this page's own document.
|
|
472
|
+
if (e && (e.lang !== lang() || e.list.ownerDocument !== doc)) { letGo(e, true); keptThreads.delete(name); e = undefined; }
|
|
473
|
+
const kept = !!e;
|
|
474
|
+
if (e) keptThreads.delete(name);
|
|
475
|
+
else e = threadEntry(name, doc);
|
|
476
|
+
keptThreads.set(name, e); // the most recent last
|
|
477
|
+
// A thread already kept is trimmed against at once; a new one first has to stay (see THREAD_PASS_MS).
|
|
478
|
+
if (kept) trimKept(name);
|
|
479
|
+
const shownAt = now();
|
|
480
|
+
const thread = e.thread, sc = scroller.current, ls = e.list;
|
|
481
|
+
e.sink = { setJump, setEmpty };
|
|
482
|
+
host.current.append(ls);
|
|
483
|
+
thread.attach(sc);
|
|
326
484
|
th.current = thread;
|
|
327
|
-
//
|
|
328
|
-
// #1682: the same for mention names — asked for the ids the messages carry; when names arrive, drawn again.
|
|
329
|
-
const wantEmojis = (msgs) => { if (emojiIndex && emojiIndex.wants(msgs)) emojiIndex.ensure(); if (mentionIndex) mentionIndex.ensure(msgs); };
|
|
330
|
-
const offEmojis = emojiIndex ? emojiIndex.subscribe(() => thread.render(store.state.msgs[name] || [])) : () => {};
|
|
331
|
-
const offMentions = mentionIndex ? mentionIndex.subscribe(() => thread.render(store.state.msgs[name] || [])) : () => {};
|
|
485
|
+
// Up to date, at the reader's place (the bottom unless they had scrolled up); a kept one's cards say what they can do.
|
|
332
486
|
thread.render(store.state.msgs[name] || [], { restore: store.state.scrollMemo[name] ?? null });
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
if (instance !== name) return;
|
|
336
|
-
if (kind === "msgs") { thread.render(store.state.msgs[name] || []); wantEmojis(store.state.msgs[name]); }
|
|
337
|
-
else if (kind === "sent") thread.jumpLatest();
|
|
338
|
-
});
|
|
339
|
-
const offPv = P() ? P().onChange(() => thread.refreshCards()) : () => {};
|
|
340
|
-
const offTrials = getAppEffects()?.subscribeTrial(() => thread.render(store.state.msgs[name] || [])) ?? (() => {});
|
|
341
|
-
const offPanel = panelStore.subscribe(() => thread.refreshCards()); // a card shows whether the panel has its block
|
|
487
|
+
if (kept) thread.refreshCards();
|
|
488
|
+
const unfollow = follow(name, thread);
|
|
342
489
|
const onScroll = () => { store.state.scrollMemo[name] = thread.onScroll(); };
|
|
343
|
-
const sc = scroller.current, ls = list.current;
|
|
344
490
|
sc.addEventListener("scroll", onScroll, { passive: true });
|
|
345
491
|
ls.addEventListener("click", thread.onClick);
|
|
492
|
+
// #2272: the message menu, swipe left / long-press on a phone, R on a focused message.
|
|
493
|
+
const offActions = installMessageActions(ls, {
|
|
494
|
+
t, messageOf: thread.messageOf, rove: thread.rove, reply: (x) => { store.startReply(name, x); document.getElementById("msgIn")?.focus(); },
|
|
495
|
+
copyText, notice: (text, ok = true) => toast(text, ok),
|
|
496
|
+
linkOf: (x) => `${location.origin}/ui/chat/${encodeURIComponent(name)}#m=${msgKey(x)}`,
|
|
497
|
+
});
|
|
498
|
+
// A copied message link (#m=<boot>-<id>): show that message, flashed.
|
|
499
|
+
const linked = /^#m=([0-9a-f]{1,32}-\d{1,15})$/.exec(location.hash);
|
|
500
|
+
if (linked) void thread.jumpTo(linked[1]);
|
|
501
|
+
// #2293: search opening a message of this chat while it is shown — the address's #m= changes, the route does not.
|
|
502
|
+
// Only this chat's address: during a jump to another chat this one is still mounted for a moment.
|
|
503
|
+
const onHash = () => {
|
|
504
|
+
const m = /^#m=([0-9a-f]{1,32}-\d{1,15})$/.exec(location.hash);
|
|
505
|
+
if (m && location.pathname === `/ui/chat/${encodeURIComponent(name)}`) void thread.jumpTo(m[1]);
|
|
506
|
+
};
|
|
507
|
+
window.addEventListener("hashchange", onHash);
|
|
346
508
|
return () => {
|
|
347
|
-
|
|
348
|
-
|
|
509
|
+
window.removeEventListener("hashchange", onHash);
|
|
510
|
+
unfollow();
|
|
511
|
+
offActions();
|
|
349
512
|
sc.removeEventListener("scroll", onScroll);
|
|
350
513
|
ls.removeEventListener("click", thread.onClick);
|
|
351
|
-
|
|
514
|
+
e.sink = null;
|
|
352
515
|
th.current = null;
|
|
516
|
+
// Passed through (new, and shown under THREAD_PASS_MS): let go. Otherwise kept for a later visit, within the budget.
|
|
517
|
+
if (keptThreads.get(name) === e && !kept && now() - shownAt < THREAD_PASS_MS) { keptThreads.delete(name); letGo(e, false); }
|
|
518
|
+
else if (keptThreads.get(name) === e) { thread.park(); ls.remove(); trimKept(null); } // kept for a later visit: the chat left
|
|
519
|
+
else letGo(e, false); // let go meanwhile (a new language)
|
|
353
520
|
};
|
|
354
521
|
}, [name]);
|
|
355
522
|
return html`<div class="scroller" ref=${scroller}>
|
|
356
|
-
<div class="thread" ref=${
|
|
523
|
+
<div class="thread-host" ref=${host}></div>
|
|
357
524
|
${empty ? html`<${Empty} icon="chat" title=${t("chat.noMessages")} />` : null}
|
|
358
|
-
|
|
359
|
-
<${Icon} name="down" size=${16} />${jump.unseen > 0 ? t("chat.newBelow", jump.unseen) : t("chat.jumpLatest")}</button>` : null}
|
|
525
|
+
<div class="jump-dock">${jump.show ? html`<button data-trust="thread-control" type="button" class="jump-latest" onClick=${() => th.current && th.current.jumpLatest()}>
|
|
526
|
+
<${Icon} name="down" size=${16} />${jump.unseen > 0 ? t("chat.newBelow", jump.unseen) : t("chat.jumpLatest")}</button>` : null}</div>
|
|
360
527
|
</div>`;
|
|
361
528
|
}
|
|
362
529
|
|
|
@@ -372,11 +539,22 @@ function Dock({ name, inst, lease, exec, awaiting, workingLabel }) {
|
|
|
372
539
|
${s.failedSends[name] ? html`<div class="failed-send" role="alert"><span>${t("chat.notSent")}</span><span class="txt">${s.failedSends[name]}</span>
|
|
373
540
|
<button type="button" class="btn btn-primary btn-sm" onClick=${() => store.putBack(name)}>${t("chat.putBack")}</button>
|
|
374
541
|
<button type="button" class="btn btn-sm" onClick=${() => store.discardFailed(name)}>${t("chat.discard")}</button></div>` : null}
|
|
542
|
+
${s.waking[name] ? html`<p class="send-waking" role="status">${t("chat.waking", name)}</p>` : null}
|
|
543
|
+
${s.sendFailures[name] ? html`<div class="failed-send send-failure" role="alert"><span>${s.sendFailures[name].error}</span>
|
|
544
|
+
<button type="button" class="btn btn-sm" disabled=${!store.canRetrySend(name)} onClick=${() => store.retrySend(name)}>${t("chat.retrySend")}</button></div>` : null}
|
|
375
545
|
<${Composer} name=${name} lease=${lease} busy=${R().isBusy(exec)} />
|
|
376
|
-
<
|
|
546
|
+
<div class="composer-row">${guestPage() ? html`<span class="guest-note" title=${t("chat.guestNote")}>${t("chat.guestNote")}</span>` : html`<${ComposerAuth} />`}<span
|
|
547
|
+
class="hint" title=${t(guestPage() ? "chat.guestMore" : "chat.composerMore")}>${t("chat.composerHint")}</span></div>
|
|
377
548
|
</div></div>`;
|
|
378
549
|
}
|
|
379
550
|
|
|
551
|
+
/** #2233: the public link's page — the dashboard's Sign in is refused there, so it is never offered (#2262 review). */
|
|
552
|
+
const publicLinkPage = () => typeof document !== "undefined" && !!document.body && document.body.dataset.publicLink === "1";
|
|
553
|
+
/** #2233: a backend's "not signed in" choice offers Sign in (the module behind the session gate, loaded when asked). */
|
|
554
|
+
function openBackendSignIn(backend) {
|
|
555
|
+
import("./backend-signin.js").then((m) => m.openSignIn({ backend }), () => toast(t("app.loadFailed"), false));
|
|
556
|
+
}
|
|
557
|
+
|
|
380
558
|
/** #1269: what the last chat command answered — its text, why it was refused, or a list to choose from. */
|
|
381
559
|
function CommandCard({ name, lease }) {
|
|
382
560
|
const c = store.state.commands[name];
|
|
@@ -393,7 +571,10 @@ function CommandCard({ name, lease }) {
|
|
|
393
571
|
: c.compact === "lost" ? t("chat.compactLost") : c.compact === "not_compacted" ? t("chat.compactNotCompacted") : t("chat.compactUnknown")}</p>` : null}
|
|
394
572
|
${c.choices && c.choices.prompt ? html`<pre class="cmd-text">${c.choices.prompt}</pre>` : null}
|
|
395
573
|
${c.choices ? html`<div class="cmd-choices" role="group" aria-label=${t("chat.cmdChoose")}>${c.choices.options.map((o) => html`<button key=${o.id} type="button"
|
|
396
|
-
class=${`btn btn-sm${o.id === c.choices.current ? " current" : ""}`} aria-current=${o.id === c.choices.current ? "true" : undefined}
|
|
574
|
+
class=${`btn btn-sm${o.id === c.choices.current ? " current" : ""}`} aria-current=${o.id === c.choices.current ? "true" : undefined}
|
|
575
|
+
disabled=${!!o.disabled} title=${o.disabled || undefined} onClick=${() => { if (!o.disabled) run(o.id); }}>${o.label}</button>`)}</div>` : null}
|
|
576
|
+
${c.choices && c.choices.options.some((o) => o.signIn) && !publicLinkPage() ? html`<div class="cmd-choices" role="group" aria-label=${t("chat.cmdSignIn")}>${c.choices.options.filter((o) => o.signIn).map((o) => html`<button
|
|
577
|
+
key=${`signin:${o.signIn}`} type="button" class="btn btn-sm btn-primary" onClick=${() => openBackendSignIn(o.signIn)}>${t("chat.cmdSignInTo", o.signIn)}</button>`)}</div>` : null}
|
|
397
578
|
</div>`;
|
|
398
579
|
}
|
|
399
580
|
|
|
@@ -440,6 +621,12 @@ function WorkBar({ name, lease, exec, awaiting, workingLabel }) {
|
|
|
440
621
|
: html`<span class="elapsed" title=${t("chat.elapsedTitle")} aria-hidden="true">${since == null ? "" : R().formatElapsed(performance.now() - since)}</span>`}</div>`;
|
|
441
622
|
}
|
|
442
623
|
|
|
624
|
+
/** #2272: the reply bar's quote — the first ~80 characters, or what it had instead of text. */
|
|
625
|
+
function replySnippet(r) {
|
|
626
|
+
const text = r.text ? (r.text.length > 80 ? `${r.text.slice(0, 79).trimEnd()}…` : r.text) : "";
|
|
627
|
+
return text || (r.media === "photo" ? t("chat.replyPhoto") : r.media === "document" ? t("chat.replyFile") : "");
|
|
628
|
+
}
|
|
629
|
+
|
|
443
630
|
function Composer({ name, lease, busy }) {
|
|
444
631
|
const s = store.state;
|
|
445
632
|
const input = useRef(null), fileIn = useRef(null);
|
|
@@ -448,9 +635,12 @@ function Composer({ name, lease, busy }) {
|
|
|
448
635
|
const [closedFor, setClosedFor] = useState(null); // the draft the palette was closed on (Esc); it opens again on change
|
|
449
636
|
const value = s.drafts[name] || "";
|
|
450
637
|
const files = s.pendingFiles[name] || [];
|
|
638
|
+
const reply = s.replies[name]; // #2272: the message this one will reply to
|
|
451
639
|
const content = !!value.trim() || files.length > 0;
|
|
452
|
-
// A file waiting: what goes is a message with its file, never a command (no palette, no command line).
|
|
453
|
-
|
|
640
|
+
// A file waiting: what goes is a message with its file, never a command (no palette, no command line). A guest never
|
|
641
|
+
// runs one (#1920: the server refuses its slash text), so it has no palette either.
|
|
642
|
+
const guest = guestPage();
|
|
643
|
+
const palette = guest || files.length || closedFor === value ? null : paletteFor(value);
|
|
454
644
|
const pick = palette && palette.length ? palette[Math.min(sel, palette.length - 1)] : null;
|
|
455
645
|
// Grow with the text, up to a limit: set through the CSSOM, never a style attribute (#1300).
|
|
456
646
|
useLayoutEffect(() => { const el = input.current; if (!el) return; el.style.height = "auto"; el.style.height = `${Math.min(el.scrollHeight, 240)}px`; }, [value]);
|
|
@@ -471,6 +661,8 @@ function Composer({ name, lease, busy }) {
|
|
|
471
661
|
else complete(pick);
|
|
472
662
|
return;
|
|
473
663
|
}
|
|
664
|
+
// #1920: a guest's "/…" would be refused as a command — said here, the draft kept to edit.
|
|
665
|
+
if (guest && /^\s*\//.test(value)) { toast(t("chat.guestNoCommands"), false); return; }
|
|
474
666
|
const cmd = files.length ? null : parseCommandLine(value);
|
|
475
667
|
if (cmd && needsArgument(cmd.command) && !cmd.args) { setValue(`/${cmd.command} `); return; }
|
|
476
668
|
if (cmd) { runLine(cmd); return; }
|
|
@@ -484,6 +676,7 @@ function Composer({ name, lease, busy }) {
|
|
|
484
676
|
}
|
|
485
677
|
if (pick && e.key === "Tab" && !e.shiftKey) { e.preventDefault(); complete(pick); return; }
|
|
486
678
|
if (palette && e.key === "Escape" && !e.isComposing) { e.preventDefault(); setClosedFor(value); return; }
|
|
679
|
+
if (reply && e.key === "Escape" && !e.isComposing) { e.preventDefault(); store.clearReply(name); return; } // #2272
|
|
487
680
|
if (R().composerKey(e) === "send") { e.preventDefault(); submit(); }
|
|
488
681
|
};
|
|
489
682
|
const onInput = (e) => { setValue(e.target.value); };
|
|
@@ -502,6 +695,11 @@ function Composer({ name, lease, busy }) {
|
|
|
502
695
|
<span class="cmd-name mono">/${c.name}${c.arg ? html` <span class="cmd-arg">${c.arg}</span>` : null}</span><span class="cmd-desc">${t(`chat.cmd_${c.name}`)}</span></li>`)
|
|
503
696
|
: html`<li class="cmd-none" role="option" aria-selected="false">${t("chat.cmdNotCommand")}</li>`}
|
|
504
697
|
</ul>` : null}
|
|
698
|
+
${reply ? html`<div class="reply-bar" data-trust="composer" role="status">
|
|
699
|
+
<span class="reply-mark" aria-hidden="true"><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"><path d="M9 14 4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 0 11H11"/></svg></span><span class="reply-label">${t("chat.replyingTo", reply.sender)}</span>
|
|
700
|
+
<span class="reply-text">${replySnippet(reply)}</span>
|
|
701
|
+
<button type="button" class="icon-btn reply-cancel" title=${t("chat.replyCancel")} aria-label=${t("chat.replyCancel")} onClick=${() => { store.clearReply(name); input.current?.focus(); }}><${Icon} name="close" size=${14} /></button>
|
|
702
|
+
</div>` : null}
|
|
505
703
|
${files.length ? html`<div class="pending-files">${files.map((f, i) => html`<${FileChip} key=${`${f.name}-${i}`} f=${f} i=${i} name=${name} />`)}</div>` : null}
|
|
506
704
|
<div class="composer">
|
|
507
705
|
<button id="attachBtn" type="button" class="icon-btn" title=${t("chat.attachTitle")} aria-label=${t("chat.attachTitle")} onClick=${() => fileIn.current && fileIn.current.click()}><${Icon} name="attach" /></button>
|
|
@@ -553,7 +751,7 @@ function DeleteDialog({ name, onClose }) {
|
|
|
553
751
|
// navigates anything (the person may be anywhere by then).
|
|
554
752
|
try {
|
|
555
753
|
const res = await confirmedWrite(`/ui/instances/${encodeURIComponent(name)}/delete`, { method: "POST", body: { confirm: typed }, label: t("chat.deleteTitle", name),
|
|
556
|
-
onPending: () => { handedOver = true; toast(t("app.pendingSent")); if (lease.current()) { setBusy(false); onClose(); } } });
|
|
754
|
+
onPending: (_id, view) => { handedOver = true; toast(t(selfConfirmed(view) ? "app.pendingSelfSent" : "app.pendingSent")); if (lease.current()) { setBusy(false); onClose(); } } });
|
|
557
755
|
r = res.ok ? res.body || {} : { error: (res.body && res.body.error) || `HTTP ${res.status}` };
|
|
558
756
|
} catch (err) { r = { error: err && err.message ? err.message : t("chat.disconnected") }; }
|
|
559
757
|
if (r && r.error) { toast(r.error, false); if (!handedOver && lease.current()) setBusy(false); return; }
|
package/dist/ui/panel-details.js
CHANGED
|
@@ -14,6 +14,7 @@ import { PanelHeader, setTitle, statusClass, statusLabel, openDrawer } from "/as
|
|
|
14
14
|
import { navigate } from "/assets/app-nav.js";
|
|
15
15
|
import { settingsPath } from "/assets/app-route.js";
|
|
16
16
|
import { InstanceSwitch } from "/assets/instance-switch.js";
|
|
17
|
+
import { modelText } from "/assets/instance-nav.js";
|
|
17
18
|
import { HeaderTools } from "/assets/header-tools.js";
|
|
18
19
|
import { Menu } from "/assets/ui-menu.js";
|
|
19
20
|
import { themeMenuItems, themesStore } from "/assets/app-themes.js";
|
|
@@ -143,7 +144,7 @@ function DetailsView({ name, inst, navKey, exec, awaiting }) {
|
|
|
143
144
|
<button type="button" class="btn btn-sm d-edit-settings" onClick=${editInSettings}>${t("chat.dEditInSettings")}</button></div></section>
|
|
144
145
|
<section class="card"><h3>${t("chat.dRuntime")}</h3>
|
|
145
146
|
${row(t("chat.dBackend"), d.backend || "--")}
|
|
146
|
-
${row(t("chat.dModel"), `${d.model || sl.model?.display_name || "--"}${d.model_source === "live" ? "" : src(d.model_source)}`)}
|
|
147
|
+
${row(t("chat.dModel"), `${(d.model && modelText(d)) || sl.model?.display_name || "--"}${d.model_source === "live" ? "" : src(d.model_source)}`)}
|
|
147
148
|
${d.effort ? row(t("chat.dEffort"), `${d.effort}${src(d.effort_source)}`) : null}
|
|
148
149
|
${row(t("chat.dCost"), `$${cost.toFixed(2)} ${t("chat.dCostNote")}`)}
|
|
149
150
|
${row(t("chat.dContext"), html`<span class="pct">${ctx != null ? `${Math.round(ctx)}%` : "--"}</span>${ctx != null ? bar(ctx, ctx > 80 ? "warn" : "") : null}`)}
|