@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
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
import { html, useEffect, useLayoutEffect, useMemo, useRef, useState } from "./app-html.js";
|
|
5
5
|
import { t } from "./app-i18n.js";
|
|
6
6
|
import { useLease } from "./app-ctx.js";
|
|
7
|
-
import { guestPage } from "./app-store.js";
|
|
7
|
+
import { createStore, guestPage, useStore } from "./app-store.js";
|
|
8
|
+
import { onPrefsChanged, prefInForce, savePref } from "./app-prefs.js";
|
|
8
9
|
import { readStream } from "./read-stream.js";
|
|
9
10
|
import { Dialog } from "./ui-dialog.js";
|
|
10
11
|
import { ErrorState, Skeleton } from "./ui-states.js";
|
|
@@ -39,6 +40,24 @@ function resetText(iso) {
|
|
|
39
40
|
if (ms <= 0) return tn("usage.reset.soon");
|
|
40
41
|
return usageText("", { key: "usage.reset.in", args: [usageDuration(ms)] });
|
|
41
42
|
}
|
|
43
|
+
/** "14:05" today, "10/19 14:05" another day, in this browser's time: when last known numbers were read, a window reset. */
|
|
44
|
+
export function usageClock(iso, now = Date.now()) {
|
|
45
|
+
const at = new Date(iso || "");
|
|
46
|
+
if (Number.isNaN(at.getTime())) return "";
|
|
47
|
+
const hm = `${String(at.getHours()).padStart(2, "0")}:${String(at.getMinutes()).padStart(2, "0")}`;
|
|
48
|
+
return new Date(now).toDateString() === at.toDateString() ? hm : `${at.getMonth() + 1}/${at.getDate()} ${hm}`;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A row showing its last known numbers (the live read failed; #2236 follow-up): "已過期 · 快取於 14:05" and, for an expiry
|
|
52
|
+
* or another failure, what to do on a second line (its full text is the mark's tooltip too). A row from an older
|
|
53
|
+
* server (no `cachedAt`) says its hint, as before.
|
|
54
|
+
*/
|
|
55
|
+
export function staleNote(p) {
|
|
56
|
+
if (!p.stale) return null;
|
|
57
|
+
if (!p.cachedAt || !p.staleCause) return { mark: usageText(p.hint || "", p.hintI18n), detail: "" };
|
|
58
|
+
const detail = p.staleCause !== "transient" && (p.hint || p.hintI18n) ? usageText(p.hint || "", p.hintI18n) : "";
|
|
59
|
+
return { mark: usageText("", { key: `usage.stale.${p.staleCause}`, args: [usageClock(p.cachedAt)] }), detail };
|
|
60
|
+
}
|
|
42
61
|
function expiryText(iso) {
|
|
43
62
|
if (!iso) return "";
|
|
44
63
|
const at = new Date(iso), ms = at.getTime() - Date.now();
|
|
@@ -48,6 +67,8 @@ function expiryText(iso) {
|
|
|
48
67
|
export function UsageMetric({ m }) {
|
|
49
68
|
const bar = useRef(null);
|
|
50
69
|
const label = usageText(m.label, m.labelI18n);
|
|
70
|
+
// Its window has reset since these numbers were read: no number and no bar — an old one is never shown as current.
|
|
71
|
+
if (m.resetPassed) return html`<div class="u-metric u-reset-since"><div class="u-row"><span class="u-label">${label}</span><span class="u-val">${usageText("", { key: "usage.metric.reset_since", args: [usageClock(m.resetsAt)] })}</span></div></div>`;
|
|
51
72
|
const note = m.note ? usageText(m.note, m.noteI18n) : "";
|
|
52
73
|
const pct = m.type === "percent" ? Math.min(100, Math.max(0, m.used ?? 0)) : 0;
|
|
53
74
|
useLayoutEffect(() => { if (bar.current) bar.current.style.width = `${pct}%`; }, [pct]); // CSSOM (#1300)
|
|
@@ -70,10 +91,13 @@ export function UsageMetric({ m }) {
|
|
|
70
91
|
/**
|
|
71
92
|
* #2014: a row's title. A credential profile's row (`profile`; its API `name` is "Claude (<profile>)") shows the
|
|
72
93
|
* provider name on the title line beside the plan badge, and the profile on its own full-width muted line under it;
|
|
73
|
-
* the full name is the tooltip, and the dialog shows the profile unclipped.
|
|
94
|
+
* the full name is the tooltip, and the dialog shows the profile unclipped. The default login's row beside profiles
|
|
95
|
+
* (`defaultLogin`; "Claude (default)", #2236) does the same with "default" in the page's language, never a clipped
|
|
96
|
+
* "Claude (d…". Any other row: its name.
|
|
74
97
|
*/
|
|
75
98
|
export function providerTitle(p) {
|
|
76
99
|
const name = String((p && p.name) || ""), profile = p && typeof p.profile === "string" && p.profile ? p.profile : "";
|
|
100
|
+
if (!profile && p && p.defaultLogin === true && name.endsWith(" (default)")) return { base: name.slice(0, -" (default)".length), profile: tn("usage.default_login") };
|
|
77
101
|
const suffix = ` (${profile})`;
|
|
78
102
|
return profile && name.endsWith(suffix) ? { base: name.slice(0, -suffix.length), profile } : { base: name, profile };
|
|
79
103
|
}
|
|
@@ -84,9 +108,20 @@ export function providerTitle(p) {
|
|
|
84
108
|
* tooltip and for a screen reader.
|
|
85
109
|
*/
|
|
86
110
|
export function planBadge(plan) {
|
|
87
|
-
const
|
|
88
|
-
|
|
111
|
+
const text = String(plan || "").trim();
|
|
112
|
+
const m = /^(\S+)(?: [^()]+)? \((\d+(?:\.\d+)?)x\)$/i.exec(text);
|
|
113
|
+
if (m) return `${m[1]} ×${m[2]}`;
|
|
114
|
+
// #2412: a long name ("Self Serve Business Usage Based", Codex's plan_type spelled out) says only its kind, so the badge
|
|
115
|
+
// never takes the row from the provider's name; the full name is the badge's tooltip.
|
|
116
|
+
if (text.length > PLAN_BADGE_MAX) {
|
|
117
|
+
for (const [word, short] of PLAN_KINDS) if (word.test(text)) return short;
|
|
118
|
+
}
|
|
119
|
+
return text;
|
|
89
120
|
}
|
|
121
|
+
const PLAN_BADGE_MAX = 14;
|
|
122
|
+
/** The kinds a long plan name is shortened to, the most specific first. */
|
|
123
|
+
const PLAN_KINDS = [[/\benterprise\b/i, "Enterprise"], [/\bbusiness\b/i, "Business"], [/\bteam\b/i, "Team"], [/\bedu(?:cation)?\b/i, "Edu"],
|
|
124
|
+
[/\bpro\+/i, "Pro+"], [/\bpro\b/i, "Pro"], [/\bplus\b/i, "Plus"], [/\bmax\b/i, "Max"], [/\bfree\b/i, "Free"]];
|
|
90
125
|
/** "Updated 3 min ago" (#1585): how old the numbers are — the panel may show the last snapshot while a fresh one comes. */
|
|
91
126
|
export function updatedAgo(fetchedAt, now = Date.now()) {
|
|
92
127
|
const ms = now - new Date(fetchedAt).getTime();
|
|
@@ -95,15 +130,159 @@ export function updatedAgo(fetchedAt, now = Date.now()) {
|
|
|
95
130
|
return tn("usageUpdatedAgo", { age: min < 60 ? tn("usageMinutes", { n: min }) : tn("usageHours", { n: Math.floor(min / 60) }) });
|
|
96
131
|
}
|
|
97
132
|
|
|
133
|
+
// ── Compact: one line per login (a synced preference, "usage.compact"; the dialog and the rail alike) ──
|
|
134
|
+
const COMPACT_KEY = "agend_usage_compact";
|
|
135
|
+
function readCompact() {
|
|
136
|
+
const p = prefInForce("usage.compact");
|
|
137
|
+
return (p ? p.value : stored(COMPACT_KEY) === "on" ? true : undefined) === true;
|
|
138
|
+
}
|
|
139
|
+
export const usageViewStore = createStore({ compact: readCompact() });
|
|
140
|
+
export function setUsageCompact(on) {
|
|
141
|
+
usageViewStore.set({ compact: !!on });
|
|
142
|
+
savePref("usage.compact", on ? true : null); // the full cards are the default: switching back clears it
|
|
143
|
+
}
|
|
144
|
+
onPrefsChanged((keys) => { if (keys.has("usage.compact")) usageViewStore.set({ compact: readCompact() }); });
|
|
145
|
+
/** The header's switch between one line per login and the full cards (beside the title: the dialog's and the rail's). */
|
|
146
|
+
export function UsageCompactToggle() {
|
|
147
|
+
const { compact } = useStore(usageViewStore);
|
|
148
|
+
const [label, title] = compact ? [tn("usageFull"), tn("usageFullTitle")] : [tn("usageCompact"), tn("usageCompactTitle")];
|
|
149
|
+
return html`<button type="button" class="btn btn-ghost btn-sm u-compact-toggle" aria-pressed=${compact ? "true" : "false"} title=${title}
|
|
150
|
+
onClick=${() => setUsageCompact(!compact)}>${label}</button>`;
|
|
151
|
+
}
|
|
152
|
+
const TWO_DAYS = 48 * 3_600_000;
|
|
153
|
+
/**
|
|
154
|
+
* A login's two columns on its compact line: `short`, its shortest percent window under two days (the session), and
|
|
155
|
+
* `long`, its longest of two days or more (the week, the month) — null when it has none (a dash in that column). A window
|
|
156
|
+
* that reset since the numbers were read is left out (its full card shows no number); one of unknown length is a long one.
|
|
157
|
+
*/
|
|
158
|
+
export function compactSlots(p) {
|
|
159
|
+
const pct = ((p && p.metrics) || []).filter((m) => m && m.type === "percent" && !m.resetPassed);
|
|
160
|
+
const isShort = (m) => Number(m.windowMs) > 0 && m.windowMs < TWO_DAYS;
|
|
161
|
+
const short = pct.filter(isShort).sort((a, b) => a.windowMs - b.windowMs)[0] || null;
|
|
162
|
+
const long = pct.filter((m) => !isShort(m)).map((m, i) => ({ m, i }))
|
|
163
|
+
.sort((a, b) => ((Number(b.m.windowMs) || -1) - (Number(a.m.windowMs) || -1)) || a.i - b.i)[0]?.m || null;
|
|
164
|
+
return { short, long };
|
|
165
|
+
}
|
|
166
|
+
/** The windows a compact line shows, short first. */
|
|
167
|
+
export const compactMetrics = (p) => { const { short, long } = compactSlots(p); return [short, long].filter(Boolean); };
|
|
168
|
+
/** A window as a few characters ("5h", "7d"); one whose length is not known says its label. */
|
|
169
|
+
export function windowTag(m) {
|
|
170
|
+
const ms = Number(m && m.windowMs);
|
|
171
|
+
if (!(ms > 0)) return usageText(m.label, m.labelI18n);
|
|
172
|
+
const h = ms / 3_600_000;
|
|
173
|
+
return h < 48 ? tn("usageWindowHours", { n: Math.round(h) }) : tn("usageWindowDays", { n: Math.round(h / 24) });
|
|
174
|
+
}
|
|
175
|
+
/** A time ahead in one unit, for the narrow column: "45m", "3h", "4d" (rounded down past an hour; the tooltip is exact). */
|
|
176
|
+
function coarseDuration(ms) {
|
|
177
|
+
const min = Math.max(1, Math.ceil(ms / 60_000));
|
|
178
|
+
if (min < 60) return tn("usageWindowMinutes", { n: min });
|
|
179
|
+
const h = Math.floor(min / 60);
|
|
180
|
+
return h < 48 ? tn("usageWindowHours", { n: h }) : tn("usageWindowDays", { n: Math.floor(h / 24) });
|
|
181
|
+
}
|
|
182
|
+
/** The soonest reset still ahead among `metrics`: { short: "↻ 2h", full: "resets in 2h 5m" }, or null when none is known. */
|
|
183
|
+
export function soonestReset(metrics, now = Date.now()) {
|
|
184
|
+
const at = metrics.map((m) => new Date(m.resetsAt || "").getTime()).filter((t) => Number.isFinite(t) && t > now).sort((a, b) => a - b)[0];
|
|
185
|
+
return at === undefined ? null : { short: `↻ ${coarseDuration(at - now)}`, full: resetText(new Date(at).toISOString()) };
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* The logins grouped by provider for the compact view (nine logins, five of them Claude's: the provider once, then a
|
|
189
|
+
* line per login), in the order the person set (↑↓): a group where its first login is, its logins in their order.
|
|
190
|
+
*/
|
|
191
|
+
export function compactGroups(providers) {
|
|
192
|
+
const groups = new Map();
|
|
193
|
+
providers.forEach((p, i) => {
|
|
194
|
+
const base = providerTitle(p).base;
|
|
195
|
+
if (!groups.has(base)) groups.set(base, { base, items: [] });
|
|
196
|
+
groups.get(base).items.push({ p, i });
|
|
197
|
+
});
|
|
198
|
+
return [...groups.values()];
|
|
199
|
+
}
|
|
200
|
+
const level = (pct) => (pct >= 90 ? "crit" : pct >= 70 ? "warn" : "");
|
|
201
|
+
/**
|
|
202
|
+
* #2240: an account whose percent windows come from several pools (agy: Gemini, Claude & others, Gemini 4 Argon) — each
|
|
203
|
+
* pool with its windows and the tighter one (the most used); null for an account of one pool (its 5h / 7d lines).
|
|
204
|
+
*/
|
|
205
|
+
export function compactPools(p) {
|
|
206
|
+
const pct = ((p && p.metrics) || []).filter((m) => m && m.type === "percent" && !m.resetPassed);
|
|
207
|
+
const pools = new Map();
|
|
208
|
+
for (const m of pct) {
|
|
209
|
+
if (!m.pool || typeof m.pool.label !== "string") return null;
|
|
210
|
+
if (!pools.has(m.pool.label)) pools.set(m.pool.label, { pool: m.pool, metrics: [] });
|
|
211
|
+
pools.get(m.pool.label).metrics.push(m);
|
|
212
|
+
}
|
|
213
|
+
if (pools.size < 2) return null;
|
|
214
|
+
return [...pools.values()].map((x) => ({ ...x, worst: x.metrics.reduce((a, b) => ((b.used ?? 0) > (a.used ?? 0) ? b : a)) }));
|
|
215
|
+
}
|
|
216
|
+
const pctOf = (m) => Math.min(100, Math.max(0, m.used ?? 0));
|
|
217
|
+
/**
|
|
218
|
+
* One window on its own line: its few characters ("5h"), a full-width bar and the percent, coloured as the full card.
|
|
219
|
+
* A pool's line (#2240): the pool's name in place of the window, its every window in the tooltip.
|
|
220
|
+
*/
|
|
221
|
+
function CompactMeter({ m, tag, title }) {
|
|
222
|
+
const bar = useRef(null);
|
|
223
|
+
const pct = Math.min(100, Math.max(0, m.used ?? 0)), cls = level(pct);
|
|
224
|
+
useLayoutEffect(() => { if (bar.current) bar.current.style.width = `${pct}%`; }, [pct]); // CSSOM (#1300)
|
|
225
|
+
const word = cls === "crit" ? tn("usageNear") : cls === "warn" ? tn("usageHigh") : "";
|
|
226
|
+
return html`<span class="u-cm" title=${title || `${usageText(m.label, m.labelI18n)}: ${pct.toFixed(0)}%${word ? ` (${word})` : ""}`}>
|
|
227
|
+
<span class="u-cm-tag">${tag || windowTag(m)}</span><span class="u-cm-bar"><span ref=${bar} class=${`u-cm-fill ${cls}`}></span></span>
|
|
228
|
+
<span class=${`u-cm-pct ${cls}`}>${pct.toFixed(0)}%</span></span>`;
|
|
229
|
+
}
|
|
230
|
+
/** What a login says instead of numbers (not logged in, an error), or "" when it has numbers. */
|
|
231
|
+
function rowNote(p) {
|
|
232
|
+
if (p.status === "error") return usageText(p.error || tn("usage.error_fallback"), p.errorI18n);
|
|
233
|
+
if (p.status === "no-credentials") return tn("usage.not_logged_in");
|
|
234
|
+
return "";
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* A login in three short lines, under its provider's name (the user's pick, 2026-10-22): its name and plan with the
|
|
238
|
+
* soonest reset on the right; then its short window and its long one, each a labelled full-width bar and the percent.
|
|
239
|
+
* Numbers not current, a failed read or no login: one muted line in place of the bars, what is wrong as its tooltip.
|
|
240
|
+
* Pressed, it opens its full card.
|
|
241
|
+
*/
|
|
242
|
+
export function CompactRow({ p, onExpand }) {
|
|
243
|
+
const title = providerTitle(p), failed = p.status === "error" || p.status === "no-credentials";
|
|
244
|
+
const pools = failed || p.stale ? null : compactPools(p);
|
|
245
|
+
const metrics = failed || p.stale ? [] : pools ? pools.flatMap((x) => x.metrics) : compactMetrics(p);
|
|
246
|
+
const note = rowNote(p), stale = p.stale ? staleNote(p) : null;
|
|
247
|
+
const say = stale ? stale.mark : note || tn("usage.no_data");
|
|
248
|
+
const detail = stale ? [stale.mark, stale.detail].filter(Boolean).join(" — ") : say;
|
|
249
|
+
const reset = soonestReset(metrics);
|
|
250
|
+
const name = title.profile || title.base;
|
|
251
|
+
return html`<button type="button" class=${`u-crow${p.stale ? " is-stale" : ""}${pools ? " is-pooled" : ""}`} aria-expanded="false" title=${`${p.name} — ${tn("usageExpand")}`} onClick=${onExpand}>
|
|
252
|
+
<span class="u-crow-head"><span class="u-crow-name">${name}</span>
|
|
253
|
+
${p.plan ? html`<span class="pill u-plan" title=${p.plan}><span aria-hidden="true">${planBadge(p.plan)}</span><span class="sr-only">${p.plan}</span></span>` : null}
|
|
254
|
+
${reset ? html`<span class="u-crow-reset" title=${reset.full}>${reset.short}<span class="sr-only"> (${reset.full})</span></span>` : null}</span>
|
|
255
|
+
${pools ? pools.map((x) => html`<${CompactMeter} key=${x.pool.label} m=${x.worst} tag=${usageText(x.pool.label, x.pool.labelI18n)}
|
|
256
|
+
title=${x.metrics.map((m) => `${usageText(m.label, m.labelI18n)}: ${pctOf(m).toFixed(0)}%`).join(" · ")} />`)
|
|
257
|
+
: metrics.length ? metrics.map((m, j) => html`<${CompactMeter} key=${j} m=${m} />`)
|
|
258
|
+
: html`<span class=${`u-crow-note${(stale || (p.status === "error" && !p.transient)) ? " is-alert" : ""}`} title=${detail}>${say}</span>`}
|
|
259
|
+
</button>`;
|
|
260
|
+
}
|
|
261
|
+
/** A provider's logins: its name once (×N), in small capitals, then each login (or the full card of one opened). */
|
|
262
|
+
export function CompactGroup({ group, line }) {
|
|
263
|
+
return html`<section class="u-cgroup">
|
|
264
|
+
<div class="u-cg-head"><span class="u-cg-name" title=${group.base}>${group.base}</span>${group.items.length > 1 ? html`<span class="u-cg-count">×${group.items.length}</span>` : null}</div>
|
|
265
|
+
${group.items.map(line)}
|
|
266
|
+
</section>`;
|
|
267
|
+
}
|
|
268
|
+
|
|
98
269
|
/**
|
|
99
270
|
* The usage read and its rows: the dialog's body and the rail's (#1673). `owner`: its lease's key — the reads and the
|
|
100
271
|
* minute's timer live and end with it.
|
|
101
272
|
*/
|
|
102
273
|
export function UsageBody({ owner }) {
|
|
103
274
|
const lease = useLease(owner);
|
|
104
|
-
const [data, setData] = useState(undefined); // undefined: loading; null: failed
|
|
275
|
+
const [data, setData] = useState(undefined); // undefined: loading; null: failed, with nothing read before
|
|
276
|
+
// The last read failed while numbers were already shown: they stay, with a quiet note (#2236/#2289 for the server's
|
|
277
|
+
// rows; here for the read itself — a dropped or failed read must not flash the error over numbers already on screen).
|
|
278
|
+
const [failed, setFailed] = useState(false);
|
|
105
279
|
const [order, setOrder] = useState(() => { try { const a = JSON.parse(stored(USAGE_ORDER_KEY) || "[]"); return Array.isArray(a) ? a.filter((x) => typeof x === "string") : []; } catch { return []; } });
|
|
106
280
|
const reads = useMemo(() => readStream(lease), [lease]);
|
|
281
|
+
// Compact (one line per login): a line pressed opens its full card here, until folded or the mode changes.
|
|
282
|
+
const { compact } = useStore(usageViewStore);
|
|
283
|
+
const [expanded, setExpanded] = useState(() => new Set());
|
|
284
|
+
useEffect(() => { setExpanded(new Set()); }, [compact]);
|
|
285
|
+
const toggleOne = (id) => setExpanded((was) => { const next = new Set(was); if (next.has(id)) next.delete(id); else next.add(id); return next; });
|
|
107
286
|
// Refresh (force) supersedes a read on its way; the minute's tick waits for it.
|
|
108
287
|
const load = async (force) => {
|
|
109
288
|
const token = reads.begin(force);
|
|
@@ -111,19 +290,26 @@ export function UsageBody({ owner }) {
|
|
|
111
290
|
try {
|
|
112
291
|
const r = await lease.fetch(`/api/ai-usage${force ? "?force=1" : ""}`);
|
|
113
292
|
if (!reads.live(token)) return;
|
|
293
|
+
// A refused or failed answer (a 500, a proxy's 502 page, a session that lapsed) is a failed read, not numbers.
|
|
294
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
114
295
|
const d = await r.json();
|
|
115
|
-
if (
|
|
116
|
-
|
|
296
|
+
if (!d || !Array.isArray(d.providers)) throw new Error("no providers");
|
|
297
|
+
if (reads.live(token)) { setData(d); setFailed(false); }
|
|
298
|
+
} catch {
|
|
299
|
+
if (!reads.live(token)) return;
|
|
300
|
+
setData((had) => (had && Array.isArray(had.providers) ? had : null)); // the last numbers stay; none: the error
|
|
301
|
+
setFailed(true);
|
|
302
|
+
}
|
|
117
303
|
finally { reads.end(token); }
|
|
118
304
|
};
|
|
119
305
|
useEffect(() => { load(false); lease.interval(() => load(false), 60_000); }, [lease]);
|
|
120
306
|
// #1585: the server answered with the last snapshot while it fetches a fresh one — read again shortly (the same
|
|
121
307
|
// cache: no vendor call of its own) so the fresh numbers replace it without waiting for the minute's tick.
|
|
122
308
|
useEffect(() => {
|
|
123
|
-
if (!data || !data.refreshing) return undefined;
|
|
309
|
+
if (!data || !data.refreshing || failed) return undefined;
|
|
124
310
|
const timer = setTimeout(() => load(false), 4_000);
|
|
125
311
|
return () => clearTimeout(timer);
|
|
126
|
-
}, [data]);
|
|
312
|
+
}, [data, failed]);
|
|
127
313
|
const key = (p) => String(p.id || p.name || "");
|
|
128
314
|
const ordered = (providers) => {
|
|
129
315
|
const rank = new Map(order.map((id, i) => [id, i]));
|
|
@@ -144,22 +330,26 @@ export function UsageBody({ owner }) {
|
|
|
144
330
|
else if (!data || !Array.isArray(data.providers)) content = html`<${ErrorState} message=${tn("usageFail")} onRetry=${() => load(true)} />`;
|
|
145
331
|
else {
|
|
146
332
|
const providers = ordered(data.providers);
|
|
147
|
-
|
|
148
|
-
${providers.map((p, i) => html`<section key=${key(p)} class="u-provider">
|
|
333
|
+
const card = (p, i) => html`<section key=${key(p)} class=${p.stale ? "u-provider is-stale" : "u-provider"}>
|
|
149
334
|
<div class="u-head"><strong title=${p.name}>${providerTitle(p).base}</strong>${p.plan ? html`<span class="pill u-plan" title=${p.plan}><span aria-hidden="true">${planBadge(p.plan)}</span><span class="sr-only">${p.plan}</span></span>` : null}
|
|
150
|
-
<span class="u-order"
|
|
335
|
+
<span class="u-order">${compact ? html`<button type="button" class="icon-btn u-collapse" aria-expanded="true" aria-label=${tn("usageCollapse")} title=${tn("usageCollapse")}
|
|
336
|
+
onClick=${() => toggleOne(key(p))}><${Icon} name="minus" size=${14} /></button>` : null}
|
|
151
337
|
<button type="button" class="icon-btn" disabled=${i === 0} aria-label=${tn("usageMoveUp")} title=${tn("usageMoveUp")} onClick=${() => move(key(p), -1, data.providers)}><${Icon} name="up" size=${14} /></button>
|
|
152
338
|
<button type="button" class="icon-btn" disabled=${i === providers.length - 1} aria-label=${tn("usageMoveDown")} title=${tn("usageMoveDown")} onClick=${() => move(key(p), 1, data.providers)}><${Icon} name="down" size=${14} /></button>
|
|
153
339
|
</span></div>
|
|
154
340
|
${providerTitle(p).profile ? html`<div class="u-profile" title=${p.name}>${providerTitle(p).profile}</div>` : null}
|
|
155
|
-
${p.stale ? html`<p class="note"
|
|
341
|
+
${p.stale ? html`<p class="note u-stale" title=${staleNote(p).detail || null}>${staleNote(p).mark}</p>${staleNote(p).detail ? html`<p class="note u-stale-detail">${staleNote(p).detail}</p>` : null}` : null}
|
|
156
342
|
${p.status === "error" && !p.transient ? html`<p class="u-err">${usageText(p.error || tn("usage.error_fallback"), p.errorI18n)}</p>`
|
|
157
343
|
: p.status === "error" && p.transient ? html`<p class="note">${usageText(p.error || tn("usage.error_fallback"), p.errorI18n)}</p>`
|
|
158
344
|
: p.status === "no-credentials" ? html`<p class="note">${tn("usage.not_logged_in")}</p>${p.hint ? html`<p class="note">${usageText(p.hint, p.hintI18n)}</p>` : null}`
|
|
159
345
|
: html`${(p.metrics || []).map((m, j) => html`<${UsageMetric} key=${j} m=${m} />`)}
|
|
160
346
|
${!p.stale && p.hint ? html`<p class="note">${usageText(p.hint, p.hintI18n)}</p>` : !(p.metrics || []).length ? html`<p class="note">${tn("usage.no_data")}</p>` : null}`}
|
|
161
|
-
</section
|
|
162
|
-
|
|
347
|
+
</section>`;
|
|
348
|
+
content = html`${!providers.length ? html`<p class="note">${tn("usage.empty_active")}</p>` : null}
|
|
349
|
+
${compact ? compactGroups(providers).map((g) => html`<${CompactGroup} key=${g.base} group=${g}
|
|
350
|
+
line=${({ p, i }) => (expanded.has(key(p)) ? card(p, i) : html`<${CompactRow} key=${key(p)} p=${p} onExpand=${() => toggleOne(key(p))} />`)} />`)
|
|
351
|
+
: providers.map((p, i) => card(p, i))}
|
|
352
|
+
<div class="u-foot"><span class="note" title=${new Date(data.fetchedAt).toLocaleString()}>${updatedAgo(data.fetchedAt)}${failed ? html` · <span class="u-refresh-failed" role="status">${tn("usageRefreshFailed")}</span>` : data.refreshing ? html` · <span class="u-refreshing">${tn("usageRefreshing")}</span>` : null}</span>
|
|
163
353
|
${byAgent() ? html`<a class="btn btn-ghost btn-sm u-by-agent" href="/ui/fleet/usage" title=${tn("usageByAgentTitle")}>${tn("usageByAgent")}</a>` : null}
|
|
164
354
|
<button type="button" class="btn btn-sm" onClick=${() => load(true)}>${tn("usageRefresh")}</button></div>`;
|
|
165
355
|
}
|
|
@@ -174,5 +364,5 @@ const byAgent = () => !guestPage() && typeof location !== "undefined" && locatio
|
|
|
174
364
|
|
|
175
365
|
/** `owner`: the navigation that opened it — its reads and the minute's timer live and end with it. */
|
|
176
366
|
export function UsageDialog({ onClose, owner = "" }) {
|
|
177
|
-
return html`<${Dialog} title=${tn("usage.title")} onClose=${onClose} wide=${true}><${UsageBody} owner=${`usage-dialog:${owner}`} /></${Dialog}>`;
|
|
367
|
+
return html`<${Dialog} title=${tn("usage.title")} tools=${html`<${UsageCompactToggle} />`} onClose=${onClose} wide=${true}><${UsageBody} owner=${`usage-dialog:${owner}`} /></${Dialog}>`;
|
|
178
368
|
}
|
|
@@ -37,6 +37,7 @@ register("view", {
|
|
|
37
37
|
"usageUpdatedAgo": "Updated {age} ago",
|
|
38
38
|
"usageUpdatedJustNow": "Updated just now",
|
|
39
39
|
"usageRefreshing": "Refreshing…",
|
|
40
|
+
"usageRefreshFailed": "Couldn't refresh — showing the last numbers",
|
|
40
41
|
"usageMinutes": "{n} min",
|
|
41
42
|
"usageHours": "{n} h",
|
|
42
43
|
"usageRefresh": "Refresh",
|
|
@@ -46,6 +47,16 @@ register("view", {
|
|
|
46
47
|
"usageNear": "near limit",
|
|
47
48
|
"usageMoveUp": "Move up",
|
|
48
49
|
"usageMoveDown": "Move down",
|
|
50
|
+
"usageCompact": "Compact",
|
|
51
|
+
"usageCompactTitle": "One line per login",
|
|
52
|
+
"usageFull": "Full",
|
|
53
|
+
"usageFullTitle": "The full card for each login",
|
|
54
|
+
"usageExpand": "Show the full card",
|
|
55
|
+
"usageCollapse": "Back to one line",
|
|
56
|
+
"usageWindowHours": "{n}h",
|
|
57
|
+
"usageWindowDays": "{n}d",
|
|
58
|
+
"usageWindowMinutes": "{n}m",
|
|
59
|
+
"usageStaleMark": "Not current",
|
|
49
60
|
"tooltipBackend": "Backend: {value}",
|
|
50
61
|
"tooltipStatus": "Status: {value}",
|
|
51
62
|
"tooltipContext": "Context: {value}",
|
|
@@ -61,6 +72,8 @@ register("view", {
|
|
|
61
72
|
"modelWhyStart": "detected when it starts",
|
|
62
73
|
"modelWhyCli": "this CLI does not report a default",
|
|
63
74
|
"groupOther": "Other",
|
|
75
|
+
"groupTeam": "Team",
|
|
76
|
+
"groupTag": "Tag",
|
|
64
77
|
"statusRunning": "Running",
|
|
65
78
|
"statusPaused": "Paused",
|
|
66
79
|
"statusStopped": "Stopped",
|
|
@@ -73,6 +86,7 @@ register("view", {
|
|
|
73
86
|
"usage.title_plain": "AI subscription usage",
|
|
74
87
|
"usage.empty_active": "No active backends with usage tracking",
|
|
75
88
|
"usage.not_logged_in": "not logged in",
|
|
89
|
+
"usage.default_login": "default",
|
|
76
90
|
"usage.error_fallback": "error",
|
|
77
91
|
"usage.no_data": "no data",
|
|
78
92
|
"usage.reset.in": "resets in {0}",
|
|
@@ -135,6 +149,10 @@ register("view", {
|
|
|
135
149
|
"usage.error.rate_limited": "Rate limited by {0} — try again later.",
|
|
136
150
|
"usage.error.rate_limited_transient": "{0}: can't fetch usage right now (rate limited). This does not affect your agents.",
|
|
137
151
|
"usage.stale_rate_limited": "data from {0} min ago — can't refresh right now",
|
|
152
|
+
"usage.stale.expired": "expired · cached at {0}",
|
|
153
|
+
"usage.stale.transient": "not updated · cached at {0}",
|
|
154
|
+
"usage.stale.error": "couldn't read · cached at {0}",
|
|
155
|
+
"usage.metric.reset_since": "reset since {0}",
|
|
138
156
|
"usage.error.http": "Usage request failed (HTTP {0}).",
|
|
139
157
|
"usage.error.billing_http": "Billing request failed (HTTP {0}).",
|
|
140
158
|
"usage.error.invalid_response": "Invalid response from usage endpoint.",
|
|
@@ -157,7 +175,6 @@ register("view", {
|
|
|
157
175
|
"usageButton": "Usage",
|
|
158
176
|
"helpButton": "Help",
|
|
159
177
|
"close": "Close",
|
|
160
|
-
"expandProfile": "Show the profile",
|
|
161
178
|
"rosterFailed": "Failed to load roster: {error}\n(Is the fleet running?)",
|
|
162
179
|
"paneFailed": "⚠ Could not load pane for {name} (HTTP {status}).",
|
|
163
180
|
"signInToSave": "Sign in to save — your session may have ended.",
|
|
@@ -200,7 +217,6 @@ register("view", {
|
|
|
200
217
|
"textSize": "Text size: {size}",
|
|
201
218
|
"profileTitle": "Edit {name}'s profile",
|
|
202
219
|
"avatar": "Avatar",
|
|
203
|
-
"collapseProfile": "Hide the profile",
|
|
204
220
|
"instancesLabel": "Instances",
|
|
205
221
|
"favorites": "Favorites",
|
|
206
222
|
"favAdd": "Add {name} to favorites",
|
|
@@ -211,6 +227,22 @@ register("view", {
|
|
|
211
227
|
"favDown": "Move {name} down",
|
|
212
228
|
"favFull": "Favorites are full ({max})",
|
|
213
229
|
"favFiltered": "Clear the filter to reorder favorites",
|
|
230
|
+
"favSorted": "Favorites are sorted by last reply — set them back to your order to move them",
|
|
231
|
+
"replyJustNow": "just now",
|
|
232
|
+
"replyMinutes": "{n} min ago",
|
|
233
|
+
"replyHours": "{n} h ago",
|
|
234
|
+
"replyYesterday": "yesterday",
|
|
235
|
+
"replyDays": "{n} d ago",
|
|
236
|
+
"replyTitle": "Last replied: {time}",
|
|
237
|
+
"sortTitle": "Sort the list",
|
|
238
|
+
"sortCustom": "Custom",
|
|
239
|
+
"sortCustomHint": "Your own order (drag rows); replies never move them",
|
|
240
|
+
"sortRecent": "Recent replies",
|
|
241
|
+
"sortRecentHint": "No groups: the last reply first",
|
|
242
|
+
"sortFavs": "Favorites, in Recent replies",
|
|
243
|
+
"sortFavsFixed": "Pinned on top, in your order",
|
|
244
|
+
"sortFavsRecent": "Sorted by last reply too",
|
|
245
|
+
"recentOthers": "Recent replies first",
|
|
214
246
|
"pinnedCurrent": "Current",
|
|
215
247
|
"pinnedLabel": "The instance you have open"
|
|
216
248
|
},
|
|
@@ -247,6 +279,7 @@ register("view", {
|
|
|
247
279
|
"usageUpdatedAgo": "{age}前更新",
|
|
248
280
|
"usageUpdatedJustNow": "剛剛更新",
|
|
249
281
|
"usageRefreshing": "更新中…",
|
|
282
|
+
"usageRefreshFailed": "無法更新,顯示上次的數據",
|
|
250
283
|
"usageMinutes": "{n} 分鐘",
|
|
251
284
|
"usageHours": "{n} 小時",
|
|
252
285
|
"usageRefresh": "重新整理",
|
|
@@ -256,6 +289,16 @@ register("view", {
|
|
|
256
289
|
"usageNear": "接近上限",
|
|
257
290
|
"usageMoveUp": "上移",
|
|
258
291
|
"usageMoveDown": "下移",
|
|
292
|
+
"usageCompact": "精簡",
|
|
293
|
+
"usageCompactTitle": "每個登入一行",
|
|
294
|
+
"usageFull": "完整",
|
|
295
|
+
"usageFullTitle": "每個登入顯示完整卡片",
|
|
296
|
+
"usageExpand": "顯示完整卡片",
|
|
297
|
+
"usageCollapse": "收回成一行",
|
|
298
|
+
"usageWindowHours": "{n}小時",
|
|
299
|
+
"usageWindowDays": "{n}天",
|
|
300
|
+
"usageWindowMinutes": "{n}分",
|
|
301
|
+
"usageStaleMark": "不是最新",
|
|
259
302
|
"tooltipBackend": "後端:{value}",
|
|
260
303
|
"tooltipStatus": "狀態:{value}",
|
|
261
304
|
"tooltipContext": "上下文:{value}",
|
|
@@ -271,6 +314,8 @@ register("view", {
|
|
|
271
314
|
"modelWhyStart": "啟動時偵測",
|
|
272
315
|
"modelWhyCli": "這個 CLI 不提供預設值",
|
|
273
316
|
"groupOther": "其他",
|
|
317
|
+
"groupTeam": "團隊",
|
|
318
|
+
"groupTag": "標籤",
|
|
274
319
|
"statusRunning": "運行中",
|
|
275
320
|
"statusPaused": "已暫停",
|
|
276
321
|
"statusStopped": "已停止",
|
|
@@ -283,6 +328,7 @@ register("view", {
|
|
|
283
328
|
"usage.title_plain": "AI 訂閱用量",
|
|
284
329
|
"usage.empty_active": "沒有使用中且支援用量追蹤的 Backend",
|
|
285
330
|
"usage.not_logged_in": "未登入",
|
|
331
|
+
"usage.default_login": "預設",
|
|
286
332
|
"usage.error_fallback": "錯誤",
|
|
287
333
|
"usage.no_data": "無資料",
|
|
288
334
|
"usage.reset.in": "{0} 後重置",
|
|
@@ -345,6 +391,10 @@ register("view", {
|
|
|
345
391
|
"usage.error.rate_limited": "{0} 暫時限制請求速率,請稍後再試。",
|
|
346
392
|
"usage.error.rate_limited_transient": "暫時查不到 {0} 用量({0} 限制查詢頻率),不影響你的 agent。",
|
|
347
393
|
"usage.stale_rate_limited": "{0} 分鐘前的資料,暫時無法更新",
|
|
394
|
+
"usage.stale.expired": "已過期 · 快取於 {0}",
|
|
395
|
+
"usage.stale.transient": "暫時無法更新 · 快取於 {0}",
|
|
396
|
+
"usage.stale.error": "讀取失敗 · 快取於 {0}",
|
|
397
|
+
"usage.metric.reset_since": "已於 {0} 重置",
|
|
348
398
|
"usage.error.http": "用量請求失敗(HTTP {0})。",
|
|
349
399
|
"usage.error.billing_http": "計費請求失敗(HTTP {0})。",
|
|
350
400
|
"usage.error.invalid_response": "用量端點回傳了無效資料。",
|
|
@@ -367,7 +417,6 @@ register("view", {
|
|
|
367
417
|
"usageButton": "用量",
|
|
368
418
|
"helpButton": "說明",
|
|
369
419
|
"close": "關閉",
|
|
370
|
-
"expandProfile": "顯示個人資料",
|
|
371
420
|
"rosterFailed": "載入 instance 清單失敗:{error}\n(Fleet 是否正在執行?)",
|
|
372
421
|
"paneFailed": "⚠ 無法載入 {name} 的 pane(HTTP {status})。",
|
|
373
422
|
"signInToSave": "請先登入才能儲存:你的 session 可能已結束。",
|
|
@@ -410,7 +459,6 @@ register("view", {
|
|
|
410
459
|
"textSize": "字級:{size}",
|
|
411
460
|
"profileTitle": "編輯 {name} 的個人資料",
|
|
412
461
|
"avatar": "頭像",
|
|
413
|
-
"collapseProfile": "隱藏個人資料",
|
|
414
462
|
"instancesLabel": "Instances",
|
|
415
463
|
"favorites": "最愛",
|
|
416
464
|
"favAdd": "把 {name} 加入最愛",
|
|
@@ -421,6 +469,22 @@ register("view", {
|
|
|
421
469
|
"favDown": "把 {name} 下移",
|
|
422
470
|
"favFull": "最愛已滿({max} 個)",
|
|
423
471
|
"favFiltered": "清除篩選後才能調整最愛順序",
|
|
472
|
+
"favSorted": "最愛目前依最近回覆排序;改回「照你的順序」才能移動",
|
|
473
|
+
"replyJustNow": "剛剛",
|
|
474
|
+
"replyMinutes": "{n} 分鐘前",
|
|
475
|
+
"replyHours": "{n} 小時前",
|
|
476
|
+
"replyYesterday": "昨天",
|
|
477
|
+
"replyDays": "{n} 天前",
|
|
478
|
+
"replyTitle": "最後回覆:{time}",
|
|
479
|
+
"sortTitle": "排序方式",
|
|
480
|
+
"sortCustom": "自訂",
|
|
481
|
+
"sortCustomHint": "你拖曳排好的順序,有回覆也不會跳動",
|
|
482
|
+
"sortRecent": "最近回覆",
|
|
483
|
+
"sortRecentHint": "不分組,最後回覆的在上面",
|
|
484
|
+
"sortFavs": "最愛(最近回覆模式時)",
|
|
485
|
+
"sortFavsFixed": "固定在最上面,照你的順序",
|
|
486
|
+
"sortFavsRecent": "也依最近回覆排序",
|
|
487
|
+
"recentOthers": "最近回覆在上",
|
|
424
488
|
"pinnedCurrent": "目前",
|
|
425
489
|
"pinnedLabel": "你目前開著的 instance"
|
|
426
490
|
}
|
|
@@ -20,6 +20,7 @@ register("webauth", {
|
|
|
20
20
|
reason_not_admin_session: "Guests can't authorize.",
|
|
21
21
|
reason_token_rotated: "The dashboard's token changed: sign in again.",
|
|
22
22
|
reason_public_link: "Not on the temporary public link.",
|
|
23
|
+
reason_named_link_off: "Over your named link: turn on \"Also over my named link\" in Settings → Web on this computer.",
|
|
23
24
|
reason_not_session: "Sign in to authorize.",
|
|
24
25
|
reason_other: "This browser can't be authorized here.",
|
|
25
26
|
refusal_pending: "A request is already waiting in your DM.",
|
|
@@ -27,6 +28,10 @@ register("webauth", {
|
|
|
27
28
|
refusal_dm_unavailable: "Couldn't send you a DM. Open your DMs with the bot, then try again.",
|
|
28
29
|
refusal_other: "That didn't work: {0}",
|
|
29
30
|
settings: "Settings",
|
|
31
|
+
verifiedShort: "Verified",
|
|
32
|
+
authorizeShort: "Authorize",
|
|
33
|
+
authorizeWhy: "Not verified: authorize this browser to speak as you",
|
|
34
|
+
waitingShort: "Waiting for your Confirm ({0})",
|
|
30
35
|
},
|
|
31
36
|
"zh-TW": {
|
|
32
37
|
verified: "已驗證 · 以你的身分發言到 {0}",
|
|
@@ -42,6 +47,7 @@ register("webauth", {
|
|
|
42
47
|
reason_not_admin_session: "訪客無法授權。",
|
|
43
48
|
reason_token_rotated: "儀表板的 token 已變更:請重新登入。",
|
|
44
49
|
reason_public_link: "臨時公開連結上無法授權。",
|
|
50
|
+
reason_named_link_off: "透過固定網域:請在這台電腦的 設定 → 網頁 開啟「也允許透過我的固定網域」。",
|
|
45
51
|
reason_not_session: "登入後才能授權。",
|
|
46
52
|
reason_other: "這個瀏覽器在這裡無法授權。",
|
|
47
53
|
refusal_pending: "已經有一個請求在你的私訊中等待。",
|
|
@@ -49,10 +55,14 @@ register("webauth", {
|
|
|
49
55
|
refusal_dm_unavailable: "無法私訊給你。請開放與 bot 的私訊後再試一次。",
|
|
50
56
|
refusal_other: "沒有成功:{0}",
|
|
51
57
|
settings: "設定",
|
|
58
|
+
verifiedShort: "已驗證",
|
|
59
|
+
authorizeShort: "授權",
|
|
60
|
+
authorizeWhy: "未驗證:授權這個瀏覽器以你的身分發言",
|
|
61
|
+
waitingShort: "等待確認({0})",
|
|
52
62
|
},
|
|
53
63
|
});
|
|
54
64
|
const tn = (k, ...v) => t(`webauth.${k}`, ...v);
|
|
55
|
-
const REASONS = ["disabled", "loopback_only", "no_account", "not_admin", "not_admin_session", "token_rotated", "public_link", "not_session"];
|
|
65
|
+
const REASONS = ["disabled", "loopback_only", "no_account", "not_admin", "not_admin_session", "token_rotated", "public_link", "named_link_off", "not_session"];
|
|
56
66
|
// Until when: the time, with the day when it isn't today (an authorization lasts up to 48 h).
|
|
57
67
|
const clock = (ms) => {
|
|
58
68
|
const d = new Date(ms), today = new Date().toDateString() === d.toDateString();
|
|
@@ -139,6 +149,45 @@ export function AuthorizeChip() {
|
|
|
139
149
|
return html`<div class="webauth-chip" data-state=${a.st.state}>${body(a)}${a.notice ? html` <span class="note" role="status">${a.notice}</span>` : null}</div>`;
|
|
140
150
|
}
|
|
141
151
|
|
|
152
|
+
/**
|
|
153
|
+
* The composer's row (#2215, the user's request, 2026-10-19): the same states as AuthorizeChip, each kept to a few words so
|
|
154
|
+
* they share one row with the key hint. What a state would have said at length is in its tooltip and its accessible
|
|
155
|
+
* name: when "Verified" ends, why it can't be authorized, the countdown's ask. A tap on "✓ Verified" shows when it
|
|
156
|
+
* ends (touch has no hover) in a bubble above the row, until the next tap, a tap elsewhere or Escape. What pressing
|
|
157
|
+
* Authorize answered (sent, refused) is said in the row itself, in the hint's place (#2216 review: a bubble left over the
|
|
158
|
+
* composer covered Attach and what was being typed, with nothing to close it).
|
|
159
|
+
*/
|
|
160
|
+
export function ComposerAuth() {
|
|
161
|
+
const a = useWebAuthorization();
|
|
162
|
+
const [open, setOpen] = useState(false);
|
|
163
|
+
const tip = useRef("wa-tip-" + Math.random().toString(36).slice(2, 8));
|
|
164
|
+
useEffect(() => { setOpen(false); }, [a.st && a.st.state]); // a new state closes the bubble
|
|
165
|
+
if (guestPage()) return null;
|
|
166
|
+
if (publicLink()) return html`<span class="webauth-row note" data-state="public" title=${tn("publicLink")}>${tn("publicLink")}</span>`;
|
|
167
|
+
if (!a.st) return null;
|
|
168
|
+
const st = a.st, id = tip.current;
|
|
169
|
+
const said = a.notice ? html`<span class="webauth-notice" role="status">${a.notice}</span>` : null;
|
|
170
|
+
if (st.state === "verified") {
|
|
171
|
+
const until = tn("verified", clock(st.until));
|
|
172
|
+
return html`<span class="webauth-row" data-state="verified">
|
|
173
|
+
<button type="button" class="webauth-ok" title=${until} aria-label=${`✓ ${until}`} aria-expanded=${open ? "true" : "false"}
|
|
174
|
+
aria-controls=${id} onClick=${() => setOpen((v) => !v)} onBlur=${() => setOpen(false)}
|
|
175
|
+
onKeyDown=${(e) => { if (e.key === "Escape" && open) { e.stopPropagation(); setOpen(false); } }}>✓ ${tn("verifiedShort")}</button><span
|
|
176
|
+
id=${id} class="webauth-tip" role="tooltip" hidden=${!open}>${until}</span>${said}</span>`;
|
|
177
|
+
}
|
|
178
|
+
if (st.state === "pending") {
|
|
179
|
+
const asks = tn("waiting", mmss(a.left));
|
|
180
|
+
return html`<span class="webauth-row" data-state="pending"><span class="note" title=${a.notice ? `${asks} — ${a.notice}` : asks}>${tn("waitingShort", mmss(a.left))}</span>${said}</span>`;
|
|
181
|
+
}
|
|
182
|
+
if (st.reason === "not_authorized" || st.reason === "authorization_expired") {
|
|
183
|
+
return html`<span class="webauth-row" data-state="none"><span class="note" aria-hidden="true">${tn("notVerified")} ·</span><button type="button" class="webauth-ask"
|
|
184
|
+
title=${tn("authorizeWhy")} aria-label=${tn("authorizeWhy")} onClick=${a.ask}>${tn("authorizeShort")}</button>${said}</span>`;
|
|
185
|
+
}
|
|
186
|
+
const why = REASONS.includes(st.reason) ? tn(`reason_${st.reason}`) : tn("reason_other");
|
|
187
|
+
return html`<span class="webauth-row" data-state="none"><span class="note" title=${why}>${tn("notVerified")}<span class="sr-only">: ${why}</span></span>${st.reason === "disabled" || st.reason === "loopback_only"
|
|
188
|
+
? html` · <a href="/settings/web" title=${why}>${tn("settings")}</a>` : null}</span>`;
|
|
189
|
+
}
|
|
190
|
+
|
|
142
191
|
function body(a) {
|
|
143
192
|
const st = a.st;
|
|
144
193
|
if (st.state === "verified") return html`<span class="webauth-ok">✓ ${tn("verified", clock(st.until))}</span>`;
|
package/dist/ui/signin.html
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
<meta name="referrer" content="no-referrer">
|
|
7
7
|
<meta name="robots" content="noindex">
|
|
8
8
|
<title>AgEnD — Sign in</title>
|
|
9
|
+
<!--app-icon-->
|
|
9
10
|
<link rel="icon" href="/favicon.ico" sizes="16x16 32x32 64x64">
|
|
10
11
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" sizes="any">
|
|
11
12
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
|
|
13
|
+
<!--/app-icon-->
|
|
12
14
|
<script src="/assets/theme.js"></script>
|
|
13
15
|
<link rel="stylesheet" href="/assets/tokens.css">
|
|
14
16
|
<style>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
html, body { margin: 0; height: 100%; background: #111; color: #ddd; font: 14px system-ui, sans-serif; }
|
|
1
|
+
html, body { margin: 0; height: 100%; background: #111; color: #ddd; font: 14px system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", emoji; }
|
|
2
2
|
body { display: flex; flex-direction: column; }
|
|
3
3
|
#bar { display: flex; align-items: center; gap: 12px; padding: 6px 10px; background: #1c1c1c; border-bottom: 1px solid #333; }
|
|
4
4
|
#bar #title { font-weight: 600; }
|
|
@@ -6,18 +6,18 @@ body { display: flex; flex-direction: column; }
|
|
|
6
6
|
#bar button { background: #402; color: #fbb; border: 1px solid #733; border-radius: 4px; padding: 3px 10px; cursor: pointer; }
|
|
7
7
|
#gate { max-width: 560px; margin: 40px auto; padding: 0 16px; line-height: 1.5; }
|
|
8
8
|
#gate form { display: flex; gap: 8px; margin-top: 12px; }
|
|
9
|
-
#gate input { flex: 1; font: 16px ui-monospace, monospace; letter-spacing: 1px; padding: 8px; background: #000; color: #fff; border: 1px solid #555; border-radius: 4px; }
|
|
9
|
+
#gate input { flex: 1; font: 16px ui-monospace, monospace, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", emoji; letter-spacing: 1px; padding: 8px; background: #000; color: #fff; border: 1px solid #555; border-radius: 4px; }
|
|
10
10
|
#gate button { padding: 8px 16px; background: #246; color: #fff; border: 0; border-radius: 4px; cursor: pointer; }
|
|
11
11
|
#gate-msg { color: #f88; min-height: 1.5em; }
|
|
12
12
|
#term { flex: 1; min-height: 0; padding: 4px; overflow: hidden; } /* never drawn over the rows below it (#1242) */
|
|
13
13
|
#code-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px 10px; background: #1c1c1c; border-top: 1px solid #333; }
|
|
14
14
|
#code-row[hidden] { display: none; }
|
|
15
|
-
#code-row input { flex: 1; min-width: 12em; font: 16px ui-monospace, monospace; padding: 8px; background: #000; color: #fff; border: 1px solid #555; border-radius: 4px; }
|
|
15
|
+
#code-row input { flex: 1; min-width: 12em; font: 16px ui-monospace, monospace, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", emoji; padding: 8px; background: #000; color: #fff; border: 1px solid #555; border-radius: 4px; }
|
|
16
16
|
#code-row button { padding: 8px 16px; background: #246; color: #fff; border: 0; border-radius: 4px; cursor: pointer; }
|
|
17
17
|
#code-msg { color: #9ad; min-height: 1.2em; }
|
|
18
18
|
#code-hint { flex-basis: 100%; margin: 0; color: #aaa; font-size: 13px; }
|
|
19
19
|
#keys { display: flex; flex-wrap: wrap; gap: 6px; padding: 6px; background: #1c1c1c; border-top: 1px solid #333; }
|
|
20
|
-
#keys button { background: #222; color: #ddd; border: 1px solid #444; border-radius: 4px; padding: 6px 10px; font: 14px ui-monospace, monospace; cursor: pointer; }
|
|
20
|
+
#keys button { background: #222; color: #ddd; border: 1px solid #444; border-radius: 4px; padding: 6px 10px; font: 14px ui-monospace, monospace, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", emoji; cursor: pointer; }
|
|
21
21
|
#done { padding: 10px; background: #1c1c1c; border-top: 1px solid #333; }
|
|
22
22
|
#done.ok { color: #8d8; } #done.bad { color: #f88; }
|
|
23
23
|
@media (min-width: 900px) { #keys { display: none; } }
|