@songsid/agend 2.3.0-beta.2 → 2.3.0-beta.20
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 +704 -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
|
@@ -60,7 +60,7 @@ export function t(key, ...values) {
|
|
|
60
60
|
|
|
61
61
|
register("app", {
|
|
62
62
|
en: {
|
|
63
|
-
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet
|
|
63
|
+
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet", view: "View", settings: "Settings", instances: "Instances", newInstance: "New instance", newAgent: "New agent",
|
|
64
64
|
collapse: "Hide the sidebar", expand: "Show the sidebar", openMenu: "Open the sidebar", closeMenu: "Close the sidebar",
|
|
65
65
|
resizeSidebar: "Sidebar width", resizeSidebarHint: "Drag to resize · double-click to reset",
|
|
66
66
|
names: "Names", namesNickname: "Nickname first", namesInstance: "Real name first",
|
|
@@ -74,11 +74,13 @@ register("app", {
|
|
|
74
74
|
hydrating: "Loading what is open now…", hydrateFailed: "Could not load what is open now (prompts, ticks).",
|
|
75
75
|
skip: "Skip to the conversation", loadFailed: "This could not be loaded.", retry: "Try again", loading: "Loading…",
|
|
76
76
|
noInstances: "No instances yet", noInstancesHint: "Create one to start chatting.",
|
|
77
|
+
guestChip: "Guest", guestAs: "Guest · {0}", guestAsOn: "Guest · {0} ({1})", guestHint: "You see only the agents you can already use in chat.",
|
|
77
78
|
session: "Session", signIn: "Sign in", signedIn: "Signed in", signedOut: "Not signed in", thisDevice: "This device", devicePrefs: "Theme and language",
|
|
78
79
|
lastActive: "active {0}", justNow: "just now", minAgo: "{0} min ago", hrAgo: "{0} h ago", signOut: "Sign out",
|
|
79
80
|
signOutAll: "Sign out everywhere", devices: "Signed-in devices", expires: "Ends by {0} at the latest, or after {1} unused",
|
|
80
81
|
failed: "That did not work — try again.", close: "Close", more: "More actions", menu: "Menu",
|
|
81
82
|
pendingTitle: "Changes waiting for confirmation", pending_pending: "Waiting for confirmation", pending_applying: "Confirmed — applying…",
|
|
83
|
+
pendingWeb: "Confirmed by your account (this browser is web-verified). General is told.",
|
|
82
84
|
pending_applied: "Confirmed and applied", pending_rejected: "Not applied", pending_expired: "Expired — nothing was changed",
|
|
83
85
|
pending_stale: "Not applied — settings changed meanwhile", pending_failed: "Confirmed, but applying it failed",
|
|
84
86
|
pendingChat: "A fleet admin confirms this in chat (General topic).", pendingHost: "Confirm it on the host: {0}", pendingLeft: "{0} left", withdraw: "Withdraw",
|
|
@@ -86,13 +88,16 @@ register("app", {
|
|
|
86
88
|
opDone: "Settings applied", opRestart: "Settings saved — AgEnD needs a restart to use them", opPartial: "Some settings were not applied",
|
|
87
89
|
opFailed: "Settings were not applied", openSettings: "Open Settings",
|
|
88
90
|
pendingSent: "Sent for confirmation — a fleet admin confirms it in chat.",
|
|
91
|
+
pendingSelfSent: "Confirmed by your account (this browser is web-verified) — applying.",
|
|
89
92
|
needsNav: "Needs you", needsTab: "Needs you", needsCount: "{0} waiting",
|
|
93
|
+
// #2293: global search — chats, cross-instance messages and tasks (not the sidebar's filter of agents).
|
|
94
|
+
search: "Search", searchTitle: "Search chats, messages between agents and tasks ({0})",
|
|
90
95
|
confirmTitle: "Please confirm", confirmOk: "Continue", cancel: "Cancel",
|
|
91
96
|
// The server's own wording (src/locale.ts needs.reason.*), so the web says what Discord says.
|
|
92
97
|
needs_reason_hang: "Not responding", needs_reason_exited: "Exited", needs_reason_assist: "Waiting at its terminal", needs_reason_permission: "Permission needed", needs_reason_dangerous_command: "Dangerous command waiting", needs_reason_login: "Sign-in needed", needs_reason_dialog: "Waiting at a dialog", needs_reason_terminal_input: "May be waiting for input", needs_reason_auth_paused: "Paused: sign-in needed", needs_reason_crashed: "Crashed", needs_reason_delivery_uncertain: "Could not confirm delivery", needs_reason_delivery_failed: "Delivery failed",
|
|
93
98
|
},
|
|
94
99
|
"zh-TW": {
|
|
95
|
-
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet 概覽", view: "檢視", settings: "設定", instances: "Instances", newInstance: "新增 instance",
|
|
100
|
+
brand: "AgEnD", fleet: "Fleet", fleetOverview: "Fleet 概覽", view: "檢視", settings: "設定", instances: "Instances", newInstance: "新增 instance", newAgent: "新增 Agent",
|
|
96
101
|
collapse: "隱藏側邊欄", expand: "顯示側邊欄", openMenu: "打開側邊欄", closeMenu: "關閉側邊欄",
|
|
97
102
|
resizeSidebar: "側邊欄寬度", resizeSidebarHint: "拖曳調整寬度 · 按兩下恢復預設",
|
|
98
103
|
names: "名稱", namesNickname: "暱稱優先", namesInstance: "實際名稱優先",
|
|
@@ -106,11 +111,13 @@ register("app", {
|
|
|
106
111
|
hydrating: "正在載入目前的狀態…", hydrateFailed: "無法載入目前的狀態(提示、送達標記)。",
|
|
107
112
|
skip: "跳到對話", loadFailed: "無法載入。", retry: "再試一次", loading: "載入中…",
|
|
108
113
|
noInstances: "還沒有 instance", noInstancesHint: "建立一個就能開始聊天。",
|
|
114
|
+
guestChip: "訪客", guestAs: "訪客 · {0}", guestAsOn: "訪客 · {0}({1})", guestHint: "你只會看到在聊天中本來就能用的 agent。",
|
|
109
115
|
session: "登入狀態", signIn: "登入", signedIn: "已登入", signedOut: "尚未登入", thisDevice: "這台裝置", devicePrefs: "主題與語言",
|
|
110
116
|
lastActive: "{0}活動", justNow: "剛剛", minAgo: "{0} 分鐘前", hrAgo: "{0} 小時前", signOut: "登出",
|
|
111
117
|
signOutAll: "全部登出", devices: "已登入的裝置", expires: "最晚 {0} 結束;閒置 {1} 也會結束",
|
|
112
118
|
failed: "沒有成功,請再試一次。", close: "關閉", more: "更多動作", menu: "選單",
|
|
113
119
|
pendingTitle: "等待確認的變更", pending_pending: "等待確認", pending_applying: "已確認——套用中…",
|
|
120
|
+
pendingWeb: "由你的帳號確認(這個瀏覽器已通過網頁驗證),也會通知 General。",
|
|
114
121
|
pending_applied: "已確認並套用", pending_rejected: "未套用", pending_expired: "已逾時——沒有任何變更",
|
|
115
122
|
pending_stale: "未套用——設定在這期間已變動", pending_failed: "已確認,但套用失敗",
|
|
116
123
|
pendingChat: "由 fleet 管理員在聊天(General topic)中確認。", pendingHost: "請在主機上確認:{0}", pendingLeft: "剩 {0}", withdraw: "撤回",
|
|
@@ -118,7 +125,9 @@ register("app", {
|
|
|
118
125
|
opDone: "設定已套用", opRestart: "設定已儲存——需要重新啟動 AgEnD 才會生效", opPartial: "部分設定沒有套用",
|
|
119
126
|
opFailed: "設定沒有套用", openSettings: "開啟設定",
|
|
120
127
|
pendingSent: "已送出確認——由 fleet 管理員在聊天中確認。",
|
|
128
|
+
pendingSelfSent: "已由你的帳號確認(這個瀏覽器已通過網頁驗證)——套用中。",
|
|
121
129
|
needsNav: "等你處理", needsTab: "待處理", needsCount: "{0} 件待處理",
|
|
130
|
+
search: "搜尋", searchTitle: "搜尋聊天、agent 之間的訊息與任務({0})",
|
|
122
131
|
confirmTitle: "請確認", confirmOk: "繼續", cancel: "取消",
|
|
123
132
|
needs_reason_hang: "沒有回應", needs_reason_exited: "已結束", needs_reason_assist: "在終端機上等待", needs_reason_permission: "需要權限", needs_reason_dangerous_command: "危險指令待確認", needs_reason_login: "需要登入", needs_reason_dialog: "停在對話框", needs_reason_terminal_input: "可能在等輸入", needs_reason_auth_paused: "已暫停:需要登入", needs_reason_crashed: "已崩潰", needs_reason_delivery_uncertain: "無法確認是否送達", needs_reason_delivery_failed: "傳送失敗",
|
|
124
133
|
},
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// - The status frame's prefs_rev: another device changed something; the host's values are read again and applied. A
|
|
19
19
|
// revision counts as seen only once its read succeeded (a failed one is tried again, at most every few seconds).
|
|
20
20
|
import { deviceLanguage, lang, setLang } from "./app-i18n.js";
|
|
21
|
-
import { appStore } from "./app-store.js";
|
|
21
|
+
import { appStore, guestPage } from "./app-store.js";
|
|
22
22
|
|
|
23
23
|
const SYNCED_FLAG = "agend_prefs_synced";
|
|
24
24
|
const RETRY_MS = 5000;
|
|
@@ -31,6 +31,7 @@ export const SYNCED = {
|
|
|
31
31
|
"nav.collapsed": { ls: "agend_instance_collapsed", ...json },
|
|
32
32
|
"nav.filter": { ls: "agend_instance_filter", ...json },
|
|
33
33
|
"nav.favorites": { ls: "agend_favorites", ...json }, // #1664
|
|
34
|
+
"nav.sort": { ls: "agend_nav_sort", ...json }, // #2179
|
|
34
35
|
"preview.optIn": { ls: "agend_html_preview", toLocal: (v) => (v ? "on" : null), fromLocal: (s) => (s === "on" ? true : undefined) },
|
|
35
36
|
"names.primary": { ls: "agend_names_primary", toLocal: (v) => (v === "instance" ? v : null), fromLocal: (s) => (s === "instance" ? s : undefined) }, // #1722
|
|
36
37
|
// #1629 r2 (d): "Show agents' themes and effects" — on unless turned off (only "off" is cached).
|
|
@@ -40,8 +41,9 @@ export const SYNCED = {
|
|
|
40
41
|
"card.sizeByInstance": { ls: "agend_card_sizes", ...json },
|
|
41
42
|
// #1629 r4-4: the person's own sidebar widget ({ spec, data }), drawn by the page's own components.
|
|
42
43
|
"widget.sidebar": { ls: "agend_widget_sidebar", ...json },
|
|
43
|
-
// #1958: where identity colours show by default (
|
|
44
|
+
// #1958: where identity colours show by default (#2056: name, bar and ring unless chosen), and the host's switch to turn them off.
|
|
44
45
|
"color.show": { ls: "agend_color_show", ...json },
|
|
46
|
+
"theme.pageByInstance": { ls: "agend_theme_page", ...json }, // #2196
|
|
45
47
|
"color.off": { ls: "agend_color_off", toLocal: (v) => (v === true ? "on" : null), fromLocal: (s) => (s === "on" ? true : undefined) },
|
|
46
48
|
};
|
|
47
49
|
// #1629: fixed personal scope. A separate session-bound owner-effect store synchronizes these, never this host cache.
|
|
@@ -77,6 +79,15 @@ const inflight = new Map(); // key → writes sent and not answered yet
|
|
|
77
79
|
let flushTimer = null;
|
|
78
80
|
let writes = Promise.resolve(); // one write at a time, in the order they were made
|
|
79
81
|
const listeners = new Set();
|
|
82
|
+
// #2193: whether the signed-in person has a personal effect slot chosen (their fx.* keys: in the page's data-prefs and
|
|
83
|
+
// in every host read, never in this host cache). The effects runtime is loaded only when there is something to play.
|
|
84
|
+
const ownerEffectsIn = (values) => !!values && OWNER_EFFECT_PREF_KEYS.some((k) => own(values, k) && values[k] != null && values[k] !== "");
|
|
85
|
+
let ownerFx = initial ? ownerEffectsIn(initial.values) : false;
|
|
86
|
+
const ownerFxListeners = new Set();
|
|
87
|
+
/** Whether the person has any personal effect (fx.page/header/sidebar/box/cursor) chosen, as this page last read. */
|
|
88
|
+
export function ownerEffectsChosen() { return ownerFx; }
|
|
89
|
+
/** Called when that changes. Returns the unsubscribe. */
|
|
90
|
+
export function onOwnerEffectsChanged(fn) { ownerFxListeners.add(fn); return () => ownerFxListeners.delete(fn); }
|
|
80
91
|
|
|
81
92
|
// The host's values into the cache, now — before the sidebar, the tour or the first-run card read their keys. A key
|
|
82
93
|
// the host does not have: the default, on a device in step with the host; this device's own (to upload) otherwise.
|
|
@@ -88,9 +99,9 @@ if (host) {
|
|
|
88
99
|
}
|
|
89
100
|
}
|
|
90
101
|
|
|
91
|
-
/** This page may change the host's preferences: the signed-in app, not over the public link. */
|
|
102
|
+
/** This page may change the host's preferences: the signed-in app, not over the public link, not a guest's (#1920). */
|
|
92
103
|
export function prefsWritable() {
|
|
93
|
-
return !!initial && !(typeof document !== "undefined" && document.body && document.body.dataset.publicLink === "1");
|
|
104
|
+
return !!initial && !guestPage() && !(typeof document !== "undefined" && document.body && document.body.dataset.publicLink === "1");
|
|
94
105
|
}
|
|
95
106
|
/**
|
|
96
107
|
* The value in force for a key, in memory — never only in this browser's storage (a full storage must not bring back
|
|
@@ -117,6 +128,8 @@ function take(body) {
|
|
|
117
128
|
if (!isView(body) || (rev !== null && body.rev < rev)) return false;
|
|
118
129
|
rev = body.rev;
|
|
119
130
|
host = hostValues(body.values);
|
|
131
|
+
const fx = ownerEffectsIn(body.values);
|
|
132
|
+
if (fx !== ownerFx) { ownerFx = fx; for (const fn of [...ownerFxListeners]) { try { fn(fx); } catch { /* the rest still hear */ } } }
|
|
120
133
|
return true;
|
|
121
134
|
}
|
|
122
135
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// #1408 §3: the app's routes on the client. The same table as the server's classifier (src/web-shell-routes.ts;
|
|
2
2
|
// a test runs both over one list of cases). Pure: no DOM, no history.
|
|
3
3
|
|
|
4
|
-
export const FLEET_TABS = ["tasks", "schedules", "teams", "org", "cache", "config"];
|
|
4
|
+
export const FLEET_TABS = ["tasks", "schedules", "teams", "org", "cache", "usage", "config"];
|
|
5
5
|
export const SETTINGS_SECTIONS = ["device", "appearance", "agents", "bots", "classic", "general", "web", "advanced"]; // #1604: device first
|
|
6
6
|
const MAX_INSTANCE_NAME = 128;
|
|
7
7
|
const PATH_SEPARATOR_OR_CONTROL = /[/\\\u0000-\u001f\u007f]/;
|
|
@@ -50,6 +50,24 @@ export function viewPath(instance) { return instance ? `/view/${encodeURICompone
|
|
|
50
50
|
export function detailsPath(instance) { return `/ui/fleet/agent/${encodeURIComponent(instance)}`; }
|
|
51
51
|
export function logPath(instance) { return `/ui/log/${encodeURIComponent(instance)}`; }
|
|
52
52
|
export function fleetPath(tab) { return tab && tab !== "tasks" ? `/ui/fleet/${tab}` : "/ui/fleet"; }
|
|
53
|
+
/** #2183: this device's last Fleet tab (Fleet remembers it; the Org chart the first time). */
|
|
54
|
+
export const LAST_FLEET_TAB_KEY = "agend_last_fleet_tab";
|
|
55
|
+
export function lastFleetTab() {
|
|
56
|
+
let tab = null;
|
|
57
|
+
try { tab = localStorage.getItem(LAST_FLEET_TAB_KEY); } catch { /* storage blocked: the default */ }
|
|
58
|
+
return FLEET_TABS.includes(tab) ? tab : "org";
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* #2183: where Fleet (the sidebar's entry, the phone's tab) goes — on a Fleet tab, that tab (the route, not storage: the
|
|
62
|
+
* panel stores it in an effect after this render, and a storage write re-renders nothing); anywhere else, the last one.
|
|
63
|
+
*/
|
|
64
|
+
export function fleetEntryPath(route) {
|
|
65
|
+
return fleetPath(route && route.panel === "fleet" ? route.tab : lastFleetTab()); // parseRoute names only FLEET_TABS
|
|
66
|
+
}
|
|
67
|
+
export function rememberFleetTab(tab) {
|
|
68
|
+
if (!FLEET_TABS.includes(tab)) return;
|
|
69
|
+
try { localStorage.setItem(LAST_FLEET_TAB_KEY, tab); } catch { /* this page only */ }
|
|
70
|
+
}
|
|
53
71
|
export const NEEDS_PATH = "/ui/needs";
|
|
54
72
|
export function settingsPath(section) { return section && section !== "agents" ? `/settings/${section}` : "/settings"; }
|
|
55
73
|
export function routePath(route) {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { html, useEffect, useRef, useState } from "./app-html.js";
|
|
5
5
|
import { Icon } from "./ui-icons.js";
|
|
6
6
|
import { t, lang } from "./app-i18n.js";
|
|
7
|
+
import { AuthorizeChip } from "./web-authorize.js";
|
|
7
8
|
|
|
8
9
|
async function getJson(url) {
|
|
9
10
|
try {
|
|
@@ -53,6 +54,7 @@ export function SessionMenu() {
|
|
|
53
54
|
${!me ? html`<h3>${t("app.signedOut")}</h3><a class="btn" href=${`/signin?next=${encodeURIComponent(location.pathname)}`}>${t("app.signIn")}</a>` : html`
|
|
54
55
|
<h3>${t("app.signedIn")} · ${me.label}</h3>
|
|
55
56
|
<p class="sub">${t("app.expires", clock(me.expiresAt), span(me.idleMs))}</p>
|
|
57
|
+
<${AuthorizeChip} />
|
|
56
58
|
${rows.length > 1 ? html`<h3>${t("app.devices")}</h3><ul class="devices">${rows.map(s => html`<li key=${s.handle}>
|
|
57
59
|
<span class="grow"><span class="name">${s.label}${s.current ? ` · ${t("app.thisDevice")}` : ""}</span><span class="when">${t("app.lastActive", ago(s.lastSeen))}</span></span>
|
|
58
60
|
${s.current ? null : html`<button type="button" class="btn btn-sm danger" onClick=${() => act("DELETE", `/auth/sessions/${encodeURIComponent(s.handle)}`, refresh)}>${t("app.signOut")}</button>`}</li>`)}</ul>` : null}
|
|
@@ -7,11 +7,13 @@ import { Toasts } from "./ui-toast.js";
|
|
|
7
7
|
import { ConfirmHost } from "./ui-confirm.js";
|
|
8
8
|
import { ColorDialogHost } from "./identity-color.js";
|
|
9
9
|
import { t, lang, setLang, onLang } from "./app-i18n.js";
|
|
10
|
-
import { appStore, createStore, useStore } from "./app-store.js";
|
|
10
|
+
import { appStore, createStore, guestBadge, guestPage, useStore } from "./app-store.js";
|
|
11
11
|
import { navStore } from "./app-nav.js";
|
|
12
|
-
import {
|
|
12
|
+
import { toast } from "./ui-toast.js";
|
|
13
|
+
import { chatPath, viewPath, settingsPath, routeKey, NEEDS_PATH, fleetEntryPath } from "./app-route.js";
|
|
13
14
|
import { SessionMenu } from "./app-session.js";
|
|
14
|
-
import { savePref } from "./app-prefs.js";
|
|
15
|
+
import { onPrefsChanged, savePref } from "./app-prefs.js";
|
|
16
|
+
import { applyPageTheme, pageNow, resolvedMode, themesStore } from "./app-themes.js";
|
|
15
17
|
import { ErrorState, Skeleton } from "./ui-states.js";
|
|
16
18
|
import { InstanceNav, RosterNav, namesStore, setNamesPrimary } from "./instance-nav.js";
|
|
17
19
|
import { UsageRail, usageRailStore } from "./header-tools.js";
|
|
@@ -19,7 +21,7 @@ import { OwnerCssKeepBar } from "./owner-css.js";
|
|
|
19
21
|
import { AgentWidget, fleetBinds, sidebarWidget, sidebarWidgetStore } from "./agent-widget.js";
|
|
20
22
|
|
|
21
23
|
/** Shell state shared with panels: the phone drawer, the collapsed sidebar, extensions a panel module adds. */
|
|
22
|
-
export const shellStore = createStore({ drawer: false, collapsed: readCollapsed(), keyboard: false, dialog: null, side: null });
|
|
24
|
+
export const shellStore = createStore({ drawer: false, collapsed: readCollapsed(), keyboard: false, dialog: null, side: null, banner: null });
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
* The mounted panel's own sidebar section, in place of the instance list (View's roster: its groups, filter and order,
|
|
@@ -39,10 +41,66 @@ let newInstanceOpener = null;
|
|
|
39
41
|
export function setNewInstanceOpener(fn) { newInstanceOpener = fn; }
|
|
40
42
|
export function requestNewInstance() { if (newInstanceOpener) newInstanceOpener(); }
|
|
41
43
|
|
|
44
|
+
/**
|
|
45
|
+
* #2074: whether this page's session may make an agent — an admin's (/auth/session's tier); a guest's create is refused.
|
|
46
|
+
* Asked once per page; a session that ends takes the buttons away. A display hint only: the create route decides.
|
|
47
|
+
*/
|
|
48
|
+
export const canCreateStore = createStore({ value: false });
|
|
49
|
+
let canCreateOf = null; // the AgendAuth asked (one per page)
|
|
50
|
+
export function useCanCreate() {
|
|
51
|
+
const s = useStore(canCreateStore);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
const auth = typeof window !== "undefined" ? window.AgendAuth : undefined;
|
|
54
|
+
if (!auth || typeof auth.canWrite !== "function" || canCreateOf === auth) return;
|
|
55
|
+
canCreateOf = auth;
|
|
56
|
+
canCreateStore.set({ value: false });
|
|
57
|
+
Promise.resolve(auth.canWrite()).then((v) => { if (canCreateOf === auth && !auth.sessionEnded?.()) canCreateStore.set({ value: v === true }); }, () => {});
|
|
58
|
+
auth.onSessionEnd?.(() => { if (canCreateOf === auth) canCreateStore.set({ value: false }); });
|
|
59
|
+
}, []);
|
|
60
|
+
return s.value;
|
|
61
|
+
}
|
|
62
|
+
|
|
42
63
|
/** An app-level dialog (New instance): rendered by the shell until closed, whatever panel is showing. */
|
|
43
64
|
export function showDialog(Component, props = {}) { shellStore.set({ dialog: { Component, props } }); }
|
|
44
65
|
export function closeDialog() { shellStore.set({ dialog: null }); }
|
|
45
66
|
|
|
67
|
+
// ── #2293: global search — an admin's. The dialog lives behind the session gate (/ui/js/search-dialog.js) and loads the
|
|
68
|
+
// first time it opens; the sidebar row, the header's button and the shortcuts only open it. ──
|
|
69
|
+
export const isMacLike = () => typeof navigator !== "undefined" && /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent || "");
|
|
70
|
+
/** What the row and tooltips show: ⌘K on a Mac, Ctrl K elsewhere. */
|
|
71
|
+
export const searchShortcut = () => (isMacLike() ? "⌘K" : "Ctrl K");
|
|
72
|
+
/**
|
|
73
|
+
* Whether this page offers search: an admin's page reached directly. A guest's never, and never over the public link —
|
|
74
|
+
* the server refuses it there (#2298 review), so no entry, no shortcut, and Ctrl+F stays the browser's.
|
|
75
|
+
*/
|
|
76
|
+
export function searchOffered(admin) {
|
|
77
|
+
const onLink = typeof document !== "undefined" && !!document.body && document.body.dataset.publicLink === "1";
|
|
78
|
+
return !!admin && !guestPage() && !onLink;
|
|
79
|
+
}
|
|
80
|
+
let searchModule = null;
|
|
81
|
+
/** Open search; `preset.instance`: narrowed to that agent (Ctrl+F in its chat). */
|
|
82
|
+
export function openSearch(preset = {}) {
|
|
83
|
+
closeDrawer();
|
|
84
|
+
(searchModule ??= import("/ui/js/search-dialog.js")).then(
|
|
85
|
+
(m) => showDialog(m.SearchDialog, { preset }),
|
|
86
|
+
() => { searchModule = null; toast(t("app.loadFailed"), false); });
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Ctrl+K (⌘K) anywhere opens search; Ctrl+F (⌘F) in an agent's chat opens it narrowed to that agent — elsewhere the
|
|
90
|
+
* browser's own find stays. Not while another dialog is open (search, open already, has its input focused).
|
|
91
|
+
*/
|
|
92
|
+
export function handleSearchKey(e) {
|
|
93
|
+
if (!searchOffered(true)) return;
|
|
94
|
+
if (e.isComposing || e.altKey || e.shiftKey || !(isMacLike() ? e.metaKey : e.ctrlKey)) return;
|
|
95
|
+
const key = (e.key || "").toLowerCase();
|
|
96
|
+
if (key !== "k" && key !== "f") return;
|
|
97
|
+
if (typeof document !== "undefined" && document.querySelector("dialog[open]")) return;
|
|
98
|
+
const route = navStore.get().route;
|
|
99
|
+
if (key === "f" && !(route && route.panel === "chat" && route.instance)) return;
|
|
100
|
+
e.preventDefault();
|
|
101
|
+
openSearch(key === "f" ? { instance: route.instance } : {});
|
|
102
|
+
}
|
|
103
|
+
|
|
46
104
|
function readCollapsed() { try { return localStorage.getItem("agend_sidebar") === "hidden"; } catch { return false; } }
|
|
47
105
|
const narrow = () => typeof matchMedia === "function" && matchMedia("(max-width: 899px)").matches;
|
|
48
106
|
|
|
@@ -247,9 +305,8 @@ export function signInHref() {
|
|
|
247
305
|
function Sidebar({ route, onNewInstance, viewOnly }) {
|
|
248
306
|
const app = useStore(appStore);
|
|
249
307
|
const shell = useStore(shellStore);
|
|
250
|
-
|
|
251
|
-
const on = (panel) => !!route &&
|
|
252
|
-
const openInstance = openInstanceOf(route);
|
|
308
|
+
const canCreate = useCanCreate();
|
|
309
|
+
const on = (panel) => !!route && route.panel === panel;
|
|
253
310
|
// A count badge is hidden at 0; its number is also in the link's accessible name.
|
|
254
311
|
const navLink = (panel, href, icon, label, count = 0) => html`<a class=${`side-row${on(panel) ? " active" : ""}`} href=${href}
|
|
255
312
|
aria-current=${on(panel) ? "page" : undefined} aria-label=${count ? `${label} (${t("app.needsCount", count)})` : undefined} onClick=${closeDrawer}>
|
|
@@ -271,22 +328,39 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
|
|
|
271
328
|
<${SidebarResize} />
|
|
272
329
|
</aside>`;
|
|
273
330
|
}
|
|
274
|
-
// #
|
|
275
|
-
//
|
|
331
|
+
// #1920 phase 3: a guest's sidebar — its own agents to pick from, who it is signed in as, and its session; no fleet,
|
|
332
|
+
// Needs you, View, Settings, new agent or widget (each is an admin's, and the server refuses a guest them anyway).
|
|
333
|
+
if (guestPage()) {
|
|
334
|
+
return html`<aside id="sidebar" class="sidebar" aria-label=${t("app.menu")}>
|
|
335
|
+
<div class="side-head" data-trust="navigation">
|
|
336
|
+
<a class="brand" href="/ui" onClick=${closeDrawer}>${t("app.brand")}</a>
|
|
337
|
+
<button type="button" class="icon-btn side-collapse" onClick=${toggleSidebar} aria-label=${narrow() ? t("app.closeMenu") : t("app.collapse")} title=${narrow() ? t("app.closeMenu") : t("app.collapse")} aria-controls="sidebar"><${Icon} name="sidebar" /></button>
|
|
338
|
+
</div>
|
|
339
|
+
<${InstanceNav} route=${route} items=${app.instances} loaded=${app.ready !== false} exec=${app.exec} awaiting=${app.awaiting} onPick=${closeDrawer} />
|
|
340
|
+
<div class="side-foot" data-trust="navigation">
|
|
341
|
+
<${GuestChip} />
|
|
342
|
+
<${SessionMenu} />
|
|
343
|
+
</div>
|
|
344
|
+
<${SidebarResize} />
|
|
345
|
+
</aside>`;
|
|
346
|
+
}
|
|
347
|
+
// #1675: the whole fleet, from anywhere — top left, so at the top of a phone's drawer too. #2183 (the user's call): the
|
|
348
|
+
// one Fleet entry ("Fleet" / "Fleet 概覽"), on the tab this device used last (the Org chart the first time); an agent's
|
|
349
|
+
// View, Log and Details are its header's tabs, so the sidebar has no "Fleet" (Details) or "View" row of its own.
|
|
276
350
|
const onFleet = !!route && route.panel === "fleet";
|
|
277
|
-
const overview = html`<a class=${`side-row side-overview${onFleet ? " active" : ""}`} href=${
|
|
351
|
+
const overview = html`<a class=${`side-row side-overview${onFleet ? " active" : ""}`} href=${fleetEntryPath(route)}
|
|
278
352
|
aria-current=${onFleet ? "page" : undefined} onClick=${closeDrawer}><${Icon} name="org" /><span class="grow">${t("app.fleetOverview")}</span></a>`;
|
|
279
353
|
return html`<aside id="sidebar" class="sidebar" aria-label=${t("app.menu")}>
|
|
280
354
|
<div class="side-head" data-trust="navigation">
|
|
281
355
|
<a class="brand" href="/ui" onClick=${closeDrawer}>${t("app.brand")}</a>
|
|
282
356
|
<button type="button" class="icon-btn side-collapse" onClick=${toggleSidebar} aria-label=${narrow() ? t("app.closeMenu") : t("app.collapse")} title=${narrow() ? t("app.closeMenu") : t("app.collapse")} aria-controls="sidebar"><${Icon} name="sidebar" /></button>
|
|
283
|
-
<button type="button" class="icon-btn" onClick=${onNewInstance} aria-label=${t("app.newInstance")} title=${t("app.newInstance")}><${Icon} name="plus" /></button>
|
|
284
357
|
</div>
|
|
285
358
|
<nav data-trust="navigation" class="side-nav" aria-label=${t("app.menu")}>
|
|
286
359
|
${overview}
|
|
287
360
|
${navLink("needs", NEEDS_PATH, "inbox", t("app.needsNav"), needsCount)}
|
|
288
|
-
${
|
|
289
|
-
|
|
361
|
+
${searchOffered(canCreate) ? html`<button type="button" class="side-row side-search" onClick=${() => openSearch()} title=${t("app.searchTitle", searchShortcut())}
|
|
362
|
+
aria-keyshortcuts=${isMacLike() ? "Meta+K" : "Control+K"}><${Icon} name="search" /><span class="grow">${t("app.search")}</span><kbd class="kbd-hint" aria-hidden="true">${searchShortcut()}</kbd></button>` : null}
|
|
363
|
+
${canCreate && onNewInstance ? html`<button type="button" class="side-row side-new" onClick=${onNewInstance}><${Icon} name="plus" /><span class="grow">${t("app.newAgent")}</span></button>` : null}
|
|
290
364
|
</nav>
|
|
291
365
|
${shell.side ? html`<${shell.side.Component} />` : html`<${InstanceNav} route=${route} items=${app.instances} loaded=${app.ready !== false}
|
|
292
366
|
exec=${app.exec} awaiting=${app.awaiting} onPick=${closeDrawer} />`}
|
|
@@ -299,6 +373,17 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
|
|
|
299
373
|
</aside>`;
|
|
300
374
|
}
|
|
301
375
|
|
|
376
|
+
/** #1920 phase 3: "Guest · <name> (<platform>)" — who this guest's page is signed in as; what a guest sees, in its title. */
|
|
377
|
+
const PLATFORM_NAMES = { discord: "Discord", telegram: "Telegram" };
|
|
378
|
+
function GuestChip() {
|
|
379
|
+
const { name, platform } = guestBadge();
|
|
380
|
+
const where = PLATFORM_NAMES[platform] || platform;
|
|
381
|
+
const label = name ? (where ? t("app.guestAsOn", name, where) : t("app.guestAs", name)) : t("app.guestChip");
|
|
382
|
+
// Inside .side-foot (a marked, stock-trusted element): no trust marker of its own — effect-stock-trust's closed inventory
|
|
383
|
+
// refuses any element it does not know, which would hide a guest's static effect posters (#2101 review).
|
|
384
|
+
return html`<p class="guest-chip" title=${t("app.guestHint")}><${Icon} name="user" size=${14} /><span class="grow">${label}</span></p>`;
|
|
385
|
+
}
|
|
386
|
+
|
|
302
387
|
/** #1629 r4-4: the person's own sidebar widget (their synced preference), with the fleet's counts. */
|
|
303
388
|
function SidebarWidget({ app }) {
|
|
304
389
|
useStore(sidebarWidgetStore);
|
|
@@ -347,20 +432,25 @@ function PrefsPopover() {
|
|
|
347
432
|
* The header every panel shows: ☰ (phone, or a collapsed sidebar), its title and status, then its actions. `nav`
|
|
348
433
|
* (#1523 N2): an instance page's view switch — beside the title on a wide screen, a row of tabs under it on a phone.
|
|
349
434
|
*/
|
|
350
|
-
export function PanelHeader({ title, sub, children, headingRef, nav }) {
|
|
435
|
+
export function PanelHeader({ title, sub, children, headingRef, nav, notice }) {
|
|
351
436
|
const shell = useStore(shellStore);
|
|
437
|
+
const admin = useCanCreate();
|
|
438
|
+
const canCreate = admin && !!newInstanceOpener;
|
|
352
439
|
return html`<header data-trust="header" class=${`panel-head${shell.collapsed ? " collapsed" : ""}`}>
|
|
353
440
|
<button type="button" id="sbOpen" class="icon-btn sb-open" onClick=${() => (narrow() ? openDrawer() : toggleSidebar())}
|
|
354
441
|
aria-label=${narrow() ? t("app.openMenu") : t("app.expand")} title=${narrow() ? t("app.openMenu") : t("app.expand")} aria-controls="sidebar" aria-expanded=${shell.drawer ? "true" : "false"}><${Icon} name="menu" /></button>
|
|
442
|
+
${canCreate && shell.collapsed ? html`<button type="button" class="icon-btn sb-new" onClick=${requestNewInstance} aria-label=${t("app.newAgent")} title=${t("app.newAgent")}><${Icon} name="plus" /></button>` : null}
|
|
443
|
+
${searchOffered(admin) ? html`<button type="button" class="icon-btn sb-search" onClick=${() => openSearch()} aria-label=${t("app.search")} title=${t("app.searchTitle", searchShortcut())}><${Icon} name="search" /></button>` : null}
|
|
355
444
|
<div class="panel-title"><h1 ref=${headingRef} tabindex="-1">${title}</h1>${sub ? html`<div class="panel-sub">${sub}</div>` : null}</div>
|
|
356
445
|
${nav || null}
|
|
357
446
|
<div class="panel-actions">${children}</div>
|
|
447
|
+
${notice || null}
|
|
358
448
|
</header>`;
|
|
359
449
|
}
|
|
360
450
|
|
|
361
451
|
/**
|
|
362
|
-
* #1523 N2: the instance a page is about — Chat, View, Log (#1218) or Details of it — or null.
|
|
363
|
-
*
|
|
452
|
+
* #1523 N2: the instance a page is about — Chat, View, Log (#1218) or Details of it — or null. #2183: with one open, the
|
|
453
|
+
* phone's Chat tab is current and goes to its chat.
|
|
364
454
|
*/
|
|
365
455
|
export function openInstanceOf(route) {
|
|
366
456
|
return route && (route.panel === "chat" || route.panel === "view" || route.panel === "log" || route.panel === "details") && route.instance ? route.instance : null;
|
|
@@ -371,24 +461,28 @@ function BottomTabs({ route, viewOnly }) {
|
|
|
371
461
|
let last = null;
|
|
372
462
|
try { last = localStorage.getItem("agend_last_instance"); } catch { /* none */ }
|
|
373
463
|
const open = openInstanceOf(route);
|
|
374
|
-
|
|
464
|
+
// #2183: Chat stands for the open agent's pages (its View, Log and Details are the tabs under its header), so it goes to that agent's chat.
|
|
465
|
+
const chatHref = open ? chatPath(open) : last ? chatPath(last) : "/ui";
|
|
375
466
|
const anyAwaiting = Object.keys(app.awaiting).length;
|
|
376
467
|
const tab = (href, icon, label, active, badge, badgeLabel) => html`<a class=${`tab${active ? " active" : ""}`} href=${href} aria-current=${active ? "page" : undefined}>
|
|
377
468
|
<${Icon} name=${icon} size=${20} /><span>${label}</span>${badge ? html`<span class="tab-badge" aria-label=${badgeLabel || t("app.needsYou")}>${badge}</span>` : null}</a>`;
|
|
378
|
-
let lastView = null;
|
|
379
|
-
try { lastView = localStorage.getItem("agend_last_view"); } catch { /* none */ }
|
|
380
|
-
const viewHref = route && (route.panel === "view" || route.panel === "log" || route.panel === "details") && route.instance ? viewPath(route.instance) : viewPath(lastView);
|
|
381
469
|
if (viewOnly) {
|
|
470
|
+
let lastView = null;
|
|
471
|
+
try { lastView = localStorage.getItem("agend_last_view"); } catch { /* none */ }
|
|
472
|
+
const viewHref = route && route.panel === "view" && route.instance ? viewPath(route.instance) : viewPath(lastView);
|
|
382
473
|
return html`<nav data-trust="navigation" class="tabs" aria-label=${t("app.menu")}>
|
|
383
474
|
${tab(viewHref, "view", t("app.view"), route && route.panel === "view")}
|
|
384
475
|
${tab(signInHref(), "user", t("app.signIn"), false)}
|
|
385
476
|
</nav>`;
|
|
386
477
|
}
|
|
478
|
+
// #1920: a guest has only its chats (the drawer lists them): no tabs to switch between.
|
|
479
|
+
if (guestPage()) return null;
|
|
480
|
+
// #2183 (the user's call): four tabs — Chat (current on /ui and on any of an agent's pages), Needs you, Fleet (on its
|
|
481
|
+
// last tab), Settings.
|
|
387
482
|
return html`<nav data-trust="navigation" class="tabs" aria-label=${t("app.menu")}>
|
|
388
|
-
${tab(chatHref, "chat", t("app.chat"), route && route.panel === "chat", anyAwaiting)}
|
|
483
|
+
${tab(chatHref, "chat", t("app.chat"), !!open || (!!route && route.panel === "chat"), anyAwaiting)}
|
|
389
484
|
${tab(NEEDS_PATH, "inbox", t("app.needsTab"), route && route.panel === "needs", (app.needs || []).length, t("app.needsCount", (app.needs || []).length))}
|
|
390
|
-
${tab(
|
|
391
|
-
${tab(viewHref, "view", t("app.view"), route && route.panel === "view")}
|
|
485
|
+
${tab(fleetEntryPath(route), "fleet", t("app.fleet"), route && route.panel === "fleet")}
|
|
392
486
|
${tab(settingsPath(), "settings", t("app.settings"), route && route.panel === "settings")}
|
|
393
487
|
</nav>`;
|
|
394
488
|
}
|
|
@@ -435,8 +529,21 @@ export function PendingChanges({ inline = false } = {}) {
|
|
|
435
529
|
const { pendingChanges } = useStore(appStore);
|
|
436
530
|
const list = pendingChanges || [];
|
|
437
531
|
useTick(list.some(p => p.state === "pending"));
|
|
532
|
+
// #2168: inline (Settings' own column), a request that has just started waiting is brought into view — on a phone the
|
|
533
|
+
// person applied far down the list, and the card that says where to confirm it sat above the screen. Once per request.
|
|
534
|
+
const box = useRef(null), shown = useRef(new Set());
|
|
535
|
+
useEffect(() => {
|
|
536
|
+
if (!inline || !box.current) return;
|
|
537
|
+
for (const p of list) {
|
|
538
|
+
if (p.state !== "pending" || shown.current.has(p.id)) continue;
|
|
539
|
+
shown.current.add(p.id);
|
|
540
|
+
const card = box.current.querySelector(`[data-pending="${p.id}"]`);
|
|
541
|
+
const still = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
542
|
+
if (card && typeof card.scrollIntoView === "function") card.scrollIntoView({ block: "nearest", behavior: still ? "auto" : "smooth" });
|
|
543
|
+
}
|
|
544
|
+
});
|
|
438
545
|
if (!list.length) return null;
|
|
439
|
-
return html`<div data-trust="confirmation" class=${`pending-stack${inline ? " inline" : ""}`} role="region" aria-label=${t("app.pendingTitle")}>${list.map(p => html`<section key=${p.id} class=${`pending-card ${p.state}`} role="status">
|
|
546
|
+
return html`<div data-trust="confirmation" ref=${box} class=${`pending-stack${inline ? " inline" : ""}`} role="region" aria-label=${t("app.pendingTitle")}>${list.map(p => html`<section key=${p.id} data-pending=${p.id} class=${`pending-card ${p.state}`} role="status">
|
|
440
547
|
<div class="pending-head"><${Icon} name=${p.state === "applied" ? "check" : p.state === "pending" || p.state === "applying" ? "clock" : "alert"} size=${16} />
|
|
441
548
|
<strong>${t(`app.pending_${p.state}`)}</strong>
|
|
442
549
|
${p.state === "pending" ? html`<span class="pending-left">${t("app.pendingLeft", mmss(p.deadline - NOW()))}</span>` : null}
|
|
@@ -444,6 +551,7 @@ export function PendingChanges({ inline = false } = {}) {
|
|
|
444
551
|
${p.label ? html`<div class="pending-label">${p.label}</div>` : null}
|
|
445
552
|
${Array.isArray(p.summary) && p.summary.length ? html`<ul class="pending-summary">${p.summary.map((line, i) => html`<li key=${i}>${line}</li>`)}</ul>` : null}
|
|
446
553
|
${p.state === "pending" ? html`<p class="note">${p.confirmation && p.confirmation.kind === "host_cli" ? t("app.pendingHost", `agend settings confirm ${p.id}`) : t("app.pendingChat")}</p>` : null}
|
|
554
|
+
${(p.state === "applying" || p.state === "applied") && p.confirmation && p.confirmation.kind === "web" ? html`<p class="note">${t("app.pendingWeb")}</p>` : null}
|
|
447
555
|
${p.state !== "pending" && p.state !== "applying" && p.state !== "applied" && p.outcome && p.outcome.message ? html`<p class="note">${p.outcome.message}</p>` : null}
|
|
448
556
|
${p.withdraw ? html`<div class="pending-actions"><button type="button" class="btn btn-sm" onClick=${p.withdraw}>${t("app.withdraw")}</button></div>` : null}
|
|
449
557
|
</section>`)}</div>`;
|
|
@@ -493,9 +601,43 @@ function Outlet({ route, seq, panels }) {
|
|
|
493
601
|
return html`<${C} route=${route} navKey=${`${routeKey(route)}|${seq}|${lang()}`} />`;
|
|
494
602
|
}
|
|
495
603
|
|
|
604
|
+
/**
|
|
605
|
+
* #2196: the open agent's colours on the whole page (its theme's page section, or a person's choice), drawn on the
|
|
606
|
+
* shell in the same render that opens it — no fetch (the themes are on the page already), no flash, colours only, so
|
|
607
|
+
* no layout moves. Redrawn when the themes, the person's choices, the viewer's switch or the light/dark mode move.
|
|
608
|
+
*/
|
|
609
|
+
function usePageTheme(ref, route) {
|
|
610
|
+
useStore(themesStore);
|
|
611
|
+
const [, bump] = useState(0);
|
|
612
|
+
useEffect(() => onPrefsChanged((changed) => { if (changed.has("theme.pageByInstance") || changed.has("fx.show")) bump((n) => n + 1); }), []);
|
|
613
|
+
useEffect(() => {
|
|
614
|
+
const T = globalThis.AgendTheme;
|
|
615
|
+
const off = T && typeof T.onChange === "function" ? T.onChange(() => bump((n) => n + 1)) : null;
|
|
616
|
+
let mq = null;
|
|
617
|
+
try { mq = globalThis.matchMedia ? globalThis.matchMedia("(prefers-color-scheme: light)") : null; } catch { mq = null; }
|
|
618
|
+
const onMq = () => bump((n) => n + 1);
|
|
619
|
+
if (mq && typeof mq.addEventListener === "function") mq.addEventListener("change", onMq);
|
|
620
|
+
return () => { if (typeof off === "function") off(); if (mq && typeof mq.removeEventListener === "function") mq.removeEventListener("change", onMq); };
|
|
621
|
+
}, []);
|
|
622
|
+
const mode = resolvedMode();
|
|
623
|
+
const p = pageNow(mode, route);
|
|
624
|
+
const key = p ? `${mode}|${JSON.stringify(p)}` : "";
|
|
625
|
+
useLayoutEffect(() => { applyPageTheme(ref.current, p, mode); }, [key]);
|
|
626
|
+
// #2199: the agent open now, as body[data-agent] — for a person's own custom CSS to follow (body[data-agent="x"]
|
|
627
|
+
// { --bg-sidebar: … }); set and cleared in the same render as the page colours, whatever the themes switch says.
|
|
628
|
+
const agent = openInstanceOf(route);
|
|
629
|
+
useLayoutEffect(() => {
|
|
630
|
+
const body = typeof document !== "undefined" ? document.body : null;
|
|
631
|
+
if (!body || !body.dataset) return;
|
|
632
|
+
if (agent) body.dataset.agent = agent; else delete body.dataset.agent;
|
|
633
|
+
}, [agent]);
|
|
634
|
+
}
|
|
635
|
+
|
|
496
636
|
export function Shell({ panels, onNewInstance, viewOnly = false }) {
|
|
497
637
|
const nav = useStore(navStore);
|
|
498
638
|
const shell = useStore(shellStore);
|
|
639
|
+
const root = useRef(null);
|
|
640
|
+
usePageTheme(root, nav.route);
|
|
499
641
|
const [, relang] = useState(0);
|
|
500
642
|
// A language switch re-renders everything and gives the panel a new lease (its key includes the language).
|
|
501
643
|
useEffect(() => onLang(() => relang(n => n + 1)), []);
|
|
@@ -508,23 +650,25 @@ export function Shell({ panels, onNewInstance, viewOnly = false }) {
|
|
|
508
650
|
vv.addEventListener("resize", onResize);
|
|
509
651
|
return () => vv.removeEventListener("resize", onResize);
|
|
510
652
|
}, []);
|
|
511
|
-
const
|
|
512
|
-
|
|
653
|
+
const guest = guestPage(); // #1920: a guest's page — no operations, usage, pending changes or owner CSS
|
|
654
|
+
const cls = ["shell", shell.collapsed ? "sb-collapsed" : "", shell.drawer ? "sb-open" : "", shell.keyboard ? "kb-open" : "", guest ? "guest" : ""].filter(Boolean).join(" ");
|
|
655
|
+
return html`<div ref=${root} class=${cls}>
|
|
513
656
|
<a data-trust="navigation" class="skip" href="#main">${t("app.skip")}</a>
|
|
514
657
|
<${Sidebar} route=${nav.route} onNewInstance=${onNewInstance} viewOnly=${viewOnly} />
|
|
515
658
|
<div class="scrim" onClick=${closeDrawer} aria-hidden="true"></div>
|
|
516
659
|
<main id="main" class="main" tabindex="-1" inert=${shell.drawer && narrow() ? true : undefined}>
|
|
517
660
|
<${ConnectionLine} />
|
|
518
|
-
${viewOnly ? null : html`<${OperationLine} route=${nav.route} />`}
|
|
661
|
+
${viewOnly || guest ? null : html`<${OperationLine} route=${nav.route} />`}
|
|
662
|
+
${viewOnly || guest || !shell.banner ? null : html`<${shell.banner} />`}
|
|
519
663
|
<${Outlet} route=${nav.route} seq=${nav.seq} panels=${panels} />
|
|
520
664
|
</main>
|
|
521
|
-
|
|
665
|
+
${guest ? null : html`<${UsageRail} route=${nav.route} />`}
|
|
522
666
|
<${BottomTabs} route=${nav.route} viewOnly=${viewOnly} />
|
|
523
667
|
${shell.dialog ? html`<${shell.dialog.Component} ...${shell.dialog.props} onClose=${closeDialog} />` : null}
|
|
524
|
-
${viewOnly || (nav.route && nav.route.panel === "settings") ? null : html`<${PendingChanges} />`}
|
|
668
|
+
${viewOnly || guest || (nav.route && nav.route.panel === "settings") ? null : html`<${PendingChanges} />`}
|
|
525
669
|
<${ConfirmHost} />
|
|
526
670
|
<${ColorDialogHost} />
|
|
527
|
-
${viewOnly ? null : html`<${OwnerCssKeepBar} />`}
|
|
671
|
+
${viewOnly || guest ? null : html`<${OwnerCssKeepBar} />`}
|
|
528
672
|
<${Toasts} />
|
|
529
673
|
</div>`;
|
|
530
674
|
}
|
|
@@ -26,6 +26,20 @@ export function createStore(initial) {
|
|
|
26
26
|
export const appStore = createStore({ ready: false, instances: [], uptime: 0, exec: {}, awaiting: {}, connection: "connecting", needs: [], connections: null,
|
|
27
27
|
hydration: "none", retryHydration: null });
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* #1920 phase 3: this page is a guest's — the server says so on <body> (data-tier="guest"). A guest sees only its own
|
|
31
|
+
* agents' chats: no fleet, Needs you, View, Settings, filters, commands or new agent, and nothing it may not read is asked
|
|
32
|
+
* for (each would be refused). The server checks every request regardless; this only keeps the page to what works.
|
|
33
|
+
*/
|
|
34
|
+
export function guestPage() {
|
|
35
|
+
return typeof document !== "undefined" && !!document.body && document.body.dataset.tier === "guest";
|
|
36
|
+
}
|
|
37
|
+
/** Who a guest's page is signed in as: its web name and its platform (the server's, on <body>). */
|
|
38
|
+
export function guestBadge() {
|
|
39
|
+
const d = typeof document !== "undefined" && document.body ? document.body.dataset : {};
|
|
40
|
+
return { name: d.guestName || "", platform: d.guestPlatform || "" };
|
|
41
|
+
}
|
|
42
|
+
|
|
29
43
|
/** Fold one status frame (stream or poll) into the store. */
|
|
30
44
|
export function applyStatus(d) {
|
|
31
45
|
if (!d || !Array.isArray(d.instances)) return;
|
|
@@ -42,7 +56,18 @@ export function applyStatus(d) {
|
|
|
42
56
|
// #1629: the agents' themes' revision (app-themes.js re-reads them when it moves).
|
|
43
57
|
themesRev: typeof d.themes_rev === "number" ? d.themes_rev : null,
|
|
44
58
|
// #1685: host memory pressure slowing or holding new agents ("elevated" | "critical"), else null.
|
|
45
|
-
hostMemory: d.host_memory === "elevated" || d.host_memory === "critical" ? d.host_memory : null
|
|
59
|
+
hostMemory: d.host_memory === "elevated" || d.host_memory === "critical" ? d.host_memory : null,
|
|
60
|
+
// #2015: while it lasts, the largest processes in the fleet and whose they are (at most 3; anything else dropped).
|
|
61
|
+
hostMemoryTop: hostMemoryTop(d.host_memory_top) });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** #2015: the status frame's host_memory_top, as the dashboard keeps it: well-formed entries only, at most 3. */
|
|
65
|
+
export function hostMemoryTop(raw) {
|
|
66
|
+
if (!Array.isArray(raw)) return [];
|
|
67
|
+
return raw.slice(0, 3).flatMap(p => p && typeof p.name === "string" && Number.isSafeInteger(p.pid) && Number.isSafeInteger(p.rssBytes) && p.rssBytes >= 0
|
|
68
|
+
&& ["fleet", "tmux", "instance", "other"].includes(p.owner)
|
|
69
|
+
? [{ name: p.name.slice(0, 64), pid: p.pid, rssBytes: p.rssBytes, owner: p.owner, ...(p.owner === "instance" && typeof p.instance === "string" ? { instance: p.instance.slice(0, 128) } : {}) }]
|
|
70
|
+
: []);
|
|
46
71
|
}
|
|
47
72
|
|
|
48
73
|
/** One "activity" event: an instance started or stopped working. */
|
|
@@ -30,7 +30,11 @@
|
|
|
30
30
|
// - suspend()/resume(): the page is leaving (pagehide) / came back from the back-forward cache.
|
|
31
31
|
|
|
32
32
|
// #1218: steps_tick — an instance's transcript moved while a Log watches it (SSE only: a poll page asks the Log itself).
|
|
33
|
-
|
|
33
|
+
// #1918: traffic — a message between instances moved; delegation — a task opened, or its report closed it (SSE only: the
|
|
34
|
+
// org canvas reads /ui/traffic when it has no stream).
|
|
35
|
+
// #2233: backend_login — a dashboard sign-in started, moved or ended (no details: the page reads its own view).
|
|
36
|
+
// tasks — the task board changed: the card numbers a write touched (SSE only: the board reads again when it is shown).
|
|
37
|
+
const EVENTS = ["status", "message", "agent_reply_live", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "steps_tick", "clock", "traffic", "delegation", "backend_login", "tasks"];
|
|
34
38
|
const MAX_HELD = 1000; // live events held during one catch-up read; more → read again afterwards
|
|
35
39
|
const RETRY_DELAYS = [1000, 2000, 4000]; // after the first failed catch-up read; then it waits for Retry
|
|
36
40
|
const POLL_LIMIT_MS = 10000; // a poll that has not answered by then counts as failed
|