@songsid/agend 2.2.0 → 2.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-cli-instructions.md +5 -2
- package/dist/agent-cli.js +284 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +2 -0
- package/dist/agent-endpoint.js +29 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.d.ts +38 -0
- package/dist/agent-file-read.js +317 -0
- package/dist/agent-file-read.js.map +1 -0
- package/dist/agent-whats-new.d.ts +11 -0
- package/dist/agent-whats-new.js +34 -2
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/atomic-write.js +9 -1
- package/dist/atomic-write.js.map +1 -1
- package/dist/auth-api.d.ts +30 -1
- package/dist/auth-api.js +61 -12
- 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/antigravity.js +3 -3
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +2 -2
- package/dist/backend/claude-code.js +10 -5
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/launch-effort.js +1 -1
- package/dist/backend/launch-effort.js.map +1 -1
- package/dist/backend/muse.js +10 -2
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +14 -0
- package/dist/backend/types.js +25 -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 +21 -3
- package/dist/backend-command.js +23 -4
- package/dist/backend-command.js.map +1 -1
- 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-analysis.d.ts +47 -1
- package/dist/cache-analysis.js +68 -8
- package/dist/cache-analysis.js.map +1 -1
- 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-report-tool.d.ts +17 -0
- package/dist/cache-report-tool.js +40 -0
- package/dist/cache-report-tool.js.map +1 -0
- package/dist/cache-service.d.ts +70 -3
- package/dist/cache-service.js +178 -17
- 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 +11 -0
- package/dist/channel/adapters/discord.js +66 -6
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +8 -1
- package/dist/channel/adapters/telegram.js +74 -4
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +48 -2
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +21 -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 +142 -110
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +119 -4
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +10 -0
- package/dist/daemon.js +327 -31
- 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 +12 -1
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/fleet-context.d.ts +15 -0
- package/dist/fleet-manager.d.ts +514 -12
- package/dist/fleet-manager.js +1885 -163
- 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/credential-profiles/SKILL.md +20 -5
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +6 -1
- 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/web-appearance/SKILL.md +492 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +482 -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-avatar.js +3 -0
- package/dist/instance-avatar.js.map +1 -1
- package/dist/instance-config-impact.js +6 -1
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +2 -0
- package/dist/instance-lifecycle.js +20 -10
- 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 +100 -8
- package/dist/locale.js.map +1 -1
- package/dist/ls-attach-resolve.d.ts +95 -0
- package/dist/ls-attach-resolve.js +174 -0
- package/dist/ls-attach-resolve.js.map +1 -0
- 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-hub.d.ts +4 -0
- package/dist/needs-you-hub.js +31 -6
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +1 -13
- package/dist/needs-you.js +3 -37
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +15 -0
- package/dist/outbound-handlers.js +152 -11
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +228 -4
- package/dist/outbound-schemas.js +147 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +21 -1
- 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 +10 -1
- package/dist/quickstart-api.js +12 -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/repo-worktree-guard.d.ts +36 -0
- package/dist/repo-worktree-guard.js +143 -0
- package/dist/repo-worktree-guard.js.map +1 -0
- package/dist/restart-progress.d.ts +65 -1
- package/dist/restart-progress.js +236 -10
- 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/scheduler.d.ts +70 -1
- package/dist/scheduler/scheduler.js +256 -17
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/service-installer.d.ts +2 -1
- package/dist/service-installer.js +18 -3
- package/dist/service-installer.js.map +1 -1
- package/dist/settings-api.d.ts +23 -0
- package/dist/settings-api.js +233 -2
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +112 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +32 -2
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.js +5 -0
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/tmux-manager.d.ts +5 -0
- package/dist/tmux-manager.js +16 -0
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tool-permissions.d.ts +4 -6
- package/dist/tool-permissions.js +100 -2
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +17 -7
- package/dist/topic-commands.js +39 -21
- package/dist/topic-commands.js.map +1 -1
- package/dist/topic-link.d.ts +128 -0
- package/dist/topic-link.js +269 -0
- package/dist/topic-link.js.map +1 -0
- package/dist/types.d.ts +61 -1
- package/dist/ui/app-effects.js +245 -0
- package/dist/ui/chat-ambient.js +307 -0
- package/dist/ui/chat-effect-posters.js +42 -0
- package/dist/ui/chat-effects.js +160 -0
- package/dist/ui/chat-live-replies.js +58 -0
- package/dist/ui/chat-render.js +25 -7
- package/dist/ui/chat-store.js +41 -13
- package/dist/ui/chat-strings.js +86 -2
- package/dist/ui/chat-thread.js +204 -37
- package/dist/ui/chat-tour.js +1 -1
- package/dist/ui/effect-trial-controller.js +124 -0
- package/dist/ui/effect-trial-offer.js +31 -0
- package/dist/ui/effect-trial-panel.js +40 -0
- package/dist/ui/fleet-cache.js +23 -1
- package/dist/ui/fleet-canvas-layout.js +111 -0
- package/dist/ui/fleet-canvas.js +525 -0
- package/dist/ui/fleet-org.js +27 -12
- package/dist/ui/fleet-traffic.js +343 -0
- package/dist/ui/fleet-usage.js +401 -0
- package/dist/ui/image-lightbox.js +1 -1
- package/dist/ui/panel-chat.js +252 -58
- package/dist/ui/panel-details.js +20 -6
- package/dist/ui/panel-fleet.js +45 -19
- package/dist/ui/panel-log.js +6 -6
- package/dist/ui/panel-needs.js +3 -3
- package/dist/ui/panel-settings.js +58 -13
- package/dist/ui/preview-panel.js +25 -9
- package/dist/ui/preview.js +3 -2
- package/dist/ui/settings-appearance.js +349 -0
- package/dist/ui/settings-catalog.js +92 -0
- package/dist/ui/settings-dialogs.js +40 -12
- package/dist/ui/settings-effects.js +202 -0
- 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 +271 -0
- package/dist/ui/settings-owner-effects.js +80 -0
- package/dist/ui/settings-strings.js +335 -10
- package/dist/ui/settings-web-authority.js +91 -0
- package/dist/ui/shared/agend-auth.js +28 -4
- package/dist/ui/shared/agent-widget.js +248 -0
- package/dist/ui/shared/app-i18n.js +6 -2
- package/dist/ui/shared/app-prefs.js +34 -13
- package/dist/ui/shared/app-route.js +42 -2
- package/dist/ui/shared/app-session.js +3 -1
- package/dist/ui/shared/app-shell.js +119 -41
- package/dist/ui/shared/app-store.js +28 -1
- package/dist/ui/shared/app-stream.js +14 -7
- package/dist/ui/shared/app-themes.js +206 -0
- package/dist/ui/shared/app.css +566 -5
- package/dist/ui/shared/app.js +23 -10
- package/dist/ui/shared/card-strings.js +32 -0
- package/dist/ui/shared/effect-app-runtime.js +297 -0
- package/dist/ui/shared/effect-baseline.js +64 -0
- package/dist/ui/shared/effect-chat-runtime.js +167 -0
- package/dist/ui/shared/effect-cursor.js +125 -0
- package/dist/ui/shared/effect-frame.js +146 -0
- package/dist/ui/shared/effect-geometry.js +137 -0
- package/dist/ui/shared/effect-host-style.js +10 -0
- package/dist/ui/shared/effect-owner-regions.js +74 -0
- package/dist/ui/shared/effect-owner-source.js +122 -0
- package/dist/ui/shared/effect-policy.js +151 -0
- package/dist/ui/shared/effect-poster-reader.js +98 -0
- package/dist/ui/shared/effect-posters.js +117 -0
- package/dist/ui/shared/effect-profiler.js +184 -0
- package/dist/ui/shared/effect-profiles.js +65 -0
- package/dist/ui/shared/effect-registry.js +543 -0
- package/dist/ui/shared/effect-runtime-loader.js +234 -0
- package/dist/ui/shared/effect-safety.js +153 -0
- package/dist/ui/shared/effect-stock-snapshot.js +43 -0
- package/dist/ui/shared/effect-stock-trust.js +217 -0
- package/dist/ui/shared/effect-trial-shadow.js +62 -0
- package/dist/ui/shared/effect-trial-source.js +103 -0
- package/dist/ui/shared/effect-trial-stage.js +170 -0
- package/dist/ui/shared/effect-trial.css +40 -0
- package/dist/ui/shared/fx-motion.js +67 -0
- package/dist/ui/shared/header-tools.js +1 -1
- package/dist/ui/shared/identity-card.js +273 -0
- package/dist/ui/shared/identity-color.js +261 -0
- package/dist/ui/shared/instance-nav.js +215 -41
- package/dist/ui/shared/owner-css.js +250 -0
- package/dist/ui/shared/owner-effect-prefs.js +117 -0
- package/dist/ui/shared/panel-view.js +103 -10
- package/dist/ui/shared/signin.js +2 -0
- package/dist/ui/shared/tokens.css +9 -3
- package/dist/ui/shared/ui-dialog.js +1 -1
- package/dist/ui/shared/ui-icons.js +3 -0
- package/dist/ui/shared/ui-menu.js +1 -1
- package/dist/ui/shared/ui-toast.js +1 -1
- package/dist/ui/shared/usage-dialog.js +22 -2
- package/dist/ui/shared/view-strings.js +98 -2
- package/dist/ui/shared/web-authorize.js +151 -0
- package/dist/ui/signin.html +1 -0
- package/dist/ui/web-terminal/terminal.css +4 -4
- package/dist/usage/providers.d.ts +28 -0
- package/dist/usage/providers.js +126 -36
- package/dist/usage/providers.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/view-api.d.ts +68 -0
- package/dist/view-api.js +249 -8
- 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 +117 -7
- package/dist/web-api.js +1283 -70
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-limits.d.ts +82 -0
- package/dist/web-appearance-limits.js +83 -0
- package/dist/web-appearance-limits.js.map +1 -0
- package/dist/web-appearance-policy.d.ts +64 -0
- package/dist/web-appearance-policy.js +87 -0
- package/dist/web-appearance-policy.js.map +1 -0
- package/dist/web-appearance-tools.d.ts +53 -0
- package/dist/web-appearance-tools.js +124 -0
- package/dist/web-appearance-tools.js.map +1 -0
- package/dist/web-appearance-view.d.ts +124 -0
- package/dist/web-appearance-view.js +278 -0
- package/dist/web-appearance-view.js.map +1 -0
- package/dist/web-appearance.d.ts +93 -0
- package/dist/web-appearance.js +373 -0
- package/dist/web-appearance.js.map +1 -0
- package/dist/web-asset-parts.d.ts +93 -0
- package/dist/web-asset-parts.js +133 -0
- package/dist/web-asset-parts.js.map +1 -0
- package/dist/web-auth.js +20 -2
- package/dist/web-auth.js.map +1 -1
- package/dist/web-card.d.ts +110 -0
- package/dist/web-card.js +266 -0
- package/dist/web-card.js.map +1 -0
- 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 +63 -0
- package/dist/web-chat-history.js +109 -6
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +1 -0
- 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.d.ts +28 -0
- package/dist/web-effect-bundle.js +171 -0
- package/dist/web-effect-bundle.js.map +1 -0
- package/dist/web-effect-canonical.d.ts +8 -0
- package/dist/web-effect-canonical.js +27 -0
- package/dist/web-effect-canonical.js.map +1 -0
- package/dist/web-effect-library.d.ts +114 -0
- package/dist/web-effect-library.js +530 -0
- package/dist/web-effect-library.js.map +1 -0
- package/dist/web-effect-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-poster.d.ts +8 -0
- package/dist/web-effect-poster.js +52 -0
- package/dist/web-effect-poster.js.map +1 -0
- package/dist/web-effect-profiles.d.ts +118 -0
- package/dist/web-effect-profiles.js +180 -0
- package/dist/web-effect-profiles.js.map +1 -0
- package/dist/web-effect-service.d.ts +93 -0
- package/dist/web-effect-service.js +335 -0
- package/dist/web-effect-service.js.map +1 -0
- package/dist/web-effect-tools.d.ts +48 -0
- package/dist/web-effect-tools.js +129 -0
- package/dist/web-effect-tools.js.map +1 -0
- package/dist/web-effect-trials.d.ts +86 -0
- package/dist/web-effect-trials.js +204 -0
- package/dist/web-effect-trials.js.map +1 -0
- package/dist/web-effect-upload.d.ts +27 -0
- package/dist/web-effect-upload.js +185 -0
- package/dist/web-effect-upload.js.map +1 -0
- package/dist/web-effect-worker.d.ts +8 -0
- package/dist/web-effect-worker.js +170 -0
- package/dist/web-effect-worker.js.map +1 -0
- package/dist/web-effect.d.ts +103 -0
- package/dist/web-effect.js +153 -0
- package/dist/web-effect.js.map +1 -0
- package/dist/web-guest-access.d.ts +125 -0
- package/dist/web-guest-access.js +234 -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-identity-color.d.ts +87 -0
- package/dist/web-identity-color.js +209 -0
- package/dist/web-identity-color.js.map +1 -0
- package/dist/web-identity-palette.d.ts +113 -0
- package/dist/web-identity-palette.js +84 -0
- package/dist/web-identity-palette.js.map +1 -0
- package/dist/web-image-meta.d.ts +38 -0
- package/dist/web-image-meta.js +262 -0
- package/dist/web-image-meta.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 +50 -0
- package/dist/web-mod-agent.js +207 -0
- package/dist/web-mod-agent.js.map +1 -0
- package/dist/web-mod-bundle.d.ts +157 -0
- package/dist/web-mod-bundle.js +529 -0
- package/dist/web-mod-bundle.js.map +1 -0
- package/dist/web-mod-export.d.ts +68 -0
- package/dist/web-mod-export.js +100 -0
- package/dist/web-mod-export.js.map +1 -0
- package/dist/web-mod-store.d.ts +289 -0
- package/dist/web-mod-store.js +638 -0
- package/dist/web-mod-store.js.map +1 -0
- package/dist/web-org.d.ts +3 -3
- package/dist/web-org.js +11 -17
- package/dist/web-org.js.map +1 -1
- package/dist/web-owner-css-store.d.ts +222 -0
- package/dist/web-owner-css-store.js +440 -0
- package/dist/web-owner-css-store.js.map +1 -0
- package/dist/web-owner-css.d.ts +58 -0
- package/dist/web-owner-css.js +552 -0
- package/dist/web-owner-css.js.map +1 -0
- package/dist/web-prefs.d.ts +62 -0
- package/dist/web-prefs.js +232 -36
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +15 -3
- package/dist/web-preview.js +28 -9
- 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 +67 -2
- package/dist/web-settings-patch.js +196 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +89 -0
- package/dist/web-settings-tools.js +273 -0
- package/dist/web-settings-tools.js.map +1 -0
- package/dist/web-shell-routes.d.ts +2 -2
- package/dist/web-shell-routes.js +2 -2
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-theme-store.d.ts +257 -0
- package/dist/web-theme-store.js +627 -0
- package/dist/web-theme-store.js.map +1 -0
- package/dist/web-theme.d.ts +123 -0
- package/dist/web-theme.js +416 -0
- package/dist/web-theme.js.map +1 -0
- 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/web-widget.d.ts +72 -0
- package/dist/web-widget.js +245 -0
- package/dist/web-widget.js.map +1 -0
- package/dist/workflow-templates/default.md +1 -1
- package/package.json +1 -1
- package/templates/systemd.service.ejs +8 -0
package/dist/ui/panel-fleet.js
CHANGED
|
@@ -11,22 +11,33 @@ import { useLease } from "/assets/app-ctx.js";
|
|
|
11
11
|
import { PanelHeader, setTitle } from "/assets/app-shell.js";
|
|
12
12
|
import { HeaderTools } from "/assets/header-tools.js";
|
|
13
13
|
import { renavigate } from "/assets/app-nav.js";
|
|
14
|
-
import { chatPath, fleetPath, FLEET_TABS } from "/assets/app-route.js";
|
|
14
|
+
import { chatPath, fleetPath, FLEET_TABS, rememberFleetTab } from "/assets/app-route.js";
|
|
15
15
|
import { Dialog } from "/assets/ui-dialog.js";
|
|
16
16
|
import { Empty, ErrorState, Skeleton } from "/assets/ui-states.js";
|
|
17
17
|
import { Icon } from "/assets/ui-icons.js";
|
|
18
18
|
import { toast } from "/assets/ui-toast.js";
|
|
19
19
|
import { confirmDialog } from "/assets/ui-confirm.js";
|
|
20
20
|
import { confirmedWrite } from "./settings-confirm.js";
|
|
21
|
-
import {
|
|
21
|
+
import { OrgCanvas } from "./fleet-canvas.js";
|
|
22
22
|
import { labelOf } from "/assets/instance-nav.js";
|
|
23
23
|
import { CacheReport } from "./fleet-cache.js";
|
|
24
|
+
import { UsageTab } from "./fleet-usage.js";
|
|
25
|
+
import { BackendSelect, ModelSelect } from "./settings-dialogs.js";
|
|
26
|
+
|
|
27
|
+
/** #2015: one of the largest processes as text: "python3 18.1 GB (dev-a)". */
|
|
28
|
+
export function memoryHogText(p) {
|
|
29
|
+
const size = p.rssBytes >= 1024 ** 3 ? `${(p.rssBytes / 1024 ** 3).toFixed(1)} GB` : `${Math.round(p.rssBytes / 1024 ** 2)} MB`;
|
|
30
|
+
const owner = p.owner === "instance" && p.instance ? p.instance
|
|
31
|
+
: t(p.owner === "fleet" ? "fleet.hostMemory_ownerFleet" : p.owner === "tmux" ? "fleet.hostMemory_ownerTmux" : "fleet.hostMemory_ownerOther");
|
|
32
|
+
return `${p.name} ${size} (${owner})`;
|
|
33
|
+
}
|
|
24
34
|
|
|
25
35
|
register("fleet", {
|
|
26
36
|
en: {
|
|
27
37
|
hostMemory_elevated: "Host memory pressure: elevated — new agents start one at a time, at least 5 s apart",
|
|
28
38
|
hostMemory_critical: "Host memory pressure: critical — new agents wait for memory to recover",
|
|
29
|
-
|
|
39
|
+
hostMemory_top: "Largest: {0}", hostMemory_ownerFleet: "the fleet", hostMemory_ownerTmux: "tmux", hostMemory_ownerOther: "not an instance",
|
|
40
|
+
title: "Fleet", tasks: "Tasks", schedules: "Schedules", teams: "Teams", org: "Org chart", cache: "Cache", usage: "Usage", config: "Config",
|
|
30
41
|
docs: "Docs", docsNewTab: "Docs (opens in a new tab)",
|
|
31
42
|
newTask: "New task", newSchedule: "New schedule", newTeam: "New team",
|
|
32
43
|
noTasks: "No tasks yet", noTasksHint: "Create one to coordinate fleet work.", noSchedules: "No schedules yet", noSchedulesHint: "Automate recurring work with cron.",
|
|
@@ -52,12 +63,13 @@ register("fleet", {
|
|
|
52
63
|
newInstance: "New instance", directory: "Directory", directoryHint: "Optional — a workspace is created if empty", topic: "Name", topicHint: "From the directory name",
|
|
53
64
|
topicRequired: "Name is required when Directory is empty", description: "Description", descriptionHint: "What this instance does", model: "Model", modelHint: "e.g. sonnet, opus, gpt-5",
|
|
54
65
|
branch: "Branch (git worktree)", branchHint: "e.g. feature-x", tags: "Tags", tagsHint: "comma-separated, e.g. dev, review", systemPrompt: "System prompt", systemPromptHint: "Custom instructions for this instance",
|
|
55
|
-
fleetDefault: "Use the fleet default", notInstalled: "(not installed)", deprecated: "(deprecated)", instanceCreated: "Instance created",
|
|
66
|
+
fleetDefault: "Use the fleet default", notInstalled: "(not installed)", notSignedIn: "(not signed in — use /login)", tooOld: "(needs {0} or newer)", unchecked: "(not checked yet)", deprecated: "(deprecated)", instanceCreated: "Instance created",
|
|
56
67
|
},
|
|
57
68
|
"zh-TW": {
|
|
58
69
|
hostMemory_elevated: "主機記憶體壓力偏高:新的 agent 一次啟動一個,至少間隔 5 秒",
|
|
59
70
|
hostMemory_critical: "主機記憶體壓力嚴重:新的 agent 會等記憶體恢復再啟動",
|
|
60
|
-
|
|
71
|
+
hostMemory_top: "最大:{0}", hostMemory_ownerFleet: "fleet 本身", hostMemory_ownerTmux: "tmux", hostMemory_ownerOther: "不屬於任何 instance",
|
|
72
|
+
title: "Fleet", tasks: "Tasks", schedules: "排程", teams: "Teams", org: "組織圖", cache: "快取", usage: "用量", config: "設定",
|
|
61
73
|
docs: "文件", docsNewTab: "文件(在新分頁開啟)",
|
|
62
74
|
newTask: "新增 task", newSchedule: "新增排程", newTeam: "新增 team",
|
|
63
75
|
noTasks: "還沒有 task", noTasksHint: "建立一個來協調 fleet 的工作。", noSchedules: "還沒有排程", noSchedulesHint: "用 cron 自動執行例行工作。",
|
|
@@ -82,7 +94,7 @@ register("fleet", {
|
|
|
82
94
|
newInstance: "新增 instance", directory: "目錄", directoryHint: "可留空——留空會自動建立工作區", topic: "名稱", topicHint: "預設取自目錄名稱",
|
|
83
95
|
topicRequired: "目錄留空時必須填寫名稱", description: "說明", descriptionHint: "這個 instance 做什麼", model: "模型", modelHint: "例如 sonnet、opus、gpt-5",
|
|
84
96
|
branch: "分支(git worktree)", branchHint: "例如 feature-x", tags: "標籤", tagsHint: "以逗號分隔,例如 dev, review", systemPrompt: "System prompt", systemPromptHint: "這個 instance 的自訂指示",
|
|
85
|
-
fleetDefault: "使用 fleet 預設", notInstalled: "(未安裝)", deprecated: "(已淘汰)", instanceCreated: "Instance 已建立",
|
|
97
|
+
fleetDefault: "使用 fleet 預設", notInstalled: "(未安裝)", notSignedIn: "(未登入,請用 /login)", tooOld: "(需要 {0} 以上版本)", unchecked: "(尚未檢查)", deprecated: "(已淘汰)", instanceCreated: "Instance 已建立",
|
|
86
98
|
},
|
|
87
99
|
});
|
|
88
100
|
|
|
@@ -91,7 +103,7 @@ const DOCS_SITE = "https://songsid.github.io/AgEnD";
|
|
|
91
103
|
export function docsUrl(language = lang()) {
|
|
92
104
|
return `${DOCS_SITE}${language === "zh-TW" ? "/zh-tw" : ""}/docs/web-guide/`;
|
|
93
105
|
}
|
|
94
|
-
const ICONS = { tasks: "tasks", schedules: "clock", teams: "team", org: "org", cache: "chart", config: "sliders" };
|
|
106
|
+
const ICONS = { tasks: "tasks", schedules: "clock", teams: "team", org: "org", cache: "chart", usage: "chart", config: "sliders" };
|
|
95
107
|
const BACKENDS = ["claude-code", "codex", "opencode", "kiro-cli", "antigravity", "grok", "muse"];
|
|
96
108
|
|
|
97
109
|
async function api(method, path, body, lease) {
|
|
@@ -130,15 +142,18 @@ export function FleetPanel({ route, navKey }) {
|
|
|
130
142
|
const lease = useLease(navKey);
|
|
131
143
|
const tab = route.tab;
|
|
132
144
|
useEffect(() => { setTitle(`${t("fleet.title")} · ${t(`fleet.${tab}`)}`); }, [tab, navKey]);
|
|
133
|
-
|
|
145
|
+
useEffect(() => { rememberFleetTab(tab); }, [tab]); // #2183: the sidebar's and the phone's Fleet reopen it
|
|
146
|
+
const Body = { tasks: Tasks, schedules: Schedules, teams: Teams, org: Org, cache: Cache, usage: UsageTab, config: Config }[tab] || Tasks;
|
|
134
147
|
// #1685: host memory pressure slowing or holding new agents — shown here, where macOS's routine "elevated" is not a chat notice.
|
|
135
|
-
const { hostMemory } = useStore(appStore);
|
|
136
|
-
|
|
137
|
-
|
|
148
|
+
const { hostMemory, hostMemoryTop } = useStore(appStore);
|
|
149
|
+
// #2015: and which processes hold the most, and whose — text only (never chat, #1712).
|
|
150
|
+
const top = hostMemory && hostMemoryTop?.length ? t("fleet.hostMemory_top", hostMemoryTop.map(memoryHogText).join(" · ")) : "";
|
|
151
|
+
const sub = hostMemory ? html`<span class=${`status host-mem ${hostMemory}`} role="status"><span class=${`dot ${hostMemory === "critical" ? "bad" : "warn"}`} aria-hidden="true"></span>${t(`fleet.hostMemory_${hostMemory}`)}${top ? html`<span class="host-mem-top">${top}</span>` : null}</span>` : null;
|
|
152
|
+
return html`<div data-effect-panel="fleet" class="panel p-fleet">
|
|
138
153
|
<${PanelHeader} title=${t("fleet.title")} sub=${sub}><${DocsLink} /><${HeaderTools} navKey=${navKey} /></${PanelHeader}>
|
|
139
|
-
<nav class="seg" aria-label=${t("fleet.title")}>${FLEET_TABS.map(k => html`<a key=${k} href=${fleetPath(k)} class=${`seg-item${k === tab ? " active" : ""}`}
|
|
154
|
+
<nav data-trust="panel-navigation" class="seg" aria-label=${t("fleet.title")}>${FLEET_TABS.map(k => html`<a key=${k} href=${fleetPath(k)} class=${`seg-item${k === tab ? " active" : ""}`}
|
|
140
155
|
aria-current=${k === tab ? "page" : undefined}><${Icon} name=${ICONS[k]} size=${16} /><span>${t(`fleet.${k}`)}</span></a>`)}</nav>
|
|
141
|
-
<div class="panel-body"><div class=${`col${tab === "org" || tab === "cache" ? " col-wide" : ""}`}><${Body} lease=${lease} /></div></div>
|
|
156
|
+
<div data-trust="panel-content" class="panel-body"><div class=${`col${tab === "org" || tab === "cache" || tab === "usage" ? " col-wide" : ""}`}><${Body} lease=${lease} /></div></div>
|
|
142
157
|
</div>`;
|
|
143
158
|
}
|
|
144
159
|
|
|
@@ -255,11 +270,11 @@ function Teams({ lease }) {
|
|
|
255
270
|
${editing ? html`<${CreateTeam} team=${editing} onClose=${() => setEditing(null)} onDone=${() => setVersion(v => v + 1)} />` : null}`;
|
|
256
271
|
}
|
|
257
272
|
|
|
258
|
-
/** #1389: the org chart — its structure read once per opening, its live state from the app store (fleet-
|
|
273
|
+
/** #1389: the org chart — its structure read once per opening, its live state from the app store. #1918: a canvas, or the list (fleet-canvas.js). */
|
|
259
274
|
function Org({ lease }) {
|
|
260
275
|
const state = useLoad(lease, "/ui/org", 0);
|
|
261
276
|
const app = useStore(appStore);
|
|
262
|
-
return html`<${Loaded} state=${state}>${(org) => html`<${
|
|
277
|
+
return html`<${Loaded} state=${state}>${(org) => html`<${OrgCanvas} org=${org} app=${app} lease=${lease} />`}</${Loaded}>`;
|
|
263
278
|
}
|
|
264
279
|
|
|
265
280
|
/** #1468: the prompt-cache analysis — one read per opening and per window chosen; Refresh reads again (fleet-cache.js). */
|
|
@@ -322,8 +337,7 @@ function Config({ lease }) {
|
|
|
322
337
|
<div class="field"><label for="cfg-users">${t("fleet.allowedUsers")}</label><${Secret} id="cfg-users" value=${form.users} onInput=${set("users")} label=${t("fleet.allowedUsers")} />
|
|
323
338
|
<p class="note">${t("fleet.allowedUsersNote")}</p></div></section>
|
|
324
339
|
<section class="card"><h3>${t("fleet.defaults")}</h3>
|
|
325
|
-
<
|
|
326
|
-
${[...(BACKENDS.includes(form.backend) ? [] : [form.backend]), ...BACKENDS].map(b => html`<option key=${b} value=${b}>${b}</option>`)}</select></label></section>
|
|
340
|
+
<div class="field"><label for="cfg-be">${t("fleet.backend")}</label><${BackendSelect} id="cfg-be" value=${form.backend} onChange=${(v) => setForm({ ...form, backend: v })} /></div></section>
|
|
327
341
|
<section class="card"><h3>${t("fleet.roots")}</h3>
|
|
328
342
|
${form.roots.map((r, i) => html`<div key=${i} class="field-row"><input value=${r} placeholder="/path/to/projects" aria-label=${t("fleet.roots")}
|
|
329
343
|
onInput=${(e) => { const roots = [...form.roots]; roots[i] = e.target.value; setForm({ ...form, roots }); }} />
|
|
@@ -510,6 +524,8 @@ function CreateTeam({ onClose, onDone, team = null }) {
|
|
|
510
524
|
export function CreateInstanceDialog({ onClose }) {
|
|
511
525
|
const lease = useLease("create-instance");
|
|
512
526
|
const [backends, setBackends] = useState(null);
|
|
527
|
+
// The backend "fleet default" means (#2098 review P3-3): its models are the ones the model list offers then.
|
|
528
|
+
const [defaultBackend, setDefaultBackend] = useState("claude-code");
|
|
513
529
|
const [f, setF] = useState({ dir: "", topic: "", desc: "", backend: "", model: "", branch: "", tags: "", prompt: "" });
|
|
514
530
|
useEffect(() => {
|
|
515
531
|
(async () => {
|
|
@@ -518,6 +534,7 @@ export function CreateInstanceDialog({ onClose }) {
|
|
|
518
534
|
if (!lease.current()) return;
|
|
519
535
|
const list = bd.backends || [];
|
|
520
536
|
const first = list.find(b => b.installed && !b.deprecated) || list.find(b => b.installed);
|
|
537
|
+
if (typeof bd.defaultBackend === "string" && bd.defaultBackend) setDefaultBackend(bd.defaultBackend);
|
|
521
538
|
setBackends(list);
|
|
522
539
|
setF(x => ({ ...x, backend: first ? first.name : "" }));
|
|
523
540
|
} catch {
|
|
@@ -547,14 +564,23 @@ export function CreateInstanceDialog({ onClose }) {
|
|
|
547
564
|
${field(`${t("fleet.topic")}${f.dir.trim() ? "" : " *"}`, html`<input value=${f.topic} onInput=${set("topic")} placeholder=${t("fleet.topicHint")} />`)}
|
|
548
565
|
${field(t("fleet.description"), html`<input value=${f.desc} onInput=${set("desc")} placeholder=${t("fleet.descriptionHint")} />`)}
|
|
549
566
|
${field(t("fleet.backend"), backends ? html`<select value=${f.backend} onChange=${set("backend")}><option value="">${t("fleet.fleetDefault")}</option>
|
|
550
|
-
${backends.map(b => html`<option key=${b.name} value=${b.name} disabled=${
|
|
551
|
-
${field(t("fleet.model"), html
|
|
567
|
+
${backends.map(b => html`<option key=${b.name} value=${b.name} disabled=${backendBlocked(b)}>${b.name}${b.deprecated ? ` ${t("fleet.deprecated")}` : ""}${backendNote(b)}</option>`)}</select>` : html`<${Skeleton} lines=${1} />`)}
|
|
568
|
+
${field(t("fleet.model"), html`<${ModelSelect} value=${f.model} onChange=${(v) => setF(x => ({ ...x, model: v }))} backend=${f.backend || defaultBackend} inherit=${t("fleet.fleetDefault")} />`)}
|
|
552
569
|
${field(t("fleet.branch"), html`<input value=${f.branch} onInput=${set("branch")} placeholder=${t("fleet.branchHint")} />`)}
|
|
553
570
|
${field(t("fleet.tags"), html`<input value=${f.tags} onInput=${set("tags")} placeholder=${t("fleet.tagsHint")} />`)}
|
|
554
571
|
${field(t("fleet.systemPrompt"), html`<textarea rows="3" value=${f.prompt} onInput=${set("prompt")} placeholder=${t("fleet.systemPromptHint")}></textarea>`)}
|
|
555
572
|
</${FormDialog}>`;
|
|
556
573
|
}
|
|
557
574
|
|
|
575
|
+
// #2072: a backend this host cannot run is shown, disabled, with why; one not checked yet stays selectable.
|
|
576
|
+
const backendState = (b) => b.state ?? (b.installed ? "usable" : b.unknown ? "unknown" : "not_installed");
|
|
577
|
+
function backendBlocked(b) { return ["not_installed", "not_signed_in", "too_old"].includes(backendState(b)); }
|
|
578
|
+
function backendNote(b) {
|
|
579
|
+
const s = backendState(b);
|
|
580
|
+
return s === "not_installed" ? ` ${t("fleet.notInstalled")}` : s === "not_signed_in" ? ` ${t("fleet.notSignedIn")}`
|
|
581
|
+
: s === "too_old" ? ` ${t("fleet.tooOld", b.minVersion ?? "?")}` : s === "unknown" ? ` ${t("fleet.unchecked")}` : "";
|
|
582
|
+
}
|
|
583
|
+
|
|
558
584
|
// ── Cron in words (#1724: in the page's language) ──
|
|
559
585
|
/**
|
|
560
586
|
* A cron expression as a person says it — "Weekdays 18:00", 「每週一到五 18:00」, "Every 15 minutes" — or the expression
|
package/dist/ui/panel-log.js
CHANGED
|
@@ -200,10 +200,10 @@ export function LogPanel({ route, navKey }) {
|
|
|
200
200
|
const name = route.instance;
|
|
201
201
|
const inst = app.instances.find((i) => i.name === name) || null;
|
|
202
202
|
useEffect(() => { setTitle(`${name} · ${t("app.log")}`); }, [name, navKey]);
|
|
203
|
-
if (!app.ready) return html`<div class="panel p-log"><${PanelHeader} title=${name} /><div class="panel-body"><${Skeleton} lines=${6} /></div></div>`;
|
|
203
|
+
if (!app.ready) return html`<div data-effect-panel="log" class="panel p-log"><${PanelHeader} title=${name} /><div data-trust="panel-content" class="panel-body"><${Skeleton} lines=${6} /></div></div>`;
|
|
204
204
|
if (!inst) {
|
|
205
|
-
return html`<div class="panel p-log"><${PanelHeader} title=${name} />
|
|
206
|
-
<div class="panel-body center"><${Empty} icon="alert" title=${t("chat.notFound", name)} hint=${t("chat.notFoundHint")}
|
|
205
|
+
return html`<div data-effect-panel="log" class="panel p-log"><${PanelHeader} title=${name} />
|
|
206
|
+
<div data-trust="panel-content" class="panel-body center"><${Empty} icon="alert" title=${t("chat.notFound", name)} hint=${t("chat.notFoundHint")}
|
|
207
207
|
action=${html`<button type="button" class="btn only-narrow" onClick=${openDrawer}>${t("chat.backToList")}</button>`} /></div></div>`;
|
|
208
208
|
}
|
|
209
209
|
return html`<${LogView} key=${name} name=${name} inst=${inst} navKey=${navKey} exec=${app.exec[name]}
|
|
@@ -372,13 +372,13 @@ function LogView({ name, inst, navKey, exec, awaiting }) {
|
|
|
372
372
|
${items.length ? html`<ol class="log-list" role="log" aria-label=${t("app.log")}>${items.map((x, i) => html`<${Row} key=${`${x.kind}:${x.id}`} x=${x} prev=${items[i - 1]} />`)}</ol>`
|
|
373
373
|
: html`<p class="note log-empty">${tl("empty")}</p>`}`;
|
|
374
374
|
}
|
|
375
|
-
const tools = state.phase === "on" ? html`<div class="log-bar" role="group" aria-label=${tl("filter")}>
|
|
375
|
+
const tools = state.phase === "on" ? html`<div data-trust="panel-controls" class="log-bar" role="group" aria-label=${tl("filter")}>
|
|
376
376
|
${["all", "tools", "errors"].map((k) => html`<button key=${k} type="button" class=${`chip-btn${filter === k ? " on" : ""}`} aria-pressed=${filter === k ? "true" : "false"} onClick=${() => setFilter(k)}>${tl(k)}</button>`)}
|
|
377
377
|
<span class="grow"></span><span class="log-live" title=${tl("live")}><span class="dot running" aria-hidden="true"></span>${tl("live")}</span></div>` : null;
|
|
378
|
-
return html`<div class="panel p-log">
|
|
378
|
+
return html`<div data-effect-panel="log" class="panel p-log">
|
|
379
379
|
<${PanelHeader} title=${name} sub=${sub} nav=${html`<${InstanceSwitch} name=${name} current="log" />`}><${HeaderTools} navKey=${navKey} /><${HeaderSlot} /></${PanelHeader}>
|
|
380
380
|
${tools}
|
|
381
|
-
<div class="panel-body log-body" ref=${scroller} onScroll=${onScroll}><div class="col log-col">${content}</div></div>
|
|
381
|
+
<div data-trust="panel-content" class="panel-body log-body" ref=${scroller} onScroll=${onScroll}><div class="col log-col">${content}</div></div>
|
|
382
382
|
</div>`;
|
|
383
383
|
}
|
|
384
384
|
|
package/dist/ui/panel-needs.js
CHANGED
|
@@ -123,9 +123,9 @@ export function NeedsPanel({ navKey }) {
|
|
|
123
123
|
useEffect(() => { if (owner) return owner.subscribe(() => tick((n) => n + 1)); return undefined; }, [owner, lease]);
|
|
124
124
|
const groups = groupNeeds(items);
|
|
125
125
|
const nowMs = Date.now();
|
|
126
|
-
return html`<div class="panel p-needs">
|
|
126
|
+
return html`<div data-effect-panel="needs" class="panel p-needs">
|
|
127
127
|
<${PanelHeader} title=${tn("title")} sub=${items.length ? t("app.needsCount", items.length) : null} />
|
|
128
|
-
<div class="panel-body"><div class="col">
|
|
128
|
+
<div data-trust="panel-content" class="panel-body"><div class="col">
|
|
129
129
|
${!items.length ? html`<${Empty} icon="check" title=${tn("empty")} hint=${tn(chatApp ? "emptyHint" : "emptyHintWeb")} />`
|
|
130
130
|
: groups.map((g) => html`<section key=${g.instance} class="n-group" aria-label=${g.instance}>
|
|
131
131
|
<h2 class="n-group-head"><a href=${chatPath(g.instance)} title=${g.instance}>${nameFor(g.instance)}</a></h2>
|
|
@@ -175,7 +175,7 @@ function NeedsItem({ item, nowMs, owner }) {
|
|
|
175
175
|
setClaim("acks", item.id, res && res.ok ? "done" : null);
|
|
176
176
|
toast((body && (body.message || body.error)) || t("app.failed"), !!(res && res.ok));
|
|
177
177
|
};
|
|
178
|
-
return html`<article class=${`n-item${BAD.has(item.reason) ? " bad" : ""}`}>
|
|
178
|
+
return html`<article data-trust="permission" class=${`n-item${BAD.has(item.reason) ? " bad" : ""}`}>
|
|
179
179
|
<span class="n-icon"><${Icon} name=${ICON[item.type] || "alert"} size=${18} /></span>
|
|
180
180
|
<div class="n-body">
|
|
181
181
|
<div class="n-title"><strong>${reasonText(item)}</strong><span class="n-age">${age(item.since, nowMs)}</span></div>
|
|
@@ -20,6 +20,7 @@ import { Empty, ErrorState, Skeleton } from "/assets/ui-states.js";
|
|
|
20
20
|
import { Icon } from "/assets/ui-icons.js";
|
|
21
21
|
import { Menu } from "/assets/ui-menu.js";
|
|
22
22
|
import { toast } from "/assets/ui-toast.js";
|
|
23
|
+
import { GroupMark, groupLabel, groupOf as navGroupOf, modelText } from "/assets/instance-nav.js";
|
|
23
24
|
import "./settings-strings.js";
|
|
24
25
|
import { api, attach, confirmedWrite, newKey } from "./settings-confirm.js";
|
|
25
26
|
import { dismissOperation, operationActive, restartFleet, startOperation, takeLeftover } from "./settings-apply.js";
|
|
@@ -30,7 +31,7 @@ import {
|
|
|
30
31
|
visibilityDefault, worstImpact,
|
|
31
32
|
} from "./settings-model.js";
|
|
32
33
|
import {
|
|
33
|
-
AgentDialog, BackendSelect, BotDialog, ChipList, ClassicDialog, Drawer, Feedback, Impact, Label, NewBotDialog, Override,
|
|
34
|
+
AgentDialog, BackendSelect, BotDialog, ChipList, ClassicDialog, Drawer, Feedback, Impact, Label, ModelSelect, NewBotDialog, Override,
|
|
34
35
|
Select, ask, impactText,
|
|
35
36
|
} from "./settings-dialogs.js";
|
|
36
37
|
import { SetupWizard } from "./settings-wizard.js";
|
|
@@ -41,9 +42,16 @@ import { takeAgentRequest } from "./settings-request.js";
|
|
|
41
42
|
import { setPreviewOptIn } from "./panel-chat.js";
|
|
42
43
|
import { startTour } from "./chat-tour.js";
|
|
43
44
|
import "./chat-strings.js";
|
|
45
|
+
import { AppearanceSection } from "./settings-appearance.js";
|
|
46
|
+
import { GuestsCard } from "./settings-guests.js";
|
|
47
|
+
import { WebAuthorityCard } from "./settings-web-authority.js";
|
|
44
48
|
|
|
45
49
|
const tn = (k, ...v) => t(`settings.${k}`, ...v);
|
|
46
|
-
|
|
50
|
+
/** What a refused change says to a person: the server's code in words (the code itself only for one not listed). */
|
|
51
|
+
const APPLY_ERRORS = new Set(["unsupported_sensitive_effect", "confirmation_diff_too_large", "session_required", "admin_required", "settings_changed",
|
|
52
|
+
"request_no_longer_current", "too_many_pending_changes", "fleet_unavailable", "invalid_settings_effect", "settings_confirmation_unavailable", "failed"]);
|
|
53
|
+
export const applyErrorText = (code) => (APPLY_ERRORS.has(code) ? tn(`applyError_${code}`) : tn("applyErrorOther", String(code)));
|
|
54
|
+
const ICONS = { device: "user", appearance: "palette", agents: "bot", bots: "plug", classic: "room", general: "sliders", web: "globe", advanced: "code" };
|
|
47
55
|
const RELEASES = "https://github.com/songsid/AgEnD/releases";
|
|
48
56
|
|
|
49
57
|
/** GET under the panel's lease → { ok, status, body }. */
|
|
@@ -86,7 +94,7 @@ async function loadLive(lease) {
|
|
|
86
94
|
if (!lease.current()) return null;
|
|
87
95
|
const live = {}, classicLive = {};
|
|
88
96
|
if (f.ok && f.body && Array.isArray(f.body.instances)) for (const i of f.body.instances) {
|
|
89
|
-
live[i.name] = { status: i.status, state: i.state, backend: i.backend, model: i.model, model_display: i.model_display, effort: i.effort, effort_supported: i.effort_supported };
|
|
97
|
+
live[i.name] = { status: i.status, state: i.state, backend: i.backend, model: i.model, model_display: modelText(i, i.model_display), effort: i.effort, effort_supported: i.effort_supported };
|
|
90
98
|
if (i.classic) classicLive[i.name] = { status: i.status, state: i.state };
|
|
91
99
|
}
|
|
92
100
|
// /api/fleet carries live state for ClassicBot rooms; the profiles are the fallback for one not listed there yet.
|
|
@@ -224,6 +232,8 @@ export function SettingsPanel({ route, navKey }) {
|
|
|
224
232
|
}, [!!ctx, navKey]);
|
|
225
233
|
// #1604: This device needs no configuration: shown at once, whatever the configuration read does.
|
|
226
234
|
const sectionBody = section === "device" ? html`<${DeviceSection} />`
|
|
235
|
+
// #1629 r4 §3: Appearance is the person's own (no configuration read): shown at once, like Preferences.
|
|
236
|
+
: section === "appearance" ? html`<${AppearanceSection} />`
|
|
227
237
|
: !data ? html`<${Skeleton} lines=${6} />`
|
|
228
238
|
: data.error ? html`<${ErrorState} message=${tn("configLoadFailed")} onRetry=${reload} />`
|
|
229
239
|
: section === "agents" ? html`<${Agents} ctx=${ctx} search=${search} openDialog=${(d) => setDialog({ ...d, key: navKey })} />`
|
|
@@ -236,14 +246,14 @@ export function SettingsPanel({ route, navKey }) {
|
|
|
236
246
|
const open = dialog && dialog.key === navKey ? dialog : null;
|
|
237
247
|
const close = () => setDialog(null);
|
|
238
248
|
const searchable = section === "agents" || section === "bots" || section === "classic";
|
|
239
|
-
return html`<div class="panel p-settings">
|
|
249
|
+
return html`<div data-effect-panel="settings" class="panel p-settings">
|
|
240
250
|
<${PanelHeader} title=${tn("title")} sub=${data && data.version ? html`<a class="pill ver" href=${data.version.includes("-") ? `${RELEASES}/latest` : `${RELEASES}/tag/v${data.version}`} target="_blank" rel="noopener">v${data.version}</a>` : null}>
|
|
241
251
|
<button type="button" class="btn btn-ghost btn-sm" disabled=${!ctx} onClick=${() => setDialog({ kind: "wizard", key: navKey })}><${Icon} name="wand" size=${16} /><span class="hide-narrow">${tn("wizardButton")}</span></button>
|
|
242
252
|
<button type="button" class="icon-btn" aria-label=${tn("helpButton")} title=${tn("helpButton")} onClick=${() => setDialog({ kind: "help", key: navKey })}><${Icon} name="info" /></button>
|
|
243
253
|
</${PanelHeader}>
|
|
244
|
-
<nav class="seg" aria-label=${tn("title")}>${SETTINGS_SECTIONS.map((k) => html`<a key=${k} href=${settingsPath(k)} class=${`seg-item${k === section ? " active" : ""}`}
|
|
254
|
+
<nav data-trust="panel-navigation" class="seg" aria-label=${tn("title")}>${SETTINGS_SECTIONS.map((k) => html`<a key=${k} href=${settingsPath(k)} class=${`seg-item${k === section ? " active" : ""}`}
|
|
245
255
|
aria-current=${k === section ? "page" : undefined}><${Icon} name=${ICONS[k]} size=${16} /><span>${tn(`sec_${k}`)}</span></a>`)}</nav>
|
|
246
|
-
<div class="panel-body"><div class="col">
|
|
256
|
+
<div data-trust="panel-content" class="panel-body"><div class="col">
|
|
247
257
|
${searchable ? html`<div class="s-toolbar"><label class="s-search"><${Icon} name="search" size=${14} /><span class="sr-only">${tn("searchAll")}</span>
|
|
248
258
|
<input type="search" value=${search} placeholder=${tn("searchAll")} onInput=${(e) => setSearch(e.target.value)} /></label></div>` : null}
|
|
249
259
|
${op ? html`<${OperationCard} op=${op} schema=${data && data.schema} />` : null}
|
|
@@ -454,7 +464,9 @@ function Agents({ ctx, search, openDialog }) {
|
|
|
454
464
|
const [collapsed, setCollapsed] = useState(() => new Set());
|
|
455
465
|
const [busy, setBusy] = useState(() => new Map()); // name → the action under way
|
|
456
466
|
const chs = channelsOf(ctx.fleet);
|
|
457
|
-
|
|
467
|
+
// #2172: the sidebar's grouping — an agent in a team under its team, else under its first tag.
|
|
468
|
+
const teamsOf = (name) => Object.keys(ctx.fleet.teams || {}).filter((t) => Array.isArray(ctx.fleet.teams[t]?.members) && ctx.fleet.teams[t].members.includes(name));
|
|
469
|
+
const groups = groupAgents(insts, ctx.live, search, (name) => navGroupOf({ tags: insts[name]?.tags, teams: teamsOf(name) }), groupLabel);
|
|
458
470
|
// One action per agent at a time: the whole row is off (Settings and ⋯ too), and the pressed button says it is working.
|
|
459
471
|
const run = async (name, action, work) => {
|
|
460
472
|
if (busy.has(name)) return;
|
|
@@ -470,7 +482,7 @@ function Agents({ ctx, search, openDialog }) {
|
|
|
470
482
|
return html`<section key=${group} class="s-group">
|
|
471
483
|
<button type="button" class="s-group-head" aria-expanded=${folded ? "false" : "true"}
|
|
472
484
|
onClick=${() => setCollapsed((c) => { const n = new Set(c); n.has(group) ? n.delete(group) : n.add(group); return n; })}>
|
|
473
|
-
<${Icon} name="chevron" size=${14} cls=${folded ? "caret folded" : "caret"} /><span class="grow">${group}</span><span class="count">${names.length}</span></button>
|
|
485
|
+
<${Icon} name="chevron" size=${14} cls=${folded ? "caret folded" : "caret"} /><${GroupMark} group=${group} /><span class="grow">${groupLabel(group)}</span><span class="count">${names.length}</span></button>
|
|
474
486
|
${folded ? null : names.map((name) => {
|
|
475
487
|
const inst = insts[name];
|
|
476
488
|
const st = (ctx.live[name] && ctx.live[name].status) || "stopped";
|
|
@@ -499,7 +511,30 @@ function Agents({ ctx, search, openDialog }) {
|
|
|
499
511
|
})}</div>`;
|
|
500
512
|
}
|
|
501
513
|
|
|
514
|
+
function ConnectionRetry({ id, ctx }) {
|
|
515
|
+
const lease = useLease(`connection-retry:${id}`);
|
|
516
|
+
const claimed = useRef(false);
|
|
517
|
+
const [busy, setBusy] = useState(false);
|
|
518
|
+
const retry = async () => {
|
|
519
|
+
if (claimed.current) return;
|
|
520
|
+
claimed.current = true; setBusy(true);
|
|
521
|
+
try {
|
|
522
|
+
const response = await lease.fetch(`/api/settings/connections/${encodeURIComponent(id)}/retry`, { method: "POST" });
|
|
523
|
+
if (!lease.current()) return;
|
|
524
|
+
toast(response.ok ? tn("connRetryQueued") : tn("connRetryFailed"));
|
|
525
|
+
await ctx.reload();
|
|
526
|
+
} catch {
|
|
527
|
+
if (lease.current()) toast(tn("connRetryFailed"));
|
|
528
|
+
} finally {
|
|
529
|
+
claimed.current = false;
|
|
530
|
+
if (lease.current()) setBusy(false);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
return html`<button type="button" class="btn btn-sm" disabled=${busy} onClick=${retry}>${tn("connRetryNow")}</button>`;
|
|
534
|
+
}
|
|
535
|
+
|
|
502
536
|
function Bots({ ctx, search, openDialog }) {
|
|
537
|
+
const overPublicLink = globalThis.document?.body?.dataset?.publicLink === "1";
|
|
503
538
|
const all = channelsOf(ctx.fleet);
|
|
504
539
|
const needle = search.trim().toLowerCase();
|
|
505
540
|
const rows = all.map((ch, i) => ({ ch, i })).filter(({ ch }) => !needle || [ch.id, ch.type, ch.group_id, ch.bot_token_env].some((v) => String(v ?? "").toLowerCase().includes(needle)));
|
|
@@ -528,6 +563,7 @@ function Bots({ ctx, search, openDialog }) {
|
|
|
528
563
|
<span class="s-actions">
|
|
529
564
|
<span class=${`tag${token ? "" : " warn"}`}>${token ? tn("tokenConfigured") : tn("tokenMissing")}</span>
|
|
530
565
|
<span class=${`s-state ${state.cls}`} title=${stateText}>${stateText}</span>
|
|
566
|
+
${!overPublicLink && ctx.fleetUp && meta.status !== "connected" ? html`<${ConnectionRetry} id=${channelId(ch, i)} ctx=${ctx} />` : null}
|
|
531
567
|
<button type="button" class="btn btn-sm" onClick=${() => openDialog({ kind: "bot", id: channelId(ch, i) })}>${tn("settingsButton")}</button></span>
|
|
532
568
|
</div>`;
|
|
533
569
|
})}</div>`}
|
|
@@ -703,7 +739,8 @@ function General({ ctx }) {
|
|
|
703
739
|
<div class="field">${L(tn("language"), "defaults.locale", "g-locale")}<${Select} id="g-locale" value=${f.locale} onChange=${set("locale")}
|
|
704
740
|
options=${localeOptions(f.locale).map((o) => (o.auto ? { value: "", label: tn("localeAuto") } : o))} /></div>
|
|
705
741
|
<div class="field">${L(tn("defaultBackend"), "defaults.backend", "g-be")}<${BackendSelect} id="g-be" value=${f.backend} onChange=${set("backend")} /></div>
|
|
706
|
-
<div class="field">${L(tn("defaultModel"), "defaults.model", "g-model")}
|
|
742
|
+
<div class="field">${L(tn("defaultModel"), "defaults.model", "g-model")}<${ModelSelect} id="g-model" value=${f.model} onChange=${set("model")}
|
|
743
|
+
backend=${f.backend || "claude-code"} inherit=${tn("modelCliDefault")} /></div>
|
|
707
744
|
<div class="field">${L(`${tn("autoPause")} (${tn("minutes")})`, "defaults.auto_pause_after", "g-auto")}<input id="g-auto" type="number" min="0" step="1" class=${errors.auto ? "invalid" : ""} value=${f.auto} onInput=${(e) => set("auto")(e.target.value)} /><${Feedback} error=${errors.auto} /></div>
|
|
708
745
|
<div class="field">${L(tn("toolProgress"), "defaults.tool_progress", "g-tp")}<${Select} id="g-tp" value=${f.tool_progress} onChange=${set("tool_progress")} options=${TOOL_PROGRESS} /></div>
|
|
709
746
|
<div class="field">${L(tn("crossInstanceVisibility"), "defaults.cross_instance_visibility", "g-vis")}<${Select} id="g-vis" value=${f.visibility} onChange=${set("visibility")} options=${VISIBILITY_MODES} />
|
|
@@ -766,17 +803,20 @@ export const WEB_READ_ONLY = [
|
|
|
766
803
|
function WebSection({ ctx, staged }) {
|
|
767
804
|
const { schema } = ctx;
|
|
768
805
|
const web = ctx.fleet.web || {}, local = (web.session && web.session.local) || {}, term = ctx.fleet.web_terminal || {};
|
|
806
|
+
// Over the public link the fields read only; the Guests and Web authority cards are not offered (the server never
|
|
807
|
+
// serves their reads there).
|
|
769
808
|
const overPublicLink = globalThis.document?.body?.dataset?.publicLink === "1";
|
|
770
809
|
const original = useMemo(() => ({
|
|
771
810
|
echo: web.echo_to_channel ?? true,
|
|
772
811
|
log: web.log_tab === true, // #1218: off by default
|
|
812
|
+
usagePub: web.usage_report_on_public_link === true, // #2122: off by default
|
|
773
813
|
pub: { allow_public: (web.public_link && web.public_link.allow_public) ?? true, ttl_minutes: (web.public_link && web.public_link.ttl_minutes) ?? 120, protocol: (web.public_link && web.public_link.protocol) ?? "http2" },
|
|
774
814
|
session: { absolute_hours: local.absolute_hours ?? null, idle_hours: local.idle_hours ?? null },
|
|
775
815
|
terminal: { enabled: term.enabled ?? null, ttl_minutes: term.ttl_minutes ?? null },
|
|
776
816
|
}), []);
|
|
777
817
|
const text = (v) => (v === null || v === undefined ? "" : String(v));
|
|
778
818
|
const [f, setF] = useState(() => ({
|
|
779
|
-
echo: original.echo, log: original.log, pub: original.pub.allow_public, ttl: String(original.pub.ttl_minutes), protocol: original.pub.protocol,
|
|
819
|
+
echo: original.echo, log: original.log, usagePub: original.usagePub, pub: original.pub.allow_public, ttl: String(original.pub.ttl_minutes), protocol: original.pub.protocol,
|
|
780
820
|
abs: text(original.session.absolute_hours), idle: text(original.session.idle_hours),
|
|
781
821
|
termOn: original.terminal.enabled !== false, termTtl: text(original.terminal.ttl_minutes),
|
|
782
822
|
}));
|
|
@@ -805,6 +845,7 @@ function WebSection({ ctx, staged }) {
|
|
|
805
845
|
const body = {
|
|
806
846
|
...(f.echo !== original.echo ? { echo_to_channel: f.echo } : {}),
|
|
807
847
|
...(f.log !== original.log ? { log_tab: f.log } : {}),
|
|
848
|
+
...(f.usagePub !== original.usagePub ? { usage_report_on_public_link: f.usagePub } : {}),
|
|
808
849
|
...(Object.keys(publicPatch).length ? { public_link: publicPatch } : {}),
|
|
809
850
|
...(Object.keys(sessionPatch).length ? { session: { local: sessionPatch } } : {}),
|
|
810
851
|
...(Object.keys(terminalPatch).length ? { web_terminal: terminalPatch } : {}),
|
|
@@ -812,6 +853,7 @@ function WebSection({ ctx, staged }) {
|
|
|
812
853
|
const fields = [
|
|
813
854
|
...(body.echo_to_channel !== undefined ? ["web.echo_to_channel"] : []),
|
|
814
855
|
...(body.log_tab !== undefined ? ["web.log_tab"] : []),
|
|
856
|
+
...(body.usage_report_on_public_link !== undefined ? ["web.usage_report_on_public_link"] : []),
|
|
815
857
|
...Object.keys(publicPatch).map((k) => `web.public_link.${k}`),
|
|
816
858
|
...Object.keys(sessionPatch).map((k) => `web.session.local.${k}`),
|
|
817
859
|
...Object.keys(terminalPatch).map((k) => `web_terminal.${k}`),
|
|
@@ -853,6 +895,8 @@ function WebSection({ ctx, staged }) {
|
|
|
853
895
|
<p class="note">${tn("webEchoHint")}</p>
|
|
854
896
|
<label class="check"><input id="webLogTab" type="checkbox" checked=${f.log} onChange=${(e) => set("log")(e.target.checked)} /><span>${tn("webLogTab")}</span><${Impact} schema=${schema} field="web.log_tab" /></label>
|
|
855
897
|
<p class="note">${tn("webLogTabHint")}</p>
|
|
898
|
+
<label class="check"><input id="webUsagePublic" type="checkbox" checked=${f.usagePub} onChange=${(e) => set("usagePub")(e.target.checked)} /><span>${tn("webUsagePublic")}</span><${Impact} schema=${schema} field="web.usage_report_on_public_link" /></label>
|
|
899
|
+
<p class="note">${tn("webUsagePublicHint")}</p>
|
|
856
900
|
<label class="check"><input id="publicWebLink" type="checkbox" checked=${f.pub} onChange=${(e) => set("pub")(e.target.checked)} /><span>${tn("publicLink")}</span><${Impact} schema=${schema} field="web.public_link.allow_public" /></label>
|
|
857
901
|
<p class="note">${tn("publicLinkHint")}</p>
|
|
858
902
|
<div class="grid2">
|
|
@@ -861,6 +905,7 @@ function WebSection({ ctx, staged }) {
|
|
|
861
905
|
</div>
|
|
862
906
|
</section>
|
|
863
907
|
</fieldset>
|
|
908
|
+
${overPublicLink ? null : html`<${GuestsCard} ctx=${ctx} staged=${staged} /><${WebAuthorityCard} ctx=${ctx} staged=${staged} />`}
|
|
864
909
|
<section class="card s-web-readonly"><h3>${tn("webReadOnlyTitle")}</h3>
|
|
865
910
|
<p class="note">${tn("webReadOnlyLead")}</p>
|
|
866
911
|
<dl class="s-web-ro">${WEB_READ_ONLY.map((k) => html`<div key=${k}><dt><code>${k}</code></dt><dd>${shown(k)}</dd></div>`)}</dl>
|
|
@@ -915,7 +960,7 @@ function Developer({ ctx }) {
|
|
|
915
960
|
/** Staged, not applied: the count, what it will cost, Discard and Apply. */
|
|
916
961
|
function PendingBar({ staged, busy, onApply, onDiscard }) {
|
|
917
962
|
const kinds = [...new Set([...staged.values()].map((c) => c.impact))];
|
|
918
|
-
return html`<div class="s-pending" role="region" aria-label=${tn("pendingRegion")}>
|
|
963
|
+
return html`<div data-trust="panel-controls" class="s-pending" role="region" aria-label=${tn("pendingRegion")}>
|
|
919
964
|
<strong>${tn("changesPending", staged.size)}</strong>
|
|
920
965
|
<span class="note">${kinds.map(impactText).join(" · ")}</span>
|
|
921
966
|
<span class="grow"></span>
|
|
@@ -938,7 +983,7 @@ function OperationCard({ op, schema }) {
|
|
|
938
983
|
const mismatch = schema && schema.fleet_signature_mismatch;
|
|
939
984
|
const title = op.phase === "failed" ? tn("applyPartial") : fleetRestarting ? tn("restartFleetTitle") : busy ? tn("applying")
|
|
940
985
|
: failedRows ? tn("applyPartial") : needsRestart ? tn("applyRestartNeeded") : tn("applyDone");
|
|
941
|
-
const note = op.phase === "failed" ? (op.error === "busy" ? tn("applyBusy") : op.error ? tn("applyStepFailed", op.error) : "")
|
|
986
|
+
const note = op.phase === "failed" ? (op.error === "busy" ? tn("applyBusy") : op.error ? tn("applyStepFailed", applyErrorText(op.error)) : "")
|
|
942
987
|
: fleetRestarting ? tn("restartFleetWaiting") : op.lostJob ? tn("applyLostJob")
|
|
943
988
|
: job && job.overdue ? tn("applyStillWorking", Math.round((job.elapsed_ms || 0) / 1000))
|
|
944
989
|
: mismatch && needsRestart ? tn("signatureMismatch", mismatch.join(", ")) : needsRestart ? tn("applyRestartHint") : "";
|
|
@@ -965,7 +1010,7 @@ function OperationCard({ op, schema }) {
|
|
|
965
1010
|
${op.steps.length ? html`<ul class="s-op-steps">${op.steps.map((s, i) => html`<li key=${i} class=${`s-step ${s.status}`}>
|
|
966
1011
|
<span class="s-step-icon" aria-hidden="true">${icon(s.status) ? html`<${Icon} name=${icon(s.status)} size=${14} />` : "·"}</span>
|
|
967
1012
|
<span class="grow">${s.label}</span>
|
|
968
|
-
<span class="note">${s.status === "waiting" ? tn("stepWaiting") : s.status === "skipped" ? tn("stepSkipped") : s.status === "failed" ? (s.error
|
|
1013
|
+
<span class="note">${s.status === "waiting" ? tn("stepWaiting") : s.status === "skipped" ? tn("stepSkipped") : s.status === "failed" ? (s.error ? applyErrorText(s.error) : tn("applyFailed")) : s.note || impactText(s.impact)}</span></li>`)}</ul>` : null}
|
|
969
1014
|
${rows.length ? html`<ul class="s-op-steps">${rows.map((r) => html`<li key=${r.target} class=${`s-step ${r.status}`}>
|
|
970
1015
|
<span class="s-step-icon" aria-hidden="true">${r.status === "done" ? html`<${Icon} name="check" size=${14} />` : r.status === "failed" ? html`<${Icon} name="alert" size=${14} />` : r.status === "restart-required" ? html`<${Icon} name="restart" size=${14} />` : "·"}</span>
|
|
971
1016
|
<span class="grow">${r.target === "fleet" ? "AgEnD" : shortName(r.target, {})}</span>
|
package/dist/ui/preview-panel.js
CHANGED
|
@@ -16,6 +16,7 @@ import { Icon } from "/assets/ui-icons.js";
|
|
|
16
16
|
import "./chat-render.js";
|
|
17
17
|
import "./preview.js";
|
|
18
18
|
import { loadHtmlAttachment } from "./html-attachment.js";
|
|
19
|
+
import { EffectTrialPanel } from "./effect-trial-panel.js";
|
|
19
20
|
import { chatTime, onDayChange } from "./chat-time.js";
|
|
20
21
|
|
|
21
22
|
const R = () => globalThis.AgendChatRender;
|
|
@@ -43,14 +44,25 @@ export const panelClaims = () => claims;
|
|
|
43
44
|
/** The frame's key in preview.js: its own, so the card that opened it keeps its own state. */
|
|
44
45
|
export const frameKey = (key) => `panel:${key}`;
|
|
45
46
|
/** Show `spec` in the panel; `run`: start it there (the card's "Open in panel" click). The block shown before stops. */
|
|
47
|
+
function retire(open) {
|
|
48
|
+
if (!open) return;
|
|
49
|
+
if (open.kind === "trial") { try { open.handle.stop(); } catch { /* host controller owns cleanup */ } }
|
|
50
|
+
else if (P()) P().stop(frameKey(open.key), "stopped", "");
|
|
51
|
+
}
|
|
46
52
|
export function openPanel(spec, { run = false } = {}) {
|
|
47
|
-
|
|
48
|
-
set({ open: { ...spec }, run: run ? ++runs : 0 });
|
|
53
|
+
const old = state.open;
|
|
54
|
+
set({ open: { ...spec, kind: "html" }, run: run ? ++runs : 0 });
|
|
55
|
+
retire(old); // State changes first: cleanup reentry cannot close a newer panel.
|
|
56
|
+
}
|
|
57
|
+
/** A checked controller handle enters the existing component slot; no HTML run token is issued. */
|
|
58
|
+
export function openTrialPanel(spec) {
|
|
59
|
+
const old = state.open;
|
|
60
|
+
set({ open: { ...spec, kind: "trial" }, run: 0 }); retire(old);
|
|
49
61
|
}
|
|
50
|
-
/** Close the
|
|
62
|
+
/** Close publishes the empty slot before old-owner callbacks can reenter. */
|
|
51
63
|
export function closePanel() {
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
const old = state.open; if (!old) return;
|
|
65
|
+
set({ open: null, run: 0 }); retire(old);
|
|
54
66
|
}
|
|
55
67
|
/** The card key the panel shows, or null. */
|
|
56
68
|
export const shownKey = () => (state.open ? state.open.key : null);
|
|
@@ -67,7 +79,7 @@ export function htmlTitle(code) {
|
|
|
67
79
|
* without one, the newest block does. `msgs` in order; `keyOf` makes a message's key.
|
|
68
80
|
*/
|
|
69
81
|
export function newerVersion(open, msgs, keyOf) {
|
|
70
|
-
if (!open || !Array.isArray(msgs)) return null;
|
|
82
|
+
if (!open || open.kind === "trial" || !Array.isArray(msgs)) return null;
|
|
71
83
|
const at = msgs.findIndex(x => keyOf(x) === open.msgKey);
|
|
72
84
|
if (at < 0) return null;
|
|
73
85
|
// An attached file: a later agent reply attaching a file of the same name is its newer version. Its HTML is read
|
|
@@ -132,7 +144,8 @@ export function PreviewPanel({ name, split, msgs, subscribe, keyOf, reveal, down
|
|
|
132
144
|
const pending = useRef(0); // #1704: the card's click, waiting for this device's Allow (the st.run it came with)
|
|
133
145
|
const ownAllow = useRef(0); // while this panel's own Allow commits its choice: the click it answers (not cancelled by it)
|
|
134
146
|
const holder = useRef(null), divider = useRef(null), panel = useRef(null);
|
|
135
|
-
const
|
|
147
|
+
const trial = st.open?.kind === "trial" && st.open.instance === name ? st.open : null;
|
|
148
|
+
const open = st.open?.kind !== "trial" && st.open?.instance === name ? st.open : null;
|
|
136
149
|
|
|
137
150
|
useEffect(() => panelStore.subscribe(setSt), []);
|
|
138
151
|
// This device's choice (here or in another tab) decides whether Preview is offered: re-read it when it changes.
|
|
@@ -231,6 +244,9 @@ export function PreviewPanel({ name, split, msgs, subscribe, keyOf, reveal, down
|
|
|
231
244
|
// Esc in the panel closes it (and is not the chat's "stop the reply").
|
|
232
245
|
const onPanelKey = (e) => { if (e.key === "Escape" && !e.isComposing) { e.preventDefault(); closePanel(); } };
|
|
233
246
|
|
|
247
|
+
if (trial) return html`<${EffectTrialPanel} binding=${trial.binding} title=${trial.handle.reply.offer.title}
|
|
248
|
+
current=${trial.handle.current} ownerCss=${trial.ownerCss} onStage=${trial.onStage}
|
|
249
|
+
onStop=${trial.handle.stop} onClose=${() => { if (panelStore.get().open === trial) closePanel(); }} />`;
|
|
234
250
|
if (!open) return null;
|
|
235
251
|
const going = run.state === "starting" || run.state === "running";
|
|
236
252
|
const a = P().availability();
|
|
@@ -250,9 +266,9 @@ export function PreviewPanel({ name, split, msgs, subscribe, keyOf, reveal, down
|
|
|
250
266
|
if (want && pending.current === want && panelStore.get().run === want) start();
|
|
251
267
|
};
|
|
252
268
|
const source = t("chat.pvSource", open.sender || name, timeOf(open.ts));
|
|
253
|
-
return html`<div class="pv-divider" ref=${divider} role="separator" aria-orientation="vertical" tabindex="0" aria-label=${t("chat.pvResize")}
|
|
269
|
+
return html`<div data-trust="preview" class="pv-divider" ref=${divider} role="separator" aria-orientation="vertical" tabindex="0" aria-label=${t("chat.pvResize")}
|
|
254
270
|
aria-valuemin=${String(MIN_PANEL)} onKeyDown=${onKey} onPointerDown=${onDown}></div>
|
|
255
|
-
<aside class="pv-panel" ref=${panel} aria-label=${t("chat.pvPanel")} onKeyDown=${onPanelKey}>
|
|
271
|
+
<aside data-trust="preview" class="pv-panel" ref=${panel} aria-label=${t("chat.pvPanel")} onKeyDown=${onPanelKey}>
|
|
256
272
|
<div class="pv-panel-head">
|
|
257
273
|
<button type="button" class="icon-btn only-narrow pv-panel-close" title=${t("chat.pvBack")} aria-label=${t("chat.pvBack")} onClick=${closePanel}><${Icon} name="back" size=${18} /></button>
|
|
258
274
|
<div class="pv-panel-title"><strong>${t("chat.pvPanel")}</strong>
|
package/dist/ui/preview.js
CHANGED
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
notify();
|
|
101
101
|
return true;
|
|
102
102
|
}
|
|
103
|
-
if (j && (j.code === "publicLinkPreviewFailed" || j.code === "publicLink" || j.code === "fleetOff")) {
|
|
103
|
+
if (j && (j.code === "publicLinkPreviewFailed" || j.code === "publicLink" || j.code === "fleetOff" || j.code === "listenFailed" || j.code === "notListening")) {
|
|
104
104
|
cfg.reasonCode = j.code; cfg.reason = ""; cfg.detail = typeof j.detail === "string" ? j.detail : "";
|
|
105
105
|
notify();
|
|
106
106
|
return true;
|
|
@@ -191,7 +191,8 @@
|
|
|
191
191
|
if (!cfg.previewOrigin || !cfg.boot) {
|
|
192
192
|
// The server's reason, in the page's language when the server named it (a code), else as the server wrote it.
|
|
193
193
|
// #1723: a failed public-link preview names why ({0} is the reason, in the page's words).
|
|
194
|
-
var arg = cfg.reasonCode === "publicLinkPreviewFailed" ? say("pvFail_" + (cfg.detail || "unknown"), Object.prototype.hasOwnProperty.call(FAIL_EN, cfg.detail) ? FAIL_EN[cfg.detail] : "an unexpected error")
|
|
194
|
+
var arg = cfg.reasonCode === "publicLinkPreviewFailed" ? say("pvFail_" + (cfg.detail || "unknown"), Object.prototype.hasOwnProperty.call(FAIL_EN, cfg.detail) ? FAIL_EN[cfg.detail] : "an unexpected error")
|
|
195
|
+
: cfg.reasonCode === "listenFailed" ? cfg.detail : cfg.dashboardOrigin;
|
|
195
196
|
var english = cfg.reasonCode === "publicLinkPreviewFailed" ? "Previews are unavailable on this public link: {0}. The link itself keeps working."
|
|
196
197
|
: cfg.reason || "Previews are not available here.";
|
|
197
198
|
var server = cfg.reasonCode ? say("pvServer_" + cfg.reasonCode, english, arg) : "";
|