@songsid/agend 2.3.0-beta.8 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -8
- package/README.zh-TW.md +16 -8
- package/dist/adapter-world.js.map +1 -1
- package/dist/agend-home.d.ts +5 -0
- package/dist/agend-home.js +7 -0
- package/dist/agend-home.js.map +1 -0
- package/dist/agent-cli-instructions.md +9 -2
- package/dist/agent-cli.js +44 -0
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +9 -0
- package/dist/agent-endpoint.js +23 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.js +1 -1
- package/dist/agent-file-read.js.map +1 -1
- package/dist/agent-whats-new.d.ts +16 -0
- package/dist/agent-whats-new.js +54 -11
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/apply-job.js.map +1 -1
- package/dist/atomic-write.js.map +1 -1
- package/dist/auth-api.d.ts +12 -0
- package/dist/auth-api.js +77 -22
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/authority-state.d.ts +4 -0
- package/dist/authority/authority-state.js +17 -8
- package/dist/authority/authority-state.js.map +1 -1
- package/dist/authority/session-authorizations.js.map +1 -1
- package/dist/authority/web-authority.d.ts +16 -8
- package/dist/authority/web-authority.js +19 -5
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/antigravity.d.ts +2 -2
- package/dist/backend/antigravity.js +2 -1
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.js +13 -4
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +8 -0
- package/dist/backend/codex-metadata.js +74 -17
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex-package.d.ts +30 -0
- package/dist/backend/codex-package.js +133 -0
- package/dist/backend/codex-package.js.map +1 -0
- package/dist/backend/codex-session-lookup.js.map +1 -1
- package/dist/backend/codex.d.ts +2 -0
- package/dist/backend/codex.js +25 -5
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +2 -0
- package/dist/backend/credential-profile.js +2 -0
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/effort-metadata.js.map +1 -1
- package/dist/backend/grok.js +58 -3
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro-engine-ledger.js.map +1 -1
- package/dist/backend/kiro-kas-store.js.map +1 -1
- package/dist/backend/kiro-v2-store.js.map +1 -1
- package/dist/backend/kiro-v3-identity.js.map +1 -1
- package/dist/backend/kiro.d.ts +9 -1
- package/dist/backend/kiro.js +102 -1
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/launch-effort.js.map +1 -1
- package/dist/backend/mock.js.map +1 -1
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/opencode-permission.js +1 -1
- package/dist/backend/opencode-permission.js.map +1 -1
- package/dist/backend/opencode.js +2 -1
- package/dist/backend/opencode.js.map +1 -1
- package/dist/backend/session-signals.js.map +1 -1
- package/dist/backend-availability.js.map +1 -1
- package/dist/backend-command.d.ts +2 -0
- package/dist/backend-command.js +3 -1
- package/dist/backend-command.js.map +1 -1
- package/dist/backend-outage.js.map +1 -1
- package/dist/binary-probe.js +1 -1
- package/dist/binary-probe.js.map +1 -1
- package/dist/bug-report-cli.d.ts +30 -0
- package/dist/bug-report-cli.js +139 -0
- package/dist/bug-report-cli.js.map +1 -0
- package/dist/bug-report.d.ts +47 -0
- package/dist/bug-report.js +137 -0
- package/dist/bug-report.js.map +1 -0
- package/dist/bundled-skills.d.ts +18 -0
- package/dist/bundled-skills.js +38 -0
- package/dist/bundled-skills.js.map +1 -0
- package/dist/cache-service.js +1 -1
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
- package/dist/channel/adapters/discord-client-retirement.js +57 -0
- package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +4 -0
- package/dist/channel/adapters/discord.js +57 -12
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +6 -0
- package/dist/channel/adapters/telegram.js +54 -14
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-server.js +21 -4
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +3 -1
- package/dist/channel/mcp-tools.js +43 -6
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/message-queue.js.map +1 -1
- package/dist/channel/sticker-download.js.map +1 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/child-process.d.ts +21 -0
- package/dist/child-process.js +54 -0
- package/dist/child-process.js.map +1 -0
- package/dist/classic-channel-manager.js +3 -2
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli-entry.js.map +1 -1
- package/dist/cli-flags.js.map +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +443 -311
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +1 -1
- package/dist/command-table.js +1 -1
- package/dist/command-table.js.map +1 -1
- package/dist/compact-watch.js.map +1 -1
- package/dist/completion-install.js.map +1 -1
- package/dist/completion.js.map +1 -1
- package/dist/config-validator.d.ts +6 -0
- package/dist/config-validator.js +81 -8
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +15 -3
- package/dist/config.js +41 -10
- package/dist/config.js.map +1 -1
- package/dist/connection-secrets.js.map +1 -1
- package/dist/context-guardian.js.map +1 -1
- package/dist/coredump-filter.js.map +1 -1
- package/dist/cpu-profile.js.map +1 -1
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/cross-instance-notice.d.ts +7 -0
- package/dist/cross-instance-notice.js +10 -0
- package/dist/cross-instance-notice.js.map +1 -1
- package/dist/daemon.d.ts +39 -1
- package/dist/daemon.js +234 -15
- package/dist/daemon.js.map +1 -1
- package/dist/daily-summary.js.map +1 -1
- package/dist/darwin-memory.js +1 -1
- package/dist/darwin-memory.js.map +1 -1
- package/dist/dashboard-live.d.ts +8 -0
- package/dist/dashboard-live.js +35 -0
- package/dist/dashboard-live.js.map +1 -0
- package/dist/dashboard-permissions.d.ts +69 -0
- package/dist/dashboard-permissions.js +138 -0
- package/dist/dashboard-permissions.js.map +1 -0
- package/dist/decision-list.d.ts +25 -0
- package/dist/decision-list.js +30 -0
- package/dist/decision-list.js.map +1 -0
- package/dist/delivery-consumed-watch.js.map +1 -1
- package/dist/delivery-outbox.js +5 -0
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-outbox.test.js.map +1 -1
- package/dist/delivery-reconciliation.test.js.map +1 -1
- package/dist/diagnostic-redaction.d.ts +10 -0
- package/dist/diagnostic-redaction.js +167 -0
- package/dist/diagnostic-redaction.js.map +1 -0
- package/dist/doctor.d.ts +8 -0
- package/dist/doctor.js +52 -0
- package/dist/doctor.js.map +1 -1
- package/dist/e2e-isolation.js.map +1 -1
- package/dist/event-log.js.map +1 -1
- package/dist/export-import.js +7 -5
- package/dist/export-import.js.map +1 -1
- package/dist/fleet-control-audit.js.map +1 -1
- package/dist/fleet-label.js.map +1 -1
- package/dist/fleet-level-config.d.ts +1 -1
- package/dist/fleet-level-config.js +2 -0
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-lock.js +3 -2
- package/dist/fleet-lock.js.map +1 -1
- package/dist/fleet-manager.d.ts +258 -15
- package/dist/fleet-manager.js +1605 -304
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +18 -0
- package/dist/fleet-process-handlers.js +70 -0
- package/dist/fleet-process-handlers.js.map +1 -0
- package/dist/fleet-startup.d.ts +14 -0
- package/dist/fleet-startup.js +30 -0
- package/dist/fleet-startup.js.map +1 -0
- package/dist/fleet-traffic.d.ts +36 -0
- package/dist/fleet-traffic.js +100 -0
- package/dist/fleet-traffic.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +0 -20
- package/dist/forged-envelope-scan.js +3 -2
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/full-restart.d.ts +5 -5
- package/dist/full-restart.js +5 -5
- package/dist/full-restart.js.map +1 -1
- package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +52 -11
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +5 -1
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +3 -1
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
- package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +321 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +28 -4
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +553 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +170 -35
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/general-knowledge/steering/core-rules.md +1 -1
- package/dist/host-memory.js.map +1 -1
- package/dist/idle-gate-log.d.ts +19 -0
- package/dist/idle-gate-log.js +15 -0
- package/dist/idle-gate-log.js.map +1 -0
- package/dist/instance-config-impact.js +25 -4
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +10 -1
- package/dist/instance-lifecycle.js +86 -25
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +12 -6
- package/dist/instructions.js +19 -10
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-compact-pane.js.map +1 -1
- package/dist/kiro-db-reader.js.map +1 -1
- package/dist/kiro-engine-status.js.map +1 -1
- package/dist/kiro-log-gate.js.map +1 -1
- package/dist/kiro-transcript-lane.js.map +1 -1
- package/dist/locale.js +428 -20
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js.map +1 -1
- package/dist/log-steps.d.ts +1 -0
- package/dist/log-steps.js +15 -0
- package/dist/log-steps.js.map +1 -1
- package/dist/logger.js +3 -2
- package/dist/logger.js.map +1 -1
- package/dist/login-controller.d.ts +45 -0
- package/dist/login-controller.js +101 -5
- package/dist/login-controller.js.map +1 -1
- package/dist/login-flows.js +1 -1
- package/dist/login-manager.js.map +1 -1
- package/dist/login-shell.js +3 -1
- package/dist/login-shell.js.map +1 -1
- package/dist/ls-attach-resolve.d.ts +96 -0
- package/dist/ls-attach-resolve.js +180 -0
- package/dist/ls-attach-resolve.js.map +1 -0
- package/dist/ls-rows.d.ts +12 -0
- package/dist/ls-rows.js +83 -4
- package/dist/ls-rows.js.map +1 -1
- package/dist/memory-pressure.js.map +1 -1
- package/dist/muse-usage-relay.js.map +1 -1
- package/dist/needs-you-hub.d.ts +98 -1
- package/dist/needs-you-hub.js +313 -44
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +5 -2
- package/dist/needs-you-live.js +6 -3
- package/dist/needs-you-live.js.map +1 -1
- package/dist/needs-you.d.ts +68 -3
- package/dist/needs-you.js +38 -4
- package/dist/needs-you.js.map +1 -1
- package/dist/network-family.js.map +1 -1
- package/dist/operator-control-paths.js +3 -4
- package/dist/operator-control-paths.js.map +1 -1
- package/dist/outbound-handlers.d.ts +3 -0
- package/dist/outbound-handlers.js +76 -19
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +112 -64
- package/dist/outbound-schemas.js +39 -12
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/outbox-open-error.js.map +1 -1
- package/dist/pane-context-cache.js.map +1 -1
- package/dist/paths.js.map +1 -1
- package/dist/private-dir.js.map +1 -1
- package/dist/probe-worker-pool.js.map +1 -1
- package/dist/profile-control.js.map +1 -1
- package/dist/prompt-file-ref.js.map +1 -1
- package/dist/provider-probe.js.map +1 -1
- package/dist/provider-secret-registry.d.ts +5 -3
- package/dist/provider-secret-registry.js +8 -2
- package/dist/provider-secret-registry.js.map +1 -1
- package/dist/public-link-auto-open.d.ts +32 -0
- package/dist/public-link-auto-open.js +86 -0
- package/dist/public-link-auto-open.js.map +1 -0
- package/dist/public-link-owner.d.ts +10 -0
- package/dist/public-link-owner.js +36 -0
- package/dist/public-link-owner.js.map +1 -0
- package/dist/public-link-progress.d.ts +12 -1
- package/dist/public-link-progress.js +5 -10
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-preview.js.map +1 -1
- package/dist/public-tunnel-config.d.ts +11 -0
- package/dist/public-tunnel-config.js +68 -0
- package/dist/public-tunnel-config.js.map +1 -0
- package/dist/public-web-gateway.d.ts +2 -0
- package/dist/public-web-gateway.js +19 -6
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +48 -3
- package/dist/public-web-link.js +177 -51
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.d.ts +9 -0
- package/dist/quickstart-api.js +82 -0
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +5 -0
- package/dist/quickstart.js +40 -25
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/reply-dedup.js.map +1 -1
- package/dist/resource-report.js +1 -1
- package/dist/resource-report.js.map +1 -1
- package/dist/restart-guard.js.map +1 -1
- package/dist/restart-progress.d.ts +80 -1
- package/dist/restart-progress.js +306 -21
- package/dist/restart-progress.js.map +1 -1
- package/dist/rollout-index.js.map +1 -1
- package/dist/runtime-cpu-profile.js.map +1 -1
- package/dist/scheduler/db.d.ts +40 -13
- package/dist/scheduler/db.js +123 -89
- package/dist/scheduler/db.js.map +1 -1
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/scheduler/task-board-text.d.ts +26 -0
- package/dist/scheduler/task-board-text.js +140 -0
- package/dist/scheduler/task-board-text.js.map +1 -0
- package/dist/scheduler/task-board.d.ts +730 -0
- package/dist/scheduler/task-board.js +2179 -0
- package/dist/scheduler/task-board.js.map +1 -0
- package/dist/scheduler/types.d.ts +6 -1
- package/dist/sd-notify.js +2 -1
- package/dist/sd-notify.js.map +1 -1
- package/dist/search/search-docs.d.ts +58 -0
- package/dist/search/search-docs.js +63 -0
- package/dist/search/search-docs.js.map +1 -0
- package/dist/search/search-index.d.ts +141 -0
- package/dist/search/search-index.js +440 -0
- package/dist/search/search-index.js.map +1 -0
- package/dist/search/search-store.d.ts +122 -0
- package/dist/search/search-store.js +236 -0
- package/dist/search/search-store.js.map +1 -0
- package/dist/search/search-worker.d.ts +1 -0
- package/dist/search/search-worker.js +163 -0
- package/dist/search/search-worker.js.map +1 -0
- package/dist/secret-file.js.map +1 -1
- package/dist/secret-store.d.ts +2 -0
- package/dist/secret-store.js +21 -0
- package/dist/secret-store.js.map +1 -1
- package/dist/service-installer.d.ts +75 -0
- package/dist/service-installer.js +206 -0
- package/dist/service-installer.js.map +1 -1
- package/dist/service-owner.d.ts +44 -0
- package/dist/service-owner.js +48 -0
- package/dist/service-owner.js.map +1 -0
- package/dist/service-plan.d.ts +39 -2
- package/dist/service-plan.js +188 -6
- package/dist/service-plan.js.map +1 -1
- package/dist/session-oom.d.ts +21 -0
- package/dist/session-oom.js +139 -0
- package/dist/session-oom.js.map +1 -0
- package/dist/settings-api.d.ts +13 -0
- package/dist/settings-api.js +73 -12
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-baseline.js.map +1 -1
- package/dist/settings-change.d.ts +5 -0
- package/dist/settings-change.js +167 -6
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +9 -1
- package/dist/settings-confirmation.js +18 -8
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-control.js +2 -1
- package/dist/settings-control.js.map +1 -1
- package/dist/settings-effect.js +29 -4
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +13 -0
- package/dist/settings-http-confirmation.js +15 -3
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/settings-instance-patch.js +13 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/settings-request-capability.d.ts +4 -1
- package/dist/settings-request-capability.js +11 -3
- package/dist/settings-request-capability.js.map +1 -1
- package/dist/settings-transaction.js.map +1 -1
- package/dist/setup-auth.d.ts +1 -0
- package/dist/setup-auth.js +2 -1
- package/dist/setup-auth.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +23 -7
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-host.d.ts +6 -1
- package/dist/setup-host.js +15 -4
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +6 -3
- package/dist/setup-wizard.js.map +1 -1
- package/dist/spawn-gate.d.ts +5 -0
- package/dist/spawn-gate.js +28 -8
- package/dist/spawn-gate.js.map +1 -1
- package/dist/start-attempt.d.ts +1 -0
- package/dist/start-attempt.js +18 -0
- package/dist/start-attempt.js.map +1 -0
- package/dist/start-failure-notice.d.ts +4 -0
- package/dist/start-failure-notice.js +20 -0
- package/dist/start-failure-notice.js.map +1 -0
- package/dist/start-failure.d.ts +147 -0
- package/dist/start-failure.js +281 -0
- package/dist/start-failure.js.map +1 -0
- package/dist/startup-memory-deadline.d.ts +23 -0
- package/dist/startup-memory-deadline.js +55 -0
- package/dist/startup-memory-deadline.js.map +1 -0
- package/dist/statusline-watcher.js.map +1 -1
- package/dist/storm-window.js.map +1 -1
- package/dist/systemd-peer-bus.js.map +1 -1
- package/dist/target-queue-worker.js.map +1 -1
- package/dist/task-board-summary.d.ts +101 -0
- package/dist/task-board-summary.js +177 -0
- package/dist/task-board-summary.js.map +1 -0
- package/dist/task-board-tool.d.ts +25 -0
- package/dist/task-board-tool.js +155 -0
- package/dist/task-board-tool.js.map +1 -0
- package/dist/task-board-waker.d.ts +51 -0
- package/dist/task-board-waker.js +141 -0
- package/dist/task-board-waker.js.map +1 -0
- package/dist/tips.js.map +1 -1
- package/dist/tmux-control.js +1 -1
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-exec-helper.d.ts +104 -0
- package/dist/tmux-exec-helper.js +412 -0
- package/dist/tmux-exec-helper.js.map +1 -0
- package/dist/tmux-manager.d.ts +1 -0
- package/dist/tmux-manager.js +29 -13
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-read.js +2 -2
- package/dist/tmux-read.js.map +1 -1
- package/dist/tool-permissions.js +9 -42
- package/dist/tool-permissions.js.map +1 -1
- package/dist/tool-progress.js.map +1 -1
- package/dist/topic-archiver.js.map +1 -1
- package/dist/topic-commands.d.ts +13 -0
- package/dist/topic-commands.js +56 -33
- package/dist/topic-commands.js.map +1 -1
- package/dist/topic-link.js.map +1 -1
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/transcript-jsonl.js.map +1 -1
- package/dist/transcript-monitor.js +5 -0
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +2 -0
- package/dist/transcript-sources.js +4 -0
- package/dist/transcript-sources.js.map +1 -1
- package/dist/tunnel/cloudflared-install.js +3 -1
- package/dist/tunnel/cloudflared-install.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +7 -16
- package/dist/tunnel/cloudflared.js +100 -13
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/lease.js +3 -2
- package/dist/tunnel/lease.js.map +1 -1
- package/dist/tunnel/manager.js.map +1 -1
- package/dist/tunnel/named-diagnostics.d.ts +13 -0
- package/dist/tunnel/named-diagnostics.js +52 -0
- package/dist/tunnel/named-diagnostics.js.map +1 -0
- package/dist/tunnel/public-fetch.js.map +1 -1
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/tunnel/types.d.ts +4 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/types.d.ts +55 -2
- package/dist/ui/app-effects.js +27 -5
- package/dist/ui/app.html +2 -0
- package/dist/ui/backend-signin.js +297 -0
- package/dist/ui/chat-effects.js +15 -7
- package/dist/ui/chat-msg-actions.js +176 -0
- package/dist/ui/chat-render.js +67 -20
- package/dist/ui/chat-store.js +218 -48
- package/dist/ui/chat-strings.js +42 -10
- package/dist/ui/chat-thread.js +249 -23
- package/dist/ui/effect-trial-controller.js +13 -8
- package/dist/ui/effect-trial-offer.js +2 -31
- package/dist/ui/effects-waker.js +2 -0
- package/dist/ui/fleet-canvas-layout.js +13 -4
- package/dist/ui/fleet-canvas.js +120 -43
- package/dist/ui/fleet-office-editor.js +149 -0
- package/dist/ui/fleet-office-model.js +358 -0
- package/dist/ui/fleet-office-pack.js +199 -0
- package/dist/ui/fleet-office-skin.js +474 -0
- package/dist/ui/fleet-office-store.js +49 -0
- package/dist/ui/fleet-office-zones.js +177 -0
- package/dist/ui/fleet-office.js +434 -0
- package/dist/ui/fleet-org.js +21 -8
- package/dist/ui/fleet-route-scene.js +272 -0
- package/dist/ui/fleet-route-worker.js +21 -0
- package/dist/ui/fleet-route.js +88 -0
- package/dist/ui/fleet-task-card.js +436 -0
- package/dist/ui/fleet-task-common.js +482 -0
- package/dist/ui/fleet-task-work.js +107 -0
- package/dist/ui/fleet-tasks.js +569 -0
- package/dist/ui/fleet-traffic.js +227 -45
- package/dist/ui/fleet-usage.js +36 -2
- package/dist/ui/guest-refused.html +41 -0
- package/dist/ui/icons/icon-192.png +0 -0
- package/dist/ui/icons/icon-512.png +0 -0
- package/dist/ui/image-lightbox.js +45 -1
- package/dist/ui/image-zoom.js +242 -0
- package/dist/ui/panel-chat.js +282 -89
- package/dist/ui/panel-details.js +2 -0
- package/dist/ui/panel-fleet.js +32 -71
- package/dist/ui/panel-needs.js +23 -6
- package/dist/ui/panel-settings.js +158 -32
- package/dist/ui/preview-panel.js +2 -1
- package/dist/ui/search-dialog.js +350 -0
- package/dist/ui/settings-appearance.js +170 -10
- package/dist/ui/settings-apply.js +3 -3
- package/dist/ui/settings-confirm.js +7 -2
- package/dist/ui/settings-dialogs.js +46 -21
- package/dist/ui/settings-discord.js +6 -2
- package/dist/ui/settings-guests.js +2 -1
- package/dist/ui/settings-learn.js +1 -0
- package/dist/ui/settings-model.js +51 -18
- package/dist/ui/settings-mods.js +8 -3
- package/dist/ui/settings-owner-effects.js +6 -4
- package/dist/ui/settings-strings.js +180 -6
- package/dist/ui/settings-token.js +3 -1
- package/dist/ui/settings-web-authority.js +13 -5
- package/dist/ui/settings-wizard.js +13 -7
- package/dist/ui/shared/agend-auth.js +3 -1
- package/dist/ui/shared/app-i18n.js +12 -5
- package/dist/ui/shared/app-needs.js +2 -2
- package/dist/ui/shared/app-prefs.js +15 -0
- package/dist/ui/shared/app-route.js +18 -0
- package/dist/ui/shared/app-shell.js +172 -28
- package/dist/ui/shared/app-store.js +3 -2
- package/dist/ui/shared/app-stream.js +7 -2
- package/dist/ui/shared/app-themes.js +116 -1
- package/dist/ui/shared/app.css +681 -54
- package/dist/ui/shared/app.js +9 -1
- package/dist/ui/shared/card-strings.js +4 -0
- package/dist/ui/shared/effect-app-runtime.js +7 -5
- package/dist/ui/shared/effect-chat-runtime.js +2 -7
- package/dist/ui/shared/effect-cursor.js +3 -2
- package/dist/ui/shared/effect-display-metadata.js +39 -0
- package/dist/ui/shared/effect-owner-source.js +8 -1
- package/dist/ui/shared/effect-policy.js +2 -2
- package/dist/ui/shared/effect-registry.js +30 -11
- package/dist/ui/shared/effect-runtime-loader.js +3 -1
- package/dist/ui/shared/effect-stock-snapshot.js +9 -0
- package/dist/ui/shared/effect-stock-trust.js +40 -9
- package/dist/ui/shared/effect-trial-source.js +1 -1
- package/dist/ui/shared/effect-trial-stage.js +27 -21
- package/dist/ui/shared/effect-trial.css +1 -1
- package/dist/ui/shared/feature-flags.js +127 -0
- package/dist/ui/shared/guest-refused.js +35 -0
- package/dist/ui/shared/header-tools.js +2 -2
- package/dist/ui/shared/identity-card.js +26 -8
- package/dist/ui/shared/identity-color.js +17 -10
- package/dist/ui/shared/instance-nav.js +183 -28
- package/dist/ui/shared/owner-css.js +30 -1
- package/dist/ui/shared/panel-view.js +14 -29
- package/dist/ui/shared/text-undo.js +210 -0
- package/dist/ui/shared/tokens.css +13 -3
- package/dist/ui/shared/ui-dialog.js +5 -4
- package/dist/ui/shared/ui-icons.js +4 -0
- package/dist/ui/shared/ui-menu.js +20 -7
- package/dist/ui/shared/ui-toast.js +16 -3
- package/dist/ui/shared/usage-dialog.js +206 -16
- package/dist/ui/shared/view-strings.js +68 -4
- package/dist/ui/shared/web-authorize.js +50 -1
- package/dist/ui/signin.html +2 -0
- package/dist/ui/web-terminal/terminal.css +4 -4
- package/dist/ui/web-terminal/terminal.html +10 -10
- package/dist/ui/web-terminal/terminal.js +58 -12
- package/dist/update-check.js.map +1 -1
- package/dist/update-dispatch.js +1 -1
- package/dist/update-dispatch.js.map +1 -1
- package/dist/update-install.js.map +1 -1
- package/dist/update-launch.d.ts +10 -1
- package/dist/update-launch.js +39 -14
- package/dist/update-launch.js.map +1 -1
- package/dist/update-marker.js.map +1 -1
- package/dist/update-preflight.js +1 -1
- package/dist/update-preflight.js.map +1 -1
- package/dist/update-progress.d.ts +3 -1
- package/dist/update-progress.js +3 -1
- package/dist/update-progress.js.map +1 -1
- package/dist/usage/format-rich.js +6 -3
- package/dist/usage/format-rich.js.map +1 -1
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +2 -1
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/i18n.d.ts +13 -1
- package/dist/usage/i18n.js +29 -0
- package/dist/usage/i18n.js.map +1 -1
- package/dist/usage/providers.d.ts +89 -2
- package/dist/usage/providers.js +247 -41
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/statusline-usage.js.map +1 -1
- package/dist/usage/usage-api.d.ts +5 -1
- package/dist/usage/usage-api.js +185 -58
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/usage-report.js.map +1 -1
- package/dist/usage-rollup.js +1 -1
- package/dist/usage-rollup.js.map +1 -1
- package/dist/user-systemd.d.ts +24 -0
- package/dist/user-systemd.js +75 -0
- package/dist/user-systemd.js.map +1 -0
- package/dist/view-api.d.ts +7 -0
- package/dist/view-api.js +16 -4
- package/dist/view-api.js.map +1 -1
- package/dist/wake-coordinator.js.map +1 -1
- package/dist/web-ambient.js +9 -2
- package/dist/web-ambient.js.map +1 -1
- package/dist/web-api.d.ts +58 -10
- package/dist/web-api.js +1104 -71
- package/dist/web-api.js.map +1 -1
- package/dist/web-app-icon-worker.d.ts +1 -0
- package/dist/web-app-icon-worker.js +16 -0
- package/dist/web-app-icon-worker.js.map +1 -0
- package/dist/web-app-icon.d.ts +109 -0
- package/dist/web-app-icon.js +257 -0
- package/dist/web-app-icon.js.map +1 -0
- package/dist/web-appearance-policy.js.map +1 -1
- package/dist/web-appearance-tools.d.ts +1 -0
- package/dist/web-appearance-tools.js +7 -3
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-appearance.d.ts +4 -10
- package/dist/web-appearance.js +7 -4
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-auth.d.ts +8 -4
- package/dist/web-auth.js +33 -21
- package/dist/web-auth.js.map +1 -1
- package/dist/web-backend-login.d.ts +130 -0
- package/dist/web-backend-login.js +225 -0
- package/dist/web-backend-login.js.map +1 -0
- package/dist/web-card.js.map +1 -1
- package/dist/web-channel-echo.js.map +1 -1
- package/dist/web-chat-history.d.ts +118 -8
- package/dist/web-chat-history.js +220 -25
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +5 -1
- package/dist/web-commands.js +1 -1
- package/dist/web-commands.js.map +1 -1
- package/dist/web-cookie-names.d.ts +5 -0
- package/dist/web-cookie-names.js +12 -0
- package/dist/web-cookie-names.js.map +1 -0
- package/dist/web-effect-bundle.d.ts +2 -2
- package/dist/web-effect-library.js.map +1 -1
- package/dist/web-effect-playback.js.map +1 -1
- package/dist/web-effect-profiles.d.ts +16 -16
- package/dist/web-effect-profiles.js +3 -2
- package/dist/web-effect-profiles.js.map +1 -1
- package/dist/web-effect-service.js.map +1 -1
- package/dist/web-effect-tools.js.map +1 -1
- package/dist/web-effect-trials.js.map +1 -1
- package/dist/web-effect-upload.js.map +1 -1
- package/dist/web-effect.d.ts +6 -6
- package/dist/web-effect.js.map +1 -1
- package/dist/web-experimental-http.d.ts +2 -0
- package/dist/web-experimental-http.js +12 -0
- package/dist/web-experimental-http.js.map +1 -0
- package/dist/web-experimental.d.ts +11 -0
- package/dist/web-experimental.js +49 -0
- package/dist/web-experimental.js.map +1 -0
- package/dist/web-guest-access.d.ts +4 -2
- package/dist/web-guest-access.js +22 -10
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-guest-rooms.js.map +1 -1
- package/dist/web-host-guard.d.ts +11 -0
- package/dist/web-host-guard.js +11 -0
- package/dist/web-host-guard.js.map +1 -1
- package/dist/web-icons.d.ts +33 -1
- package/dist/web-icons.js +83 -11
- package/dist/web-icons.js.map +1 -1
- package/dist/web-identity-color.js.map +1 -1
- package/dist/web-image-meta.d.ts +13 -0
- package/dist/web-image-meta.js +62 -0
- package/dist/web-image-meta.js.map +1 -1
- package/dist/web-images.js.map +1 -1
- package/dist/web-libavoid.d.ts +14 -0
- package/dist/web-libavoid.js +46 -0
- package/dist/web-libavoid.js.map +1 -0
- package/dist/web-login.js.map +1 -1
- package/dist/web-mentions.js.map +1 -1
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-mod-store.d.ts +2 -0
- package/dist/web-mod-store.js +10 -0
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-office-store.d.ts +104 -0
- package/dist/web-office-store.js +236 -0
- package/dist/web-office-store.js.map +1 -0
- package/dist/web-owner-css-store.d.ts +44 -1
- package/dist/web-owner-css-store.js +70 -9
- package/dist/web-owner-css-store.js.map +1 -1
- package/dist/web-owner-css.js.map +1 -1
- package/dist/web-png.d.ts +33 -0
- package/dist/web-png.js +329 -0
- package/dist/web-png.js.map +1 -0
- package/dist/web-prefs.d.ts +6 -0
- package/dist/web-prefs.js +29 -3
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +2 -0
- package/dist/web-preview.js +2 -0
- package/dist/web-preview.js.map +1 -1
- package/dist/web-profile.js.map +1 -1
- package/dist/web-reactions.d.ts +35 -0
- package/dist/web-reactions.js +47 -0
- package/dist/web-reactions.js.map +1 -0
- package/dist/web-request-context.d.ts +5 -0
- package/dist/web-request-context.js.map +1 -1
- package/dist/web-returning-device.d.ts +4 -2
- package/dist/web-returning-device.js +13 -6
- package/dist/web-returning-device.js.map +1 -1
- package/dist/web-schedules.js.map +1 -1
- package/dist/web-send-dedupe.d.ts +36 -0
- package/dist/web-send-dedupe.js +69 -0
- package/dist/web-send-dedupe.js.map +1 -0
- package/dist/web-session-authorization.js.map +1 -1
- package/dist/web-session.js +1 -1
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +3 -1
- package/dist/web-settings-patch.js +11 -5
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +6 -0
- package/dist/web-settings-tools.js +52 -17
- package/dist/web-settings-tools.js.map +1 -1
- package/dist/web-terminal-http.js +15 -2
- package/dist/web-terminal-http.js.map +1 -1
- package/dist/web-terminal.js +1 -1
- package/dist/web-terminal.js.map +1 -1
- package/dist/web-theme-store.d.ts +2 -2
- package/dist/web-theme-store.js +6 -3
- package/dist/web-theme-store.js.map +1 -1
- package/dist/web-theme.d.ts +29 -0
- package/dist/web-theme.js +89 -1
- package/dist/web-theme.js.map +1 -1
- package/dist/web-upload.d.ts +18 -1
- package/dist/web-upload.js +45 -7
- package/dist/web-upload.js.map +1 -1
- package/dist/web-widget.js.map +1 -1
- package/dist/webhook-emitter.js.map +1 -1
- package/dist/windows-shortcuts.d.ts +78 -0
- package/dist/windows-shortcuts.js +203 -0
- package/dist/windows-shortcuts.js.map +1 -0
- package/dist/workflow-templates/default.md +4 -1
- package/dist/ws-server.js.map +1 -1
- package/dist/yaml-shared-nodes.d.ts +25 -0
- package/dist/yaml-shared-nodes.js +185 -0
- package/dist/yaml-shared-nodes.js.map +1 -0
- package/launcher/agend-install.cjs +828 -0
- package/launcher/install-admission.cjs +4 -39
- package/launcher/postinstall.cjs +14 -12
- package/launcher/private-home.cjs +43 -0
- package/package.json +16 -13
- package/scripts/preinstall-guard.cjs +2 -5
- package/templates/windows-shortcuts.ps1 +181 -0
- package/launcher/old-updater-note.cjs +0 -48
|
@@ -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).
|
|
@@ -42,7 +43,10 @@ export const SYNCED = {
|
|
|
42
43
|
"widget.sidebar": { ls: "agend_widget_sidebar", ...json },
|
|
43
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) },
|
|
48
|
+
// The AI usage view's compact mode: one line per login (usage-dialog.js), in the dialog and the rail alike.
|
|
49
|
+
"usage.compact": { ls: "agend_usage_compact", toLocal: (v) => (v === true ? "on" : null), fromLocal: (s) => (s === "on" ? true : undefined) },
|
|
46
50
|
};
|
|
47
51
|
// #1629: fixed personal scope. A separate session-bound owner-effect store synchronizes these, never this host cache.
|
|
48
52
|
export const OWNER_EFFECT_PREF_KEYS = Object.freeze(["fx.sidebar", "fx.header", "fx.page", "fx.box", "fx.cursor"]);
|
|
@@ -77,6 +81,15 @@ const inflight = new Map(); // key → writes sent and not answered yet
|
|
|
77
81
|
let flushTimer = null;
|
|
78
82
|
let writes = Promise.resolve(); // one write at a time, in the order they were made
|
|
79
83
|
const listeners = new Set();
|
|
84
|
+
// #2193: whether the signed-in person has a personal effect slot chosen (their fx.* keys: in the page's data-prefs and
|
|
85
|
+
// in every host read, never in this host cache). The effects runtime is loaded only when there is something to play.
|
|
86
|
+
const ownerEffectsIn = (values) => !!values && OWNER_EFFECT_PREF_KEYS.some((k) => own(values, k) && values[k] != null && values[k] !== "");
|
|
87
|
+
let ownerFx = initial ? ownerEffectsIn(initial.values) : false;
|
|
88
|
+
const ownerFxListeners = new Set();
|
|
89
|
+
/** Whether the person has any personal effect (fx.page/header/sidebar/box/cursor) chosen, as this page last read. */
|
|
90
|
+
export function ownerEffectsChosen() { return ownerFx; }
|
|
91
|
+
/** Called when that changes. Returns the unsubscribe. */
|
|
92
|
+
export function onOwnerEffectsChanged(fn) { ownerFxListeners.add(fn); return () => ownerFxListeners.delete(fn); }
|
|
80
93
|
|
|
81
94
|
// The host's values into the cache, now — before the sidebar, the tour or the first-run card read their keys. A key
|
|
82
95
|
// the host does not have: the default, on a device in step with the host; this device's own (to upload) otherwise.
|
|
@@ -117,6 +130,8 @@ function take(body) {
|
|
|
117
130
|
if (!isView(body) || (rev !== null && body.rev < rev)) return false;
|
|
118
131
|
rev = body.rev;
|
|
119
132
|
host = hostValues(body.values);
|
|
133
|
+
const fx = ownerEffectsIn(body.values);
|
|
134
|
+
if (fx !== ownerFx) { ownerFx = fx; for (const fn of [...ownerFxListeners]) { try { fn(fx); } catch { /* the rest still hear */ } } }
|
|
120
135
|
return true;
|
|
121
136
|
}
|
|
122
137
|
|
|
@@ -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) {
|
|
@@ -9,9 +9,11 @@ import { ColorDialogHost } from "./identity-color.js";
|
|
|
9
9
|
import { t, lang, setLang, onLang } from "./app-i18n.js";
|
|
10
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,
|
|
@@ -62,6 +64,45 @@ export function useCanCreate() {
|
|
|
62
64
|
export function showDialog(Component, props = {}) { shellStore.set({ dialog: { Component, props } }); }
|
|
63
65
|
export function closeDialog() { shellStore.set({ dialog: null }); }
|
|
64
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. A guest's never. #2478 (the user's request): over the public link
|
|
74
|
+
* too, unless the fleet keeps it off there (web.search.public_link: false — the page says data-search-link="0", the
|
|
75
|
+
* server refuses it), so then no entry, no shortcut, and Ctrl+F stays the browser's.
|
|
76
|
+
*/
|
|
77
|
+
export function searchOffered(admin) {
|
|
78
|
+
const body = typeof document !== "undefined" ? document.body : null;
|
|
79
|
+
const offLink = !!body && body.dataset.publicLink === "1" && body.dataset.searchLink === "0";
|
|
80
|
+
return !!admin && !guestPage() && !offLink;
|
|
81
|
+
}
|
|
82
|
+
let searchModule = null;
|
|
83
|
+
/** Open search; `preset.instance`: narrowed to that agent (Ctrl+F in its chat). */
|
|
84
|
+
export function openSearch(preset = {}) {
|
|
85
|
+
closeDrawer();
|
|
86
|
+
(searchModule ??= import("/ui/js/search-dialog.js")).then(
|
|
87
|
+
(m) => showDialog(m.SearchDialog, { preset }),
|
|
88
|
+
() => { searchModule = null; toast(t("app.loadFailed"), false); });
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Ctrl+K (⌘K) anywhere opens search; Ctrl+F (⌘F) in an agent's chat opens it narrowed to that agent — elsewhere the
|
|
92
|
+
* browser's own find stays. Not while another dialog is open (search, open already, has its input focused).
|
|
93
|
+
*/
|
|
94
|
+
export function handleSearchKey(e) {
|
|
95
|
+
if (!searchOffered(true)) return;
|
|
96
|
+
if (e.isComposing || e.altKey || e.shiftKey || !(isMacLike() ? e.metaKey : e.ctrlKey)) return;
|
|
97
|
+
const key = (e.key || "").toLowerCase();
|
|
98
|
+
if (key !== "k" && key !== "f") return;
|
|
99
|
+
if (typeof document !== "undefined" && document.querySelector("dialog[open]")) return;
|
|
100
|
+
const route = navStore.get().route;
|
|
101
|
+
if (key === "f" && !(route && route.panel === "chat" && route.instance)) return;
|
|
102
|
+
e.preventDefault();
|
|
103
|
+
openSearch(key === "f" ? { instance: route.instance } : {});
|
|
104
|
+
}
|
|
105
|
+
|
|
65
106
|
function readCollapsed() { try { return localStorage.getItem("agend_sidebar") === "hidden"; } catch { return false; } }
|
|
66
107
|
const narrow = () => typeof matchMedia === "function" && matchMedia("(max-width: 899px)").matches;
|
|
67
108
|
|
|
@@ -245,6 +286,8 @@ appStore.subscribe((s) => {
|
|
|
245
286
|
|
|
246
287
|
function statusLabel(i, exec, awaiting) {
|
|
247
288
|
if (awaiting != null) return t("app.needsYou");
|
|
289
|
+
if (i.startup_phase === "queued") return t("app.statusQueued");
|
|
290
|
+
if (i.startup_phase === "starting") return t("app.statusStarting");
|
|
248
291
|
if (i.status !== "running") return i.status === "crashed" ? t("app.statusCrashed") : t("app.statusStopped");
|
|
249
292
|
if (exec === "working") return t("app.statusWorking");
|
|
250
293
|
if (exec === "stuck") return t("app.statusStuck");
|
|
@@ -252,6 +295,8 @@ function statusLabel(i, exec, awaiting) {
|
|
|
252
295
|
}
|
|
253
296
|
export function statusClass(i, exec, awaiting) {
|
|
254
297
|
if (awaiting != null) return "warn";
|
|
298
|
+
if (i?.startup_phase === "starting") return "busy";
|
|
299
|
+
if (i?.startup_phase === "queued") return "off";
|
|
255
300
|
if (!i || i.status !== "running") return i && i.status === "crashed" ? "bad" : "off";
|
|
256
301
|
return exec === "working" ? "busy" : exec === "stuck" ? "warn" : "ok";
|
|
257
302
|
}
|
|
@@ -267,9 +312,7 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
|
|
|
267
312
|
const app = useStore(appStore);
|
|
268
313
|
const shell = useStore(shellStore);
|
|
269
314
|
const canCreate = useCanCreate();
|
|
270
|
-
|
|
271
|
-
const on = (panel) => !!route && (panel === "fleet" ? route.panel === "details" : route.panel === panel);
|
|
272
|
-
const openInstance = openInstanceOf(route);
|
|
315
|
+
const on = (panel) => !!route && route.panel === panel;
|
|
273
316
|
// A count badge is hidden at 0; its number is also in the link's accessible name.
|
|
274
317
|
const navLink = (panel, href, icon, label, count = 0) => html`<a class=${`side-row${on(panel) ? " active" : ""}`} href=${href}
|
|
275
318
|
aria-current=${on(panel) ? "page" : undefined} aria-label=${count ? `${label} (${t("app.needsCount", count)})` : undefined} onClick=${closeDrawer}>
|
|
@@ -307,10 +350,11 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
|
|
|
307
350
|
<${SidebarResize} />
|
|
308
351
|
</aside>`;
|
|
309
352
|
}
|
|
310
|
-
// #1675: the whole fleet,
|
|
311
|
-
// "Fleet"
|
|
353
|
+
// #1675: the whole fleet, from anywhere — top left, so at the top of a phone's drawer too. #2183 (the user's call): the
|
|
354
|
+
// one Fleet entry ("Fleet" / "Fleet 概覽"), on the tab this device used last (the Org chart the first time); an agent's
|
|
355
|
+
// View, Log and Details are its header's tabs, so the sidebar has no "Fleet" (Details) or "View" row of its own.
|
|
312
356
|
const onFleet = !!route && route.panel === "fleet";
|
|
313
|
-
const overview = html`<a class=${`side-row side-overview${onFleet ? " active" : ""}`} href=${
|
|
357
|
+
const overview = html`<a class=${`side-row side-overview${onFleet ? " active" : ""}`} href=${fleetEntryPath(route)}
|
|
314
358
|
aria-current=${onFleet ? "page" : undefined} onClick=${closeDrawer}><${Icon} name="org" /><span class="grow">${t("app.fleetOverview")}</span></a>`;
|
|
315
359
|
return html`<aside id="sidebar" class="sidebar" aria-label=${t("app.menu")}>
|
|
316
360
|
<div class="side-head" data-trust="navigation">
|
|
@@ -320,8 +364,8 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
|
|
|
320
364
|
<nav data-trust="navigation" class="side-nav" aria-label=${t("app.menu")}>
|
|
321
365
|
${overview}
|
|
322
366
|
${navLink("needs", NEEDS_PATH, "inbox", t("app.needsNav"), needsCount)}
|
|
323
|
-
${
|
|
324
|
-
|
|
367
|
+
${searchOffered(canCreate) ? html`<button type="button" class="side-row side-search" onClick=${() => openSearch()} title=${t("app.searchTitle", searchShortcut())}
|
|
368
|
+
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}
|
|
325
369
|
${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}
|
|
326
370
|
</nav>
|
|
327
371
|
${shell.side ? html`<${shell.side.Component} />` : html`<${InstanceNav} route=${route} items=${app.instances} loaded=${app.ready !== false}
|
|
@@ -396,11 +440,13 @@ function PrefsPopover() {
|
|
|
396
440
|
*/
|
|
397
441
|
export function PanelHeader({ title, sub, children, headingRef, nav, notice }) {
|
|
398
442
|
const shell = useStore(shellStore);
|
|
399
|
-
const
|
|
443
|
+
const admin = useCanCreate();
|
|
444
|
+
const canCreate = admin && !!newInstanceOpener;
|
|
400
445
|
return html`<header data-trust="header" class=${`panel-head${shell.collapsed ? " collapsed" : ""}`}>
|
|
401
446
|
<button type="button" id="sbOpen" class="icon-btn sb-open" onClick=${() => (narrow() ? openDrawer() : toggleSidebar())}
|
|
402
447
|
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>
|
|
403
448
|
${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}
|
|
449
|
+
${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}
|
|
404
450
|
<div class="panel-title"><h1 ref=${headingRef} tabindex="-1">${title}</h1>${sub ? html`<div class="panel-sub">${sub}</div>` : null}</div>
|
|
405
451
|
${nav || null}
|
|
406
452
|
<div class="panel-actions">${children}</div>
|
|
@@ -409,8 +455,8 @@ export function PanelHeader({ title, sub, children, headingRef, nav, notice }) {
|
|
|
409
455
|
}
|
|
410
456
|
|
|
411
457
|
/**
|
|
412
|
-
* #1523 N2: the instance a page is about — Chat, View, Log (#1218) or Details of it — or null.
|
|
413
|
-
*
|
|
458
|
+
* #1523 N2: the instance a page is about — Chat, View, Log (#1218) or Details of it — or null. #2183: with one open, the
|
|
459
|
+
* phone's Chat tab is current and goes to its chat.
|
|
414
460
|
*/
|
|
415
461
|
export function openInstanceOf(route) {
|
|
416
462
|
return route && (route.panel === "chat" || route.panel === "view" || route.panel === "log" || route.panel === "details") && route.instance ? route.instance : null;
|
|
@@ -421,14 +467,15 @@ function BottomTabs({ route, viewOnly }) {
|
|
|
421
467
|
let last = null;
|
|
422
468
|
try { last = localStorage.getItem("agend_last_instance"); } catch { /* none */ }
|
|
423
469
|
const open = openInstanceOf(route);
|
|
424
|
-
|
|
470
|
+
// #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.
|
|
471
|
+
const chatHref = open ? chatPath(open) : last ? chatPath(last) : "/ui";
|
|
425
472
|
const anyAwaiting = Object.keys(app.awaiting).length;
|
|
426
473
|
const tab = (href, icon, label, active, badge, badgeLabel) => html`<a class=${`tab${active ? " active" : ""}`} href=${href} aria-current=${active ? "page" : undefined}>
|
|
427
474
|
<${Icon} name=${icon} size=${20} /><span>${label}</span>${badge ? html`<span class="tab-badge" aria-label=${badgeLabel || t("app.needsYou")}>${badge}</span>` : null}</a>`;
|
|
428
|
-
let lastView = null;
|
|
429
|
-
try { lastView = localStorage.getItem("agend_last_view"); } catch { /* none */ }
|
|
430
|
-
const viewHref = route && (route.panel === "view" || route.panel === "log" || route.panel === "details") && route.instance ? viewPath(route.instance) : viewPath(lastView);
|
|
431
475
|
if (viewOnly) {
|
|
476
|
+
let lastView = null;
|
|
477
|
+
try { lastView = localStorage.getItem("agend_last_view"); } catch { /* none */ }
|
|
478
|
+
const viewHref = route && route.panel === "view" && route.instance ? viewPath(route.instance) : viewPath(lastView);
|
|
432
479
|
return html`<nav data-trust="navigation" class="tabs" aria-label=${t("app.menu")}>
|
|
433
480
|
${tab(viewHref, "view", t("app.view"), route && route.panel === "view")}
|
|
434
481
|
${tab(signInHref(), "user", t("app.signIn"), false)}
|
|
@@ -436,11 +483,12 @@ function BottomTabs({ route, viewOnly }) {
|
|
|
436
483
|
}
|
|
437
484
|
// #1920: a guest has only its chats (the drawer lists them): no tabs to switch between.
|
|
438
485
|
if (guestPage()) return null;
|
|
486
|
+
// #2183 (the user's call): four tabs — Chat (current on /ui and on any of an agent's pages), Needs you, Fleet (on its
|
|
487
|
+
// last tab), Settings.
|
|
439
488
|
return html`<nav data-trust="navigation" class="tabs" aria-label=${t("app.menu")}>
|
|
440
|
-
${tab(chatHref, "chat", t("app.chat"), route && route.panel === "chat", anyAwaiting)}
|
|
489
|
+
${tab(chatHref, "chat", t("app.chat"), !!open || (!!route && route.panel === "chat"), anyAwaiting)}
|
|
441
490
|
${tab(NEEDS_PATH, "inbox", t("app.needsTab"), route && route.panel === "needs", (app.needs || []).length, t("app.needsCount", (app.needs || []).length))}
|
|
442
|
-
${tab(
|
|
443
|
-
${tab(viewHref, "view", t("app.view"), route && route.panel === "view")}
|
|
491
|
+
${tab(fleetEntryPath(route), "fleet", t("app.fleet"), route && route.panel === "fleet")}
|
|
444
492
|
${tab(settingsPath(), "settings", t("app.settings"), route && route.panel === "settings")}
|
|
445
493
|
</nav>`;
|
|
446
494
|
}
|
|
@@ -458,6 +506,13 @@ function ConnectionLine() {
|
|
|
458
506
|
// (agend-auth's banner says that) draw nothing either; only reconnecting and a failed catch-up are shown.
|
|
459
507
|
return null;
|
|
460
508
|
}
|
|
509
|
+
|
|
510
|
+
/** A connected fleet is still bringing up agents; this is distinct from the reconnect banner. */
|
|
511
|
+
export function StartupLine() {
|
|
512
|
+
const { startup } = useStore(appStore);
|
|
513
|
+
if (!startup) return null;
|
|
514
|
+
return html`<div data-trust="status" class="conn fleet-starting" role="status">${t("app.fleetStarting", startup.ready, startup.total)}</div>`;
|
|
515
|
+
}
|
|
461
516
|
/** #1580: the fleet is not answering (a restart): said, with when the next try is — never a silent stale page. */
|
|
462
517
|
function Reconnecting() {
|
|
463
518
|
const { retryAt } = useStore(appStore);
|
|
@@ -487,8 +542,21 @@ export function PendingChanges({ inline = false } = {}) {
|
|
|
487
542
|
const { pendingChanges } = useStore(appStore);
|
|
488
543
|
const list = pendingChanges || [];
|
|
489
544
|
useTick(list.some(p => p.state === "pending"));
|
|
545
|
+
// #2168: inline (Settings' own column), a request that has just started waiting is brought into view — on a phone the
|
|
546
|
+
// person applied far down the list, and the card that says where to confirm it sat above the screen. Once per request.
|
|
547
|
+
const box = useRef(null), shown = useRef(new Set());
|
|
548
|
+
useEffect(() => {
|
|
549
|
+
if (!inline || !box.current) return;
|
|
550
|
+
for (const p of list) {
|
|
551
|
+
if (p.state !== "pending" || shown.current.has(p.id)) continue;
|
|
552
|
+
shown.current.add(p.id);
|
|
553
|
+
const card = box.current.querySelector(`[data-pending="${p.id}"]`);
|
|
554
|
+
const still = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
555
|
+
if (card && typeof card.scrollIntoView === "function") card.scrollIntoView({ block: "nearest", behavior: still ? "auto" : "smooth" });
|
|
556
|
+
}
|
|
557
|
+
});
|
|
490
558
|
if (!list.length) return null;
|
|
491
|
-
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">
|
|
559
|
+
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">
|
|
492
560
|
<div class="pending-head"><${Icon} name=${p.state === "applied" ? "check" : p.state === "pending" || p.state === "applying" ? "clock" : "alert"} size=${16} />
|
|
493
561
|
<strong>${t(`app.pending_${p.state}`)}</strong>
|
|
494
562
|
${p.state === "pending" ? html`<span class="pending-left">${t("app.pendingLeft", mmss(p.deadline - NOW()))}</span>` : null}
|
|
@@ -496,6 +564,7 @@ export function PendingChanges({ inline = false } = {}) {
|
|
|
496
564
|
${p.label ? html`<div class="pending-label">${p.label}</div>` : null}
|
|
497
565
|
${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}
|
|
498
566
|
${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}
|
|
567
|
+
${(p.state === "applying" || p.state === "applied") && p.confirmation && p.confirmation.kind === "web" ? html`<p class="note">${t("app.pendingWeb")}</p>` : null}
|
|
499
568
|
${p.state !== "pending" && p.state !== "applying" && p.state !== "applied" && p.outcome && p.outcome.message ? html`<p class="note">${p.outcome.message}</p>` : null}
|
|
500
569
|
${p.withdraw ? html`<div class="pending-actions"><button type="button" class="btn btn-sm" onClick=${p.withdraw}>${t("app.withdraw")}</button></div>` : null}
|
|
501
570
|
</section>`)}</div>`;
|
|
@@ -545,30 +614,105 @@ function Outlet({ route, seq, panels }) {
|
|
|
545
614
|
return html`<${C} route=${route} navKey=${`${routeKey(route)}|${seq}|${lang()}`} />`;
|
|
546
615
|
}
|
|
547
616
|
|
|
617
|
+
/**
|
|
618
|
+
* #2196: the open agent's colours on the whole page (its theme's page section, or a person's choice), drawn on the
|
|
619
|
+
* shell in the same render that opens it — no fetch (the themes are on the page already), no flash, colours only, so
|
|
620
|
+
* no layout moves. Redrawn when the themes, the person's choices, the viewer's switch or the light/dark mode move.
|
|
621
|
+
*/
|
|
622
|
+
function usePageTheme(ref, route) {
|
|
623
|
+
useStore(themesStore);
|
|
624
|
+
const [, bump] = useState(0);
|
|
625
|
+
useEffect(() => onPrefsChanged((changed) => { if (changed.has("theme.pageByInstance") || changed.has("fx.show")) bump((n) => n + 1); }), []);
|
|
626
|
+
useEffect(() => {
|
|
627
|
+
const T = globalThis.AgendTheme;
|
|
628
|
+
const off = T && typeof T.onChange === "function" ? T.onChange(() => bump((n) => n + 1)) : null;
|
|
629
|
+
let mq = null;
|
|
630
|
+
try { mq = globalThis.matchMedia ? globalThis.matchMedia("(prefers-color-scheme: light)") : null; } catch { mq = null; }
|
|
631
|
+
const onMq = () => bump((n) => n + 1);
|
|
632
|
+
if (mq && typeof mq.addEventListener === "function") mq.addEventListener("change", onMq);
|
|
633
|
+
return () => { if (typeof off === "function") off(); if (mq && typeof mq.removeEventListener === "function") mq.removeEventListener("change", onMq); };
|
|
634
|
+
}, []);
|
|
635
|
+
const mode = resolvedMode();
|
|
636
|
+
const p = pageNow(mode, route);
|
|
637
|
+
const key = p ? `${mode}|${JSON.stringify(p)}` : "";
|
|
638
|
+
useLayoutEffect(() => { applyPageTheme(ref.current, p, mode); }, [key]);
|
|
639
|
+
// #2199: the agent open now, as body[data-agent] — for a person's own custom CSS to follow (body[data-agent="x"]
|
|
640
|
+
// { --bg-sidebar: … }); set and cleared in the same render as the page colours, whatever the themes switch says.
|
|
641
|
+
const agent = openInstanceOf(route);
|
|
642
|
+
useLayoutEffect(() => {
|
|
643
|
+
const body = typeof document !== "undefined" ? document.body : null;
|
|
644
|
+
if (!body || !body.dataset) return;
|
|
645
|
+
if (agent) body.dataset.agent = agent; else delete body.dataset.agent;
|
|
646
|
+
}, [agent]);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/** #2478: how far short of its tallest the view must be, with a text field focused, to be a keyboard (not a browser bar). */
|
|
650
|
+
export const KEYBOARD_MIN_PX = 150;
|
|
651
|
+
/** #2478: the on-screen keyboard is up — something is being typed into, and the view is well short of its tallest. */
|
|
652
|
+
export function keyboardUp(height, tallest, typing) { return !!typing && tallest - height > KEYBOARD_MIN_PX; }
|
|
653
|
+
const NOT_TYPED = /^(button|checkbox|radio|range|color|file|submit|reset|image|hidden)$/i;
|
|
654
|
+
/** #2478: an element the keyboard types into — a textarea, a text-like input, or an editable region. */
|
|
655
|
+
export function isTextEntry(el) {
|
|
656
|
+
if (!el || !el.tagName) return false;
|
|
657
|
+
const tag = String(el.tagName).toUpperCase();
|
|
658
|
+
if (tag === "TEXTAREA") return !el.readOnly && !el.disabled;
|
|
659
|
+
if (tag === "INPUT") return !NOT_TYPED.test(el.type || "text") && !el.readOnly && !el.disabled;
|
|
660
|
+
return el.isContentEditable === true;
|
|
661
|
+
}
|
|
662
|
+
|
|
548
663
|
export function Shell({ panels, onNewInstance, viewOnly = false }) {
|
|
549
664
|
const nav = useStore(navStore);
|
|
550
665
|
const shell = useStore(shellStore);
|
|
666
|
+
const root = useRef(null);
|
|
667
|
+
usePageTheme(root, nav.route);
|
|
551
668
|
const [, relang] = useState(0);
|
|
552
669
|
// A language switch re-renders everything and gives the panel a new lease (its key includes the language).
|
|
553
670
|
useEffect(() => onLang(() => relang(n => n + 1)), []);
|
|
554
671
|
useEffect(() => { closeDrawer(); }, [nav.seq]);
|
|
555
|
-
// The bottom tabs give their room to the keyboard on a phone.
|
|
672
|
+
// The bottom tabs (and the line under the composer) give their room to the keyboard on a phone (#2478).
|
|
556
673
|
useEffect(() => {
|
|
557
674
|
const vv = typeof window !== "undefined" ? window.visualViewport : null;
|
|
558
|
-
if (!vv) return undefined;
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
675
|
+
if (!vv || typeof document === "undefined") return undefined;
|
|
676
|
+
// The tallest the view has been at this width: what it is with no keyboard. innerHeight is no measure on its own —
|
|
677
|
+
// it shrinks with the keyboard on iOS Safari and, under interactive-widget=resizes-content, on Android — so
|
|
678
|
+
// innerHeight − height stayed near 0 and the strips stayed between the composer and the keyboard.
|
|
679
|
+
// Only a touch screen (a coarse pointer) has an on-screen keyboard: a narrow desk window made shorter is not one.
|
|
680
|
+
// Turned with the keyboard up and the field still focused, the new width has no height without it yet: the keyboard
|
|
681
|
+
// stays up until the field is left, or the view grows from its lowest by more than a keyboard (put away).
|
|
682
|
+
let width = -1, tallest = 0, held = false, lowest = 0;
|
|
683
|
+
const coarse = () => typeof matchMedia === "function" && matchMedia("(pointer: coarse)").matches;
|
|
684
|
+
const check = () => {
|
|
685
|
+
const w = Math.round(vv.width), h = vv.height;
|
|
686
|
+
const typing = coarse() && isTextEntry(document.activeElement);
|
|
687
|
+
if (w !== width) { // turned, or a new width: measured again
|
|
688
|
+
held = width !== -1 && typing && shellStore.get().keyboard;
|
|
689
|
+
width = w; tallest = 0; lowest = h;
|
|
690
|
+
}
|
|
691
|
+
if (held) {
|
|
692
|
+
lowest = Math.min(lowest, h);
|
|
693
|
+
if (!typing || h - lowest > KEYBOARD_MIN_PX) held = false; // left the field, or the keyboard was put away
|
|
694
|
+
}
|
|
695
|
+
if (!held) tallest = Math.max(tallest, window.innerHeight || 0, typing ? 0 : h); // the view itself only when not typing
|
|
696
|
+
const up = held || keyboardUp(h, tallest, typing);
|
|
697
|
+
if (up !== shellStore.get().keyboard) shellStore.set({ keyboard: up });
|
|
698
|
+
};
|
|
699
|
+
check();
|
|
700
|
+
vv.addEventListener("resize", check);
|
|
701
|
+
document.addEventListener("focusin", check);
|
|
702
|
+
document.addEventListener("focusout", check);
|
|
703
|
+
return () => { vv.removeEventListener("resize", check); document.removeEventListener("focusin", check); document.removeEventListener("focusout", check); };
|
|
562
704
|
}, []);
|
|
563
705
|
const guest = guestPage(); // #1920: a guest's page — no operations, usage, pending changes or owner CSS
|
|
564
706
|
const cls = ["shell", shell.collapsed ? "sb-collapsed" : "", shell.drawer ? "sb-open" : "", shell.keyboard ? "kb-open" : "", guest ? "guest" : ""].filter(Boolean).join(" ");
|
|
565
|
-
return html`<div class=${cls}>
|
|
707
|
+
return html`<div ref=${root} class=${cls}>
|
|
566
708
|
<a data-trust="navigation" class="skip" href="#main">${t("app.skip")}</a>
|
|
567
709
|
<${Sidebar} route=${nav.route} onNewInstance=${onNewInstance} viewOnly=${viewOnly} />
|
|
568
710
|
<div class="scrim" onClick=${closeDrawer} aria-hidden="true"></div>
|
|
569
711
|
<main id="main" class="main" tabindex="-1" inert=${shell.drawer && narrow() ? true : undefined}>
|
|
570
712
|
<${ConnectionLine} />
|
|
713
|
+
<${StartupLine} />
|
|
571
714
|
${viewOnly || guest ? null : html`<${OperationLine} route=${nav.route} />`}
|
|
715
|
+
${viewOnly || guest || !shell.banner ? null : html`<${shell.banner} />`}
|
|
572
716
|
<${Outlet} route=${nav.route} seq=${nav.seq} panels=${panels} />
|
|
573
717
|
</main>
|
|
574
718
|
${guest ? null : html`<${UsageRail} route=${nav.route} />`}
|
|
@@ -24,7 +24,7 @@ export function createStore(initial) {
|
|
|
24
24
|
* (app-stream.js catchUp) — "catching" / "retrying" / "failed" / "ok"; `retryHydration` asks for it again.
|
|
25
25
|
* `connections`: how many chat connections the fleet has (#1519 P7: 0 is web-only — the first-run card); null until known. */
|
|
26
26
|
export const appStore = createStore({ ready: false, instances: [], uptime: 0, exec: {}, awaiting: {}, connection: "connecting", needs: [], connections: null,
|
|
27
|
-
hydration: "none", retryHydration: null });
|
|
27
|
+
hydration: "none", retryHydration: null, canvasWorker: typeof document !== "undefined" && document.body?.dataset.canvasWorker === "1" });
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
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
|
|
@@ -49,7 +49,8 @@ export function applyStatus(d) {
|
|
|
49
49
|
exec[i.name] = (i.execution_state !== undefined ? i.execution_state : i.state) ?? null;
|
|
50
50
|
if (i.state === "awaiting_input") awaiting[i.name] = typeof i.interaction_summary === "string" ? i.interaction_summary : "";
|
|
51
51
|
}
|
|
52
|
-
appStore.set({ ready: true, instances: d.instances, uptime: d.uptime ?? 0, exec, awaiting,
|
|
52
|
+
appStore.set({ canvasWorker: d.canvas_worker === true, ready: true, instances: d.instances, uptime: d.uptime ?? 0, exec, awaiting,
|
|
53
|
+
startup: d.startup?.phase === "starting" ? d.startup : null,
|
|
53
54
|
connections: typeof d.connections === "number" ? d.connections : null,
|
|
54
55
|
// #1665: the host preferences' revision (app-prefs.js re-reads them when it moves).
|
|
55
56
|
prefsRev: typeof d.prefs_rev === "number" ? d.prefs_rev : null,
|
|
@@ -30,8 +30,12 @@
|
|
|
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
|
-
// #1918: traffic — a message between instances moved
|
|
34
|
-
|
|
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
|
+
// offices — the stored offices changed ({ rev }; SSE only: the Office view reads /ui/offices again).
|
|
38
|
+
const EVENTS = ["status", "message", "agent_reply_live", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "reactions", "steps_tick", "clock", "traffic", "delegation", "backend_login", "tasks", "offices"];
|
|
35
39
|
const MAX_HELD = 1000; // live events held during one catch-up read; more → read again afterwards
|
|
36
40
|
const RETRY_DELAYS = [1000, 2000, 4000]; // after the first failed catch-up read; then it waits for Retry
|
|
37
41
|
const POLL_LIMIT_MS = 10000; // a poll that has not answered by then counts as failed
|
|
@@ -125,6 +129,7 @@ export function createStream(opts) {
|
|
|
125
129
|
if (Array.isArray(d.deliveries)) emit("deliveries", d.deliveries);
|
|
126
130
|
if (Array.isArray(d.prompts)) emit("prompts", d.prompts);
|
|
127
131
|
if (Array.isArray(d.reply_buttons)) for (const u of d.reply_buttons) emit("reply_buttons", u); // #1266
|
|
132
|
+
if (Array.isArray(d.reactions)) for (const u of d.reactions) emit("reactions", u); // #2305
|
|
128
133
|
if (Array.isArray(d.needs)) emit("needs", { items: d.needs });
|
|
129
134
|
return true;
|
|
130
135
|
} catch { return false; /* the next tick, or the catch-up's retry, tries again */ }
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// #1629 (first design §5, r2 (b)(d)): agents' web themes on the page. Each applies to THAT agent's own chat surface
|
|
2
|
-
// (and its avatar ring)
|
|
2
|
+
// (and its avatar ring) — and, #2196, when the agent (theme.page.on) or a person (theme.pageByInstance) says so, its
|
|
3
|
+
// colours on the whole page while that agent's Chat, View, Log or Details is open: colour tokens only, on the shell
|
|
4
|
+
// (applyPageTheme); AgEnD's status colours, fonts, pictures and layout stay the page's own. What the host sends is
|
|
3
5
|
// canonical already; this checks it again (a value that fails is dropped, never passed on) and applies it through the
|
|
4
6
|
// CSSOM (custom properties) and fixed class tokens. No style attribute, no CSS text, no url() built in CSS.
|
|
5
7
|
// Not shown: with "Show agents' themes, effects and widgets" off (fx.show, synced), and in safe mode (?safe=1).
|
|
6
8
|
import { appStore, createStore } from "./app-store.js";
|
|
9
|
+
import { navStore } from "./app-nav.js";
|
|
7
10
|
import { onPrefsChanged, prefInForce, savePref } from "./app-prefs.js";
|
|
8
11
|
import { safeMode } from "./owner-css.js";
|
|
9
12
|
import { t } from "./app-i18n.js";
|
|
@@ -86,9 +89,110 @@ export function themeFor(name) {
|
|
|
86
89
|
out.background = { image: bg.image, fit: bg.fit, opacity: bg.opacity };
|
|
87
90
|
}
|
|
88
91
|
if (labelOk(t.workingLabel)) out.workingLabel = t.workingLabel;
|
|
92
|
+
if (t.page && typeof t.page === "object") {
|
|
93
|
+
const sb = {};
|
|
94
|
+
if (t.page.sidebar && typeof t.page.sidebar === "object") for (const m of ["light", "dark"]) if (typeof t.page.sidebar[m] === "string" && COLOR.test(t.page.sidebar[m])) sb[m] = t.page.sidebar[m];
|
|
95
|
+
out.page = { on: t.page.on === true, sidebar: sb };
|
|
96
|
+
}
|
|
89
97
|
return out;
|
|
90
98
|
}
|
|
91
99
|
|
|
100
|
+
// ── #2196: an agent's colours on the whole page ──
|
|
101
|
+
|
|
102
|
+
/** The token defaults (tokens.css; web-theme.ts THEME_DEFAULTS, pinned by a test) a theme's palette goes over. */
|
|
103
|
+
const PAGE_DEFAULTS = {
|
|
104
|
+
dark: { bg: "#212121", surface: "#2f2f2f", text: "#ececec", text2: "#b4b4b4", accent: "#7ab7ff" },
|
|
105
|
+
light: { bg: "#ffffff", surface: "#f4f4f4", text: "#0d0d0d", text2: "#5d5d5d", accent: "#0a62c2" },
|
|
106
|
+
};
|
|
107
|
+
/** AgEnD's status colours (tokens.css; web-theme.ts STATUS_COLORS, pinned by a test): never themed, always readable. */
|
|
108
|
+
export const STATUS_COLORS = {
|
|
109
|
+
dark: { ok: "#4cc38a", warn: "#e3b341", danger: "#ff8a80", dangerFill: "#c9372c", focus: "#7ab7ff" },
|
|
110
|
+
light: { ok: "#1a7f37", warn: "#8a5a00", danger: "#c4222b", dangerFill: "#c4222b", focus: "#0a62c2" },
|
|
111
|
+
};
|
|
112
|
+
const PAGE_PROPS = { bg: "--bg", sidebar: "--bg-sidebar", surface: "--surface", text: "--text", text2: "--text-2", accent: "--accent" };
|
|
113
|
+
const DERIVED_PROPS = ["--text-3", "--surface-2", "--border", "--border-strong", "--accent-dim", "--on-accent"];
|
|
114
|
+
function lum(hex) {
|
|
115
|
+
const c = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255).map((x) => (x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4));
|
|
116
|
+
return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
|
|
117
|
+
}
|
|
118
|
+
const ratio = (a, b) => { const [x, y] = [lum(a), lum(b)].sort((p, q) => q - p); return (x + 0.05) / (y + 0.05); };
|
|
119
|
+
const mix = (a, b, f) => `#${[1, 3, 5].map((i) => Math.round(parseInt(a.slice(i, i + 2), 16) * (1 - f) + parseInt(b.slice(i, i + 2), 16) * f).toString(16).padStart(2, "0")).join("")}`;
|
|
120
|
+
|
|
121
|
+
/** The instance a page is about — Chat, View, Log or Details of it (app-shell.js openInstanceOf) — or null. */
|
|
122
|
+
function openOf(route) {
|
|
123
|
+
return route && ["chat", "view", "log", "details"].includes(route.panel) && typeof route.instance === "string" ? route.instance : null;
|
|
124
|
+
}
|
|
125
|
+
/** A person's choice for `name`: "page" (the whole page), "chat" (only its chat) or null (the agent's own). */
|
|
126
|
+
export function pageChoice(name) {
|
|
127
|
+
const f = prefInForce("theme.pageByInstance");
|
|
128
|
+
const m = f && f.value;
|
|
129
|
+
return m && typeof m === "object" && own(m, name) && (m[name] === "page" || m[name] === "chat") ? m[name] : null;
|
|
130
|
+
}
|
|
131
|
+
/** Set it ("agent" clears it), kept with the host's preferences like the identity colour a person picks. */
|
|
132
|
+
export function setPageChoice(name, choice) {
|
|
133
|
+
const f = prefInForce("theme.pageByInstance");
|
|
134
|
+
const cur = f && f.value && typeof f.value === "object" ? f.value : {};
|
|
135
|
+
const keep = Object.keys(cur).filter((k) => own(cur, k) && k !== name && (cur[k] === "page" || cur[k] === "chat")).map((k) => [k, cur[k]]);
|
|
136
|
+
if (choice === "page" || choice === "chat") keep.push([name, choice]);
|
|
137
|
+
savePref("theme.pageByInstance", keep.length ? Object.fromEntries(keep) : null);
|
|
138
|
+
// In force on this page at once: what draws a theme follows this store (another device's change: onPrefsChanged).
|
|
139
|
+
themesStore.set({ pageRev: (themesStore.get().pageRev || 0) + 1 });
|
|
140
|
+
}
|
|
141
|
+
/** `name`'s theme when its colours go on the whole page (the person's choice, else the agent's), else null. */
|
|
142
|
+
export function pageThemeFor(name) {
|
|
143
|
+
if (!name) return null;
|
|
144
|
+
const theme = themeFor(name);
|
|
145
|
+
if (!theme) return null;
|
|
146
|
+
const choice = pageChoice(name);
|
|
147
|
+
return choice === "page" || (choice !== "chat" && theme.page && theme.page.on) ? theme : null;
|
|
148
|
+
}
|
|
149
|
+
/** The page's colours for `mode`: the theme's palette over the defaults, and its sidebar (else its background). */
|
|
150
|
+
export function pagePalette(theme, mode) {
|
|
151
|
+
const p = { ...PAGE_DEFAULTS[mode], ...(theme.accent ? { accent: theme.accent } : {}), ...((theme.colors && theme.colors[mode]) || {}) };
|
|
152
|
+
const out = {};
|
|
153
|
+
for (const k of Object.keys(PAGE_DEFAULTS[mode])) out[k] = p[k];
|
|
154
|
+
out.sidebar = (theme.page && theme.page.sidebar && theme.page.sidebar[mode]) || out.bg;
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Whether a page palette reads (web-theme.ts's checks, again here: a person may put an agent's colours on the page
|
|
159
|
+
* though the agent never asked): text and secondary text 4.5:1 and the accent 3:1 on the background, surface and
|
|
160
|
+
* sidebar; every status colour 3:1 on the sidebar and the background.
|
|
161
|
+
*/
|
|
162
|
+
export function pageReadable(p, mode) {
|
|
163
|
+
if (!p || !Object.values(p).every((c) => typeof c === "string" && COLOR.test(c))) return false;
|
|
164
|
+
for (const bg of [p.bg, p.surface, p.sidebar]) {
|
|
165
|
+
if (ratio(p.text, bg) < 4.5 - 1e-9 || ratio(p.text2, bg) < 4.5 - 1e-9) return false;
|
|
166
|
+
}
|
|
167
|
+
if (ratio(p.accent, p.bg) < 3 - 1e-9 || ratio(p.accent, p.sidebar) < 3 - 1e-9) return false;
|
|
168
|
+
return Object.values(STATUS_COLORS[mode]).every((c) => ratio(c, p.sidebar) >= 3 - 1e-9 && ratio(c, p.bg) >= 3 - 1e-9);
|
|
169
|
+
}
|
|
170
|
+
/** The page colours in force now for `mode` (the instance the route is about), or null: the page's own. */
|
|
171
|
+
export function pageNow(mode, route = navStore.get().route) {
|
|
172
|
+
const theme = pageThemeFor(openOf(route));
|
|
173
|
+
const p = theme && pagePalette(theme, mode);
|
|
174
|
+
return p && pageReadable(p, mode) ? p : null;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Draw page colours `p` (pageNow) on the shell `el`, or clear them (null): the palette's tokens and the few derived
|
|
178
|
+
* from it (borders, raised rows, the accent's tint and the colour on it), through the CSSOM; class th-page.
|
|
179
|
+
*/
|
|
180
|
+
export function applyPageTheme(el, p, mode) {
|
|
181
|
+
if (!el || !el.style) return;
|
|
182
|
+
for (const prop of [...Object.values(PAGE_PROPS), ...DERIVED_PROPS]) el.style.removeProperty(prop);
|
|
183
|
+
el.classList.remove("th-page");
|
|
184
|
+
if (!p) return;
|
|
185
|
+
for (const [k, prop] of Object.entries(PAGE_PROPS)) el.style.setProperty(prop, p[k]);
|
|
186
|
+
el.style.setProperty("--text-3", p.text2);
|
|
187
|
+
el.style.setProperty("--surface-2", mix(p.surface, p.text, 0.08));
|
|
188
|
+
el.style.setProperty("--border", mix(p.bg, p.text, 0.14));
|
|
189
|
+
el.style.setProperty("--border-strong", mix(p.bg, p.text, 0.45));
|
|
190
|
+
const [r, g, b] = [1, 3, 5].map((i) => parseInt(p.accent.slice(i, i + 2), 16));
|
|
191
|
+
el.style.setProperty("--accent-dim", `rgba(${r}, ${g}, ${b}, ${mode === "dark" ? 0.14 : 0.08})`);
|
|
192
|
+
el.style.setProperty("--on-accent", ratio("#ffffff", p.accent) >= ratio("#0d0d0d", p.accent) ? "#ffffff" : "#0d0d0d");
|
|
193
|
+
el.classList.add("th-page");
|
|
194
|
+
}
|
|
195
|
+
|
|
92
196
|
export function isThemeLocked(name) { return (themesStore.get().locked || []).includes(name); }
|
|
93
197
|
|
|
94
198
|
const TOKENS = ["th", "th-font-inter", "th-font-system", "th-font-mono", "th-bubble-none", "th-bubble-thin", "th-bubble-accent", "th-agent-bubble"];
|
|
@@ -193,7 +297,18 @@ export function themeMenuItems(name) {
|
|
|
193
297
|
const locked = isThemeLocked(name);
|
|
194
298
|
const w = themesStore.get().widgets;
|
|
195
299
|
const placed = w && own(w, name) && w[name] && typeof w[name] === "object" ? w[name] : {};
|
|
300
|
+
// #2196: where this agent's colours go — its own choice, the whole page, or only its chat (the person's wins).
|
|
301
|
+
const choice = pageChoice(name), theme = themeFor(name), mode = resolvedMode();
|
|
302
|
+
const agentsOwn = theme && theme.page && theme.page.on ? "chat.pageAgentOn" : "chat.pageAgentOff";
|
|
303
|
+
const readable = !!theme && pageReadable(pagePalette(theme, mode), mode);
|
|
304
|
+
const page = theme ? [
|
|
305
|
+
{ key: "page-heading", heading: true, label: t("chat.pageColours") },
|
|
306
|
+
{ key: "page-agent", checked: choice === null, label: t(agentsOwn), onSelect: () => setPageChoice(name, "agent") },
|
|
307
|
+
{ key: "page-page", checked: choice === "page", label: t("chat.pageWhole"), disabled: !readable && choice !== "page", onSelect: () => setPageChoice(name, "page") },
|
|
308
|
+
{ key: "page-chat", checked: choice === "chat", label: t("chat.pageChatOnly"), onSelect: () => setPageChoice(name, "chat") },
|
|
309
|
+
] : [];
|
|
196
310
|
return [
|
|
311
|
+
...page,
|
|
197
312
|
...["chat_header", "details"].filter((slot) => own(placed, slot)).map((slot) => ({
|
|
198
313
|
key: `widget-remove-${slot}`, label: t(slot === "chat_header" ? "chat.widgetRemoveHeader" : "chat.widgetRemoveDetails"), icon: "trash",
|
|
199
314
|
onSelect: () => removeWidget(name, slot),
|