@songsid/agend 2.3.0-beta.9 → 2.3.1
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 +7 -1
- package/dist/agent-cli.js +41 -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 +53 -12
- 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.d.ts +20 -2
- package/dist/backend/muse.js +154 -16
- 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 +7 -1
- package/dist/channel/adapters/telegram.js +57 -49
- 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 +41 -4
- 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 +448 -313
- 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 +52 -1
- package/dist/daemon.js +385 -27
- 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.js.map +1 -1
- package/dist/delivery-consumed-watch.js.map +1 -1
- package/dist/delivery-outbox.d.ts +11 -0
- package/dist/delivery-outbox.js +52 -2
- 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-context.d.ts +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.d.ts +6 -0
- package/dist/fleet-lock.js +22 -2
- package/dist/fleet-lock.js.map +1 -1
- package/dist/fleet-manager.d.ts +283 -15
- package/dist/fleet-manager.js +1825 -331
- 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.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/instance-lifecycle/SKILL.md +11 -0
- 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 +24 -4
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +554 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +156 -32
- 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 +11 -1
- package/dist/instance-lifecycle.js +97 -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 +450 -20
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +1 -0
- 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 +39 -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 +5 -2
- package/dist/outbound-handlers.js +81 -24
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +106 -60
- package/dist/outbound-schemas.js +33 -10
- 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 +149 -0
- package/dist/search/search-index.js +453 -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 +98 -1
- package/dist/service-installer.js +246 -11
- 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-stop.d.ts +45 -0
- package/dist/session-oom-stop.js +259 -0
- package/dist/session-oom-stop.js.map +1 -0
- package/dist/session-oom.d.ts +34 -0
- package/dist/session-oom.js +251 -0
- package/dist/session-oom.js.map +1 -0
- package/dist/settings-api.d.ts +14 -1
- package/dist/settings-api.js +74 -13
- 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 +7 -0
- package/dist/spawn-gate.js +45 -12
- package/dist/spawn-gate.js.map +1 -1
- package/dist/start-attempt.d.ts +11 -0
- package/dist/start-attempt.js +29 -0
- package/dist/start-attempt.js.map +1 -0
- package/dist/start-failure-chat.d.ts +37 -0
- package/dist/start-failure-chat.js +142 -0
- package/dist/start-failure-chat.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 +171 -0
- package/dist/start-failure.js +348 -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/telegram-api-root.d.ts +1 -0
- package/dist/telegram-api-root.js +40 -0
- package/dist/telegram-api-root.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.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 +56 -2
- package/dist/ui/app-effects.js +23 -5
- package/dist/ui/app.html +2 -0
- package/dist/ui/backend-signin.js +297 -0
- package/dist/ui/chat-effects.js +10 -3
- package/dist/ui/chat-msg-actions.js +176 -0
- package/dist/ui/chat-render.js +62 -18
- package/dist/ui/chat-store.js +218 -48
- package/dist/ui/chat-strings.js +40 -8
- package/dist/ui/chat-thread.js +119 -10
- 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 +69 -28
- 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 +18 -5
- 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 +81 -18
- 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 +214 -57
- package/dist/ui/panel-details.js +2 -0
- package/dist/ui/panel-fleet.js +32 -71
- package/dist/ui/panel-log.js +3 -3
- package/dist/ui/panel-needs.js +23 -6
- package/dist/ui/panel-settings.js +166 -33
- 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 +186 -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 +2 -0
- 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 +189 -28
- package/dist/ui/shared/app-store.js +3 -2
- package/dist/ui/shared/app-stream.js +5 -1
- package/dist/ui/shared/app-themes.js +116 -1
- package/dist/ui/shared/app.css +668 -48
- 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-registry.js +14 -4
- package/dist/ui/shared/effect-runtime-loader.js +3 -1
- package/dist/ui/shared/effect-stock-trust.js +5 -5
- 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 +4 -0
- 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 +216 -16
- package/dist/ui/shared/view-strings.js +70 -4
- package/dist/ui/shared/web-authorize.js +50 -1
- package/dist/ui/signin.html +2 -0
- 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.map +1 -1
- package/dist/web-api.d.ts +58 -11
- 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 +3 -0
- package/dist/working-state-journal.d.ts +68 -0
- package/dist/working-state-journal.js +93 -0
- package/dist/working-state-journal.js.map +1 -0
- 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
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// #2481: first — counts a `fleet start` attempt before anything below can fail (start-failure.ts).
|
|
3
|
+
import "./start-attempt.js";
|
|
2
4
|
import "./node-warnings.js";
|
|
5
|
+
import { installFleetProcessHandlers } from "./fleet-process-handlers.js";
|
|
3
6
|
import { applyNetworkReliabilityDefaults } from "./network-family.js";
|
|
4
7
|
// Preserve Node's dual-stack Happy Eyeballs behavior, but avoid its 250ms
|
|
5
8
|
// premature-connect failure on WSL/VPN/high-load hosts (#658).
|
|
@@ -12,32 +15,37 @@ applyNetworkReliabilityDefaults();
|
|
|
12
15
|
// never restarts into a binary that would crash at the first native DB open.
|
|
13
16
|
import { checkNodeVersion } from "./node-version-guard.js";
|
|
14
17
|
checkNodeVersion();
|
|
15
|
-
import { Command } from "commander";
|
|
18
|
+
import { Command, Option } from "commander";
|
|
19
|
+
import { registerBugReportCommand } from "./bug-report-cli.js";
|
|
16
20
|
import { join, dirname } from "node:path";
|
|
17
21
|
import { SchedulerDb } from "./scheduler/db.js";
|
|
18
22
|
import { Cron } from "croner";
|
|
19
23
|
import { existsSync, readFileSync, writeFileSync, appendFileSync, unlinkSync, mkdirSync, chmodSync, readdirSync, rmSync, statSync, realpathSync, openSync, writeSync, closeSync, } from "node:fs";
|
|
20
24
|
import { homedir, totalmem, freemem, userInfo } from "node:os";
|
|
21
25
|
import { fileURLToPath } from "node:url";
|
|
22
|
-
import {
|
|
26
|
+
import { spawnSync, execSync, execFileSync } from "node:child_process";
|
|
27
|
+
import { spawn } from "./child-process.js";
|
|
23
28
|
import { getAgendHome, getTmuxSocketName, isDefaultAgendHome } from "./paths.js";
|
|
24
29
|
import { hasPausedMarker } from "./pause-marker.js";
|
|
25
30
|
import { COMPLETION_SHELLS, completionScript } from "./completion.js";
|
|
26
31
|
import { getUpdateSelector, isExactVersion, isUnrequestedDowngrade, lookupTargetVersion, reportUpdateRestart, shouldSkipUpdate, runningFleetPredatesInstall, fleetProvenStopped, readFleetPidEvidence, pidAlive, processStartMs, } from "./update-check.js";
|
|
27
|
-
import { clearUpdateMarker, markUpdateInProgress, setUpdateProgressStage } from "./update-marker.js";
|
|
32
|
+
import { clearUpdateMarker, markUpdateInProgress, readUpdateProgress, setUpdateProgressStage } from "./update-marker.js";
|
|
28
33
|
import { describeSignalSource, forceAllowed, gateFleetControl, recordInstanceControl, withOrigin } from "./fleet-control-audit.js";
|
|
29
34
|
import { FLEET_STOP_TIMEOUT_MS, stopDetachedOwner, systemdStopTimeoutMs, detachedProcessStart, detachedProcessExited } from "./fleet-stop-budget.js";
|
|
30
35
|
import { acquireFleetLock, isFleetStartCommandLine, readProcessCommandLine, releaseProcessFleetLock, setProcessFleetLock } from "./fleet-lock.js";
|
|
31
36
|
import { limitFleetCoreDumps } from "./coredump-filter.js";
|
|
32
|
-
import { SYSTEMD_RESTART_TIMEOUT_MS } from "./service-installer.js";
|
|
37
|
+
import { SYSTEMD_RESTART_TIMEOUT_MS, getServicePath, getSystemServicePath } from "./service-installer.js";
|
|
38
|
+
import { withFsPlanLock } from "./service-plan.js";
|
|
33
39
|
import { selectSystemdRestartTarget, SYSTEMD_RESTART_INDETERMINATE_EXIT_CODE, } from "./service-restart-selection.js";
|
|
34
40
|
import { loadRawFleetConfig } from "./config.js";
|
|
35
|
-
import { setLocale, t } from "./locale.js";
|
|
41
|
+
import { detectLocale, setLocale, t } from "./locale.js";
|
|
42
|
+
import { settingsSourceLabel } from "./settings-confirmation.js";
|
|
36
43
|
import { DeliveryOutbox, deliveryStatusSelector } from "./delivery-outbox.js";
|
|
37
44
|
import { DeliveryStatusArgs } from "./outbound-schemas.js";
|
|
38
45
|
import { requestCpuProfile } from "./profile-control.js";
|
|
39
46
|
import { requestSettingsConfirmation } from "./settings-control.js";
|
|
40
47
|
import { canonicalCliEntry, selfCommand } from "./cli-entry.js";
|
|
48
|
+
import { DIRECT_FLEET_START_ENV, redirectsToService, startedByServiceManager } from "./service-owner.js";
|
|
41
49
|
import { handOff, shouldHandOff } from "./launchd-handoff.js";
|
|
42
50
|
/** Prefix tmux args with -L when socket isolation is active. */
|
|
43
51
|
function tmuxArgs(args) {
|
|
@@ -65,6 +73,7 @@ function planDeps() {
|
|
|
65
73
|
unlinkSync(path);
|
|
66
74
|
}
|
|
67
75
|
catch { /* absent */ } },
|
|
76
|
+
withPlanLock: (fn) => withFsPlanLock(DATA_DIR, fn),
|
|
68
77
|
realpath: (path) => { try {
|
|
69
78
|
return realpathSync(path);
|
|
70
79
|
}
|
|
@@ -103,15 +112,38 @@ async function handOffLaunchdActivation(action) {
|
|
|
103
112
|
return false;
|
|
104
113
|
}
|
|
105
114
|
const FLEET_CONFIG_PATH = join(DATA_DIR, "fleet.yaml");
|
|
106
|
-
// CLI commands run outside FleetManager
|
|
107
|
-
//
|
|
115
|
+
// CLI commands run outside FleetManager, in the fleet's language as the fleet decides it (#2390 follow-up): an explicit
|
|
116
|
+
// defaults.locale, else the host's zone (UTC+8 → zh-TW), else English. A line another program reads (the updater, the
|
|
117
|
+
// Windows installer and shortcuts, the rehearsal scripts) is never a locale string: tests/cli-machine-lines-2390 pins them.
|
|
118
|
+
let configForLocale;
|
|
108
119
|
try {
|
|
109
|
-
|
|
110
|
-
if (configuredLocale === "en" || configuredLocale === "zh-TW")
|
|
111
|
-
setLocale(configuredLocale);
|
|
120
|
+
configForLocale = loadRawFleetConfig(FLEET_CONFIG_PATH);
|
|
112
121
|
}
|
|
113
|
-
catch { /* malformed or missing config:
|
|
122
|
+
catch { /* malformed or missing config: the zone decides */ }
|
|
123
|
+
setLocale(detectLocale(configForLocale));
|
|
114
124
|
const program = new Command();
|
|
125
|
+
/**
|
|
126
|
+
* #2481: an installed version whose fleet keeps failing to start is said on every command, with what to run to go back.
|
|
127
|
+
* Not for the fleet process itself (its own `fleet start`/`stop`, whose output is the service's log), completion, or
|
|
128
|
+
* machine output (--json); free once the installed version has started here (start-failure.ts).
|
|
129
|
+
*/
|
|
130
|
+
const NO_START_BANNER = new Set(["fleet", "completion", "web-token", "health"]);
|
|
131
|
+
program.hook("preAction", async (_hooked, action) => {
|
|
132
|
+
let top = action;
|
|
133
|
+
while (top.parent && top.parent !== program)
|
|
134
|
+
top = top.parent;
|
|
135
|
+
if (NO_START_BANNER.has(top.name()) || action.opts().json)
|
|
136
|
+
return;
|
|
137
|
+
try {
|
|
138
|
+
const { checkStartFailure } = await import("./start-failure.js");
|
|
139
|
+
const failure = checkStartFailure(DATA_DIR);
|
|
140
|
+
if (!failure.failing)
|
|
141
|
+
return;
|
|
142
|
+
const { startFailureLines } = await import("./start-failure-notice.js");
|
|
143
|
+
console.error(["", ...startFailureLines(failure, DATA_DIR), ""].join("\n"));
|
|
144
|
+
}
|
|
145
|
+
catch { /* the banner never stands in a command's way */ }
|
|
146
|
+
});
|
|
115
147
|
function claimFleetSingleton() {
|
|
116
148
|
try {
|
|
117
149
|
setProcessFleetLock(acquireFleetLock(DATA_DIR));
|
|
@@ -144,6 +176,7 @@ program
|
|
|
144
176
|
// The root's own options only before a subcommand: otherwise `agend update --version 2.1.9` is read as
|
|
145
177
|
// `agend --version`, prints this version and installs nothing.
|
|
146
178
|
.enablePositionalOptions();
|
|
179
|
+
registerBugReportCommand(program, pkgVersion);
|
|
147
180
|
function signalFleetReload() {
|
|
148
181
|
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
149
182
|
try {
|
|
@@ -162,15 +195,15 @@ settingsCommand.command("confirm <id>").option("--yes", "Explicit noninteractive
|
|
|
162
195
|
.action(async (id, options) => {
|
|
163
196
|
try {
|
|
164
197
|
const inspected = await requestSettingsConfirmation(DATA_DIR, { action: "inspect", id });
|
|
165
|
-
console.log(
|
|
198
|
+
console.log([t("settings_confirm.source", settingsSourceLabel(inspected.pending_change.source)), t("settings_confirm.requester", inspected.pending_change.requested_by), ...inspected.pending_change.summary].join("\n"));
|
|
166
199
|
let confirmed = options.yes === true;
|
|
167
200
|
if (!confirmed) {
|
|
168
201
|
if (!process.stdin.isTTY)
|
|
169
|
-
throw new Error("
|
|
202
|
+
throw new Error(t("settings_confirm.cli_interactive"));
|
|
170
203
|
const { createInterface } = await import("node:readline/promises");
|
|
171
204
|
const input = createInterface({ input: process.stdin, output: process.stdout });
|
|
172
205
|
try {
|
|
173
|
-
confirmed = (await input.question("
|
|
206
|
+
confirmed = (await input.question(t("settings_confirm.cli_question"))).trim().toLowerCase() === "y";
|
|
174
207
|
}
|
|
175
208
|
finally {
|
|
176
209
|
input.close();
|
|
@@ -186,10 +219,10 @@ settingsCommand.command("confirm <id>").option("--yes", "Explicit noninteractive
|
|
|
186
219
|
process.exitCode = 1;
|
|
187
220
|
}
|
|
188
221
|
});
|
|
189
|
-
settingsCommand.command("reject <id>").action(async (id) => {
|
|
222
|
+
settingsCommand.command("reject <id>").description("Reject a pending Settings change on this host").action(async (id) => {
|
|
190
223
|
try {
|
|
191
224
|
const inspected = await requestSettingsConfirmation(DATA_DIR, { action: "inspect", id });
|
|
192
|
-
console.log(
|
|
225
|
+
console.log([t("settings_confirm.source", settingsSourceLabel(inspected.pending_change.source)), t("settings_confirm.requester", inspected.pending_change.requested_by), ...inspected.pending_change.summary].join("\n"));
|
|
193
226
|
const result = await requestSettingsConfirmation(DATA_DIR, { action: "reject", ticket: inspected.ticket });
|
|
194
227
|
console.log(result.pending_change.outcome?.message ?? result.pending_change.state);
|
|
195
228
|
}
|
|
@@ -215,12 +248,24 @@ fleet
|
|
|
215
248
|
.command("start")
|
|
216
249
|
.description("Start fleet or specific instance")
|
|
217
250
|
.argument("[instance]", "Specific instance to start")
|
|
218
|
-
.
|
|
251
|
+
.option("--direct", "Start here even though an AgEnD service is installed (operators only: the service cannot run on this host)")
|
|
252
|
+
.action(async (instance, opts) => {
|
|
219
253
|
// Root running fleet = sandbox environment (e.g. Docker, WSL root service)
|
|
220
254
|
// Set IS_SANDBOX so child processes (claude-code) don't refuse to run
|
|
221
255
|
if (process.getuid?.() === 0 && !process.env.IS_SANDBOX) {
|
|
222
256
|
process.env.IS_SANDBOX = "1";
|
|
223
257
|
}
|
|
258
|
+
const marked = process.env[DIRECT_FLEET_START_ENV] === "1";
|
|
259
|
+
delete process.env[DIRECT_FLEET_START_ENV];
|
|
260
|
+
// #2356: the way out when the installed service cannot run here (never activated, no GUI session for launchd) — an
|
|
261
|
+
// operator's own decision, as `restart --force` is; the fleet's singleton lock still refuses a second fleet.
|
|
262
|
+
if (opts?.direct && !forceAllowed()) {
|
|
263
|
+
console.error(t("cli.direct_refused"));
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
const direct = marked || !!opts?.direct;
|
|
267
|
+
if (!instance && redirectToService("start", [], direct))
|
|
268
|
+
return;
|
|
224
269
|
if (instance) {
|
|
225
270
|
// If fleet daemon is already running, delegate via HTTP API
|
|
226
271
|
const { loadFleetConfig } = await import("./config.js");
|
|
@@ -275,67 +320,16 @@ fleet
|
|
|
275
320
|
// without these a Ctrl-C or `systemctl stop` in that window got Node's default
|
|
276
321
|
// behaviour: instant death with fleet.pid already written, databases unclosed,
|
|
277
322
|
// and every tmux window orphaned.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
return; // SIGINT and SIGTERM share this, and crash paths call stopAll too
|
|
282
|
-
stopping = true;
|
|
283
|
-
console.log("\nStopping fleet...");
|
|
284
|
-
// stopAll fences new profile requests synchronously, before it awaits
|
|
285
|
-
// the shared owner's stop/save. Stopping the env handle first would leave
|
|
286
|
-
// the manager open to replacing that closed owner during the save.
|
|
287
|
-
await fm.stopAll().catch(err => console.error("Shutdown error:", err));
|
|
288
|
-
process.exit(0);
|
|
289
|
-
};
|
|
290
|
-
process.on("SIGINT", shutdown);
|
|
291
|
-
process.on("SIGTERM", () => {
|
|
292
|
-
// The restart that interrupted a fleet used to leave no trace of who asked.
|
|
293
|
-
console.log(describeSignalSource(DATA_DIR, "SIGTERM"));
|
|
294
|
-
void shutdown();
|
|
295
|
-
});
|
|
296
|
-
process.on("uncaughtException", (err) => {
|
|
297
|
-
// An uncaught exception leaves unknown state — still the one case worth
|
|
298
|
-
// tearing down for.
|
|
299
|
-
console.error("Uncaught exception:", err);
|
|
300
|
-
if (stopping)
|
|
301
|
-
return;
|
|
302
|
-
stopping = true;
|
|
303
|
-
fm.stopAll().catch(() => { }).finally(() => process.exit(1));
|
|
304
|
-
});
|
|
305
|
-
process.on("unhandledRejection", (err) => {
|
|
306
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
307
|
-
// 409 = another bot poller exists — the adapter retries, don't crash.
|
|
308
|
-
if (msg.includes("409") && msg.includes("getUpdates")) {
|
|
309
|
-
console.error("Bot polling conflict (409) — retrying...");
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
// Do NOT take the fleet down. A rejected promise in one instance's tmux
|
|
313
|
-
// call, health tick, or model switch used to stop every other working
|
|
314
|
-
// instance and exit(1) — the widest blast radius in the process. The
|
|
315
|
-
// per-instance health check and crash recovery handle a genuinely broken
|
|
316
|
-
// instance on their own.
|
|
317
|
-
//
|
|
318
|
-
// Surviving quietly would be its own failure mode, so this reports to the
|
|
319
|
-
// General topic as well as the log: the operator must not have to read
|
|
320
|
-
// daemon.log to learn the fleet swallowed a fault. notifyFleetError()
|
|
321
|
-
// throttles repeats, since these usually arrive from a loop.
|
|
322
|
-
console.error("Unhandled rejection (fleet continues):", err);
|
|
323
|
-
if (err instanceof Error && err.stack)
|
|
324
|
-
console.error(err.stack);
|
|
325
|
-
try {
|
|
326
|
-
fm.notifyFleetError(`⚠️ Fleet caught an unhandled error and kept running:\n\`${msg}\`\nSee daemon.log for the stack trace.`);
|
|
327
|
-
}
|
|
328
|
-
catch (notifyErr) {
|
|
329
|
-
// Never let the reporting path itself become an unhandled rejection.
|
|
330
|
-
console.error("Failed to report unhandled rejection:", notifyErr);
|
|
331
|
-
}
|
|
323
|
+
const handlers = installFleetProcessHandlers({
|
|
324
|
+
dataDir: DATA_DIR, manager: fm, runtime: process, console,
|
|
325
|
+
describeSignal: () => describeSignalSource(DATA_DIR, "SIGTERM"),
|
|
332
326
|
});
|
|
333
327
|
await fm.startCpuProfileControl().catch(err => console.warn(`Local profile control unavailable: ${String(err)}`));
|
|
334
328
|
await fm.startSettingsConfirmationControl().catch(err => console.warn(`Local Settings confirmation unavailable: ${String(err)}`));
|
|
335
|
-
if (stopping)
|
|
329
|
+
if (handlers.stopping)
|
|
336
330
|
return;
|
|
337
331
|
cpuProfile = await fm.startEnvironmentCpuProfile();
|
|
338
|
-
if (stopping) {
|
|
332
|
+
if (handlers.stopping) {
|
|
339
333
|
await cpuProfile?.stop("startup superseded by shutdown");
|
|
340
334
|
return;
|
|
341
335
|
}
|
|
@@ -366,6 +360,8 @@ fleet
|
|
|
366
360
|
.argument("[instance]", "Specific instance to stop")
|
|
367
361
|
.option("-y, --yes", "Confirm when run from a fleet agent session (this affects every instance)")
|
|
368
362
|
.action(async (instance, opts) => {
|
|
363
|
+
if (!instance && redirectToService("stop", opts?.yes ? ["--yes"] : [], false))
|
|
364
|
+
return;
|
|
369
365
|
if (instance)
|
|
370
366
|
recordInstanceControl(DATA_DIR, "instance-stop", instance);
|
|
371
367
|
else if (!gateFleetControl(DATA_DIR, "fleet-stop", { yes: opts?.yes }))
|
|
@@ -399,7 +395,7 @@ fleet
|
|
|
399
395
|
}
|
|
400
396
|
}
|
|
401
397
|
catch {
|
|
402
|
-
console.error(
|
|
398
|
+
console.error(t("cli.fleet_unreachable", port));
|
|
403
399
|
process.exit(1);
|
|
404
400
|
}
|
|
405
401
|
return;
|
|
@@ -440,176 +436,37 @@ fleet
|
|
|
440
436
|
});
|
|
441
437
|
fleet
|
|
442
438
|
.command("restart")
|
|
443
|
-
.description("
|
|
444
|
-
.argument("[instance]", "
|
|
445
|
-
.option("--reload", "
|
|
439
|
+
.description("Deprecated: runs `agend restart` (removed in 2.4)")
|
|
440
|
+
.argument("[instance]", "Restart only this instance (now `agend restart <instance>`)")
|
|
441
|
+
.option("--reload", "Ignored: every full restart is `agend restart`")
|
|
446
442
|
.option("-y, --yes", "Confirm when run from a fleet agent session (this affects every instance)")
|
|
447
|
-
.action(
|
|
443
|
+
.action((instance, opts) => {
|
|
448
444
|
if (instance && opts?.reload) {
|
|
449
445
|
console.error("--reload restarts the entire fleet process. Cannot combine with instance name.");
|
|
450
446
|
process.exit(1);
|
|
451
447
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
const port = fleet.health_port ?? 19280;
|
|
461
|
-
let token = "";
|
|
462
|
-
try {
|
|
463
|
-
token = readFileSync(join(DATA_DIR, "web.token"), "utf-8").trim();
|
|
464
|
-
}
|
|
465
|
-
catch { /* fleet may not be running */ }
|
|
466
|
-
try {
|
|
467
|
-
const resp = await fetch(`http://127.0.0.1:${port}/restart/${encodeURIComponent(instance)}`, {
|
|
468
|
-
method: "POST",
|
|
469
|
-
headers: token ? { "X-Agend-Token": token } : {},
|
|
470
|
-
});
|
|
471
|
-
const body = await resp.json();
|
|
472
|
-
if (resp.ok) {
|
|
473
|
-
console.log(`Instance "${instance}" restarted (immediate)`);
|
|
474
|
-
}
|
|
475
|
-
else {
|
|
476
|
-
console.error(`Restart failed: ${body.error ?? resp.statusText}`);
|
|
477
|
-
process.exit(1);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
catch (err) {
|
|
481
|
-
console.error(`Cannot connect to fleet (port ${port}). Is the fleet running?`);
|
|
482
|
-
process.exit(1);
|
|
483
|
-
}
|
|
484
|
-
return;
|
|
485
|
-
}
|
|
486
|
-
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
487
|
-
if (!existsSync(pidPath)) {
|
|
488
|
-
console.error("Fleet is not running (no PID file found)");
|
|
489
|
-
process.exit(1);
|
|
490
|
-
}
|
|
491
|
-
const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
|
|
492
|
-
if (!Number.isInteger(pid) || pid <= 0) {
|
|
493
|
-
console.error(`Fleet PID file at ${pidPath} is corrupted`);
|
|
494
|
-
process.exit(1);
|
|
495
|
-
}
|
|
496
|
-
if (opts?.reload) {
|
|
497
|
-
// Check if managed by launchd — if so, just signal and let launchd restart
|
|
498
|
-
let managedByLaunchd = false;
|
|
499
|
-
try {
|
|
500
|
-
const ppid = parseInt(execFileSync("ps", ["-o", "ppid=", "-p", String(pid)]).toString().trim(), 10);
|
|
501
|
-
managedByLaunchd = ppid === 1;
|
|
502
|
-
}
|
|
503
|
-
catch { /* ignore */ }
|
|
504
|
-
try {
|
|
505
|
-
process.kill(pid, "SIGUSR1");
|
|
506
|
-
}
|
|
507
|
-
catch {
|
|
508
|
-
console.error("Failed to send reload signal (process may have exited)");
|
|
509
|
-
process.exit(1);
|
|
510
|
-
}
|
|
511
|
-
if (managedByLaunchd) {
|
|
512
|
-
console.log("Fleet is managed by launchd — sent reload signal.");
|
|
513
|
-
console.log("launchd will automatically restart with new code.");
|
|
514
|
-
// Wait briefly for old process to exit, then confirm new one started
|
|
515
|
-
const deadline = Date.now() + 6 * 60 * 1000;
|
|
516
|
-
while (Date.now() < deadline) {
|
|
517
|
-
try {
|
|
518
|
-
process.kill(pid, 0);
|
|
519
|
-
await new Promise(r => setTimeout(r, 500));
|
|
520
|
-
}
|
|
521
|
-
catch {
|
|
522
|
-
break;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
// Wait for launchd to start new process
|
|
526
|
-
await new Promise(r => setTimeout(r, 2000));
|
|
527
|
-
if (existsSync(pidPath)) {
|
|
528
|
-
const newPid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
|
|
529
|
-
if (newPid !== pid) {
|
|
530
|
-
console.log(`New fleet process started (PID ${newPid})`);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
console.log("Full restart signal sent — waiting for fleet to stop...");
|
|
536
|
-
// Wait for old process to exit (up to 6 minutes: 5 min idle wait + buffer)
|
|
537
|
-
const deadline = Date.now() + 6 * 60 * 1000;
|
|
538
|
-
while (Date.now() < deadline) {
|
|
539
|
-
try {
|
|
540
|
-
process.kill(pid, 0); // check if alive
|
|
541
|
-
await new Promise(r => setTimeout(r, 500));
|
|
542
|
-
}
|
|
543
|
-
catch {
|
|
544
|
-
break; // process exited
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
// Verify it actually exited
|
|
548
|
-
try {
|
|
549
|
-
process.kill(pid, 0);
|
|
550
|
-
console.error("Old fleet process still running after timeout — aborting");
|
|
551
|
-
process.exit(1);
|
|
552
|
-
}
|
|
553
|
-
catch {
|
|
554
|
-
// Good, it exited
|
|
555
|
-
}
|
|
556
|
-
console.log("Old fleet stopped. Starting with new code...");
|
|
557
|
-
// Start new fleet in this process (new Node.js process = new code loaded)
|
|
558
|
-
if (!claimFleetSingleton())
|
|
559
|
-
return;
|
|
560
|
-
const { FleetManager } = await import("./fleet-manager.js");
|
|
561
|
-
const fm = new FleetManager(DATA_DIR);
|
|
562
|
-
await fm.startAll(FLEET_CONFIG_PATH);
|
|
563
|
-
console.log("Fleet restarted with new code");
|
|
564
|
-
// Keep process alive (same as fleet start)
|
|
565
|
-
const shutdown = async () => {
|
|
566
|
-
console.log("\nStopping fleet...");
|
|
567
|
-
await fm.stopAll();
|
|
568
|
-
process.exit(0);
|
|
569
|
-
};
|
|
570
|
-
process.on("SIGINT", shutdown);
|
|
571
|
-
process.on("SIGTERM", shutdown);
|
|
572
|
-
process.on("uncaughtException", async (err) => {
|
|
573
|
-
console.error("Uncaught exception:", err);
|
|
574
|
-
await fm.stopAll().catch(() => { });
|
|
575
|
-
process.exit(1);
|
|
576
|
-
});
|
|
577
|
-
process.on("unhandledRejection", async (err) => {
|
|
578
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
579
|
-
if (msg.includes("409") && msg.includes("getUpdates")) {
|
|
580
|
-
console.error("Bot polling conflict (409) — retrying...");
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
console.error("Unhandled rejection:", err);
|
|
584
|
-
await fm.stopAll().catch(() => { });
|
|
585
|
-
process.exit(1);
|
|
586
|
-
});
|
|
587
|
-
}
|
|
588
|
-
else {
|
|
589
|
-
// Instance-only restart (existing behavior)
|
|
590
|
-
try {
|
|
591
|
-
process.kill(pid, "SIGUSR2");
|
|
592
|
-
console.log("Graceful restart signal sent — fleet will restart when all instances are idle");
|
|
593
|
-
}
|
|
594
|
-
catch {
|
|
595
|
-
console.error("Failed to send restart signal (process may have exited)");
|
|
596
|
-
process.exit(1);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
448
|
+
// #2356: no restart of its own any more. Its SIGUSR1 reload made the fleet exit 0 and took over in this process, so
|
|
449
|
+
// under a Restart=on-failure unit the fleet stayed down (and this process, in an agent pane, died with the unit's
|
|
450
|
+
// cgroup). It runs `agend restart` itself — this Node, this CLI — with the same gate, guard and exit code.
|
|
451
|
+
const args = instance ? ["restart", instance] : ["restart", ...(opts?.yes ? ["--yes"] : [])];
|
|
452
|
+
console.error(t("cli.fleet_restart_deprecated", args.join(" ")));
|
|
453
|
+
const self = selfCommand(args);
|
|
454
|
+
const result = spawnSync(self.command, self.args, { stdio: "inherit" });
|
|
455
|
+
process.exit(result.status ?? 1);
|
|
599
456
|
});
|
|
600
457
|
fleet
|
|
601
|
-
.command("status")
|
|
602
|
-
.description("
|
|
458
|
+
.command("status", { hidden: true })
|
|
459
|
+
.description("Alias of `agend ls --resources`")
|
|
603
460
|
.option("--json", "Output as JSON")
|
|
604
461
|
.action(async (opts) => {
|
|
605
|
-
// Delegate to the `ls` command implementation
|
|
606
462
|
await lsAction({ ...opts, resources: true });
|
|
607
463
|
});
|
|
608
464
|
fleet
|
|
609
|
-
.command("logs")
|
|
610
|
-
.description("
|
|
465
|
+
.command("logs", { hidden: true })
|
|
466
|
+
.description("Removed; use `agend logs`")
|
|
611
467
|
.action(() => {
|
|
612
|
-
console.
|
|
468
|
+
console.error(t("cli.fleet_logs_removed"));
|
|
469
|
+
process.exitCode = 1;
|
|
613
470
|
});
|
|
614
471
|
fleet
|
|
615
472
|
.command("history")
|
|
@@ -941,9 +798,6 @@ backend
|
|
|
941
798
|
console.error(`Unknown backend: ${backendName}. Available: ${BACKENDS.map(b => b.id).join(", ")}`);
|
|
942
799
|
process.exit(1);
|
|
943
800
|
}
|
|
944
|
-
if (info.deprecated) {
|
|
945
|
-
console.warn(`⚠️ ${info.label} is deprecated (stops 2026-06-18). Consider switching to backend: antigravity`);
|
|
946
|
-
}
|
|
947
801
|
let issues = 0;
|
|
948
802
|
const ok = (msg) => console.log(` \x1b[32m✓\x1b[0m ${msg}`);
|
|
949
803
|
const fail = (msg) => { issues++; console.log(` \x1b[31m✗\x1b[0m ${msg}`); };
|
|
@@ -1207,7 +1061,7 @@ async function doctorMcp() {
|
|
|
1207
1061
|
}
|
|
1208
1062
|
if (!ipcOk) {
|
|
1209
1063
|
issues.push("IPC ✗ (socket not responding)");
|
|
1210
|
-
suggestions.push("agend
|
|
1064
|
+
suggestions.push("agend restart");
|
|
1211
1065
|
}
|
|
1212
1066
|
// 2. MCP config check
|
|
1213
1067
|
let mcpOk = false;
|
|
@@ -1552,6 +1406,12 @@ program
|
|
|
1552
1406
|
// the cleanup write later can prove it still owns the marker (checklist
|
|
1553
1407
|
// 3/5). A missed capture only skips the marker write; retire still runs.
|
|
1554
1408
|
let cleanupReceipt = null;
|
|
1409
|
+
// #2264 review: the old system copy is retired only for a confirmed 2.1-era layout — the copy this updater runs
|
|
1410
|
+
// from is a 2.1.x release (2.1's updater left it there). Never from "nvm" or "root" alone: a 2.2+ copy stays.
|
|
1411
|
+
if (verified.retireSystemCopy && !/^2\.1\./.test(pkgVersion)) {
|
|
1412
|
+
console.log(t("cli.system_install_kept", pkgVersion));
|
|
1413
|
+
delete verified.retireSystemCopy;
|
|
1414
|
+
}
|
|
1555
1415
|
if (verified.retireSystemCopy) {
|
|
1556
1416
|
try {
|
|
1557
1417
|
const { markCleanupPending } = await import("./update-marker.js");
|
|
@@ -1658,12 +1518,16 @@ program
|
|
|
1658
1518
|
console.log(" Note: the old system install was kept, since the new one is not running yet.");
|
|
1659
1519
|
}
|
|
1660
1520
|
}
|
|
1661
|
-
// The refresh above (`install --no-activate`) records a launchd plan; this activation consumed it
|
|
1662
|
-
//
|
|
1521
|
+
// The refresh above (`install --no-activate`) records a launchd plan; this activation consumed it. Compare-and-
|
|
1522
|
+
// delete so a newer plan published during the slow bootout is left (#2376 / #2439).
|
|
1663
1523
|
if (manager.kind === "launchd") {
|
|
1664
|
-
const {
|
|
1665
|
-
|
|
1524
|
+
const { consumeCarriedOutPlan } = await import("./service-plan.js");
|
|
1525
|
+
const uid = process.getuid?.() ?? 501;
|
|
1526
|
+
consumeCarriedOutPlan(DATA_DIR, `gui/${uid}/com.agend.fleet`, planDeps());
|
|
1666
1527
|
}
|
|
1528
|
+
// #1853: in a WSL terminal without the Windows desktop shortcuts, say once how to make them (never makes them).
|
|
1529
|
+
if (outcome.ok)
|
|
1530
|
+
await import("./windows-shortcuts.js").then(m => m.printUpdateShortcutsHint(DATA_DIR)).catch(() => { });
|
|
1667
1531
|
if (outcome.ok && outcome.via === "launchd-activation") {
|
|
1668
1532
|
console.log(" ✓ Service restarted (launchd loaded the verified job)");
|
|
1669
1533
|
// The new fleet clears the update marker once it is up.
|
|
@@ -1750,6 +1614,7 @@ program
|
|
|
1750
1614
|
}
|
|
1751
1615
|
console.log(`\n ✓ Already up to date (v${pkgVersion})\n`);
|
|
1752
1616
|
setUpdateProgressStage(DATA_DIR, "complete", { version: pkgVersion });
|
|
1617
|
+
await import("./windows-shortcuts.js").then(m => m.printUpdateShortcutsHint(DATA_DIR)).catch(() => { });
|
|
1753
1618
|
return;
|
|
1754
1619
|
}
|
|
1755
1620
|
if (isUnrequestedDowngrade(pkgVersion, targetVersion, opts)) {
|
|
@@ -1796,6 +1661,49 @@ program
|
|
|
1796
1661
|
if (verdict.kind === "unknown")
|
|
1797
1662
|
console.log(verdict.note);
|
|
1798
1663
|
}
|
|
1664
|
+
// ── #2264: the target release installs itself ──
|
|
1665
|
+
// `agend update` only chooses the version; the install — repair, `npm install -g`, proof, service, restart, the
|
|
1666
|
+
// chat's progress — is that release's own installer (launcher/agend-install.cjs), fetched pinned by npm with its
|
|
1667
|
+
// integrity checks. So every update runs the NEWEST install logic, never this (possibly old) package's, and the
|
|
1668
|
+
// one-liner runs the same program. The code below this branch is the compatibility path, unchanged: for a prefix
|
|
1669
|
+
// that needs sudo (the nvm route), and for a target from before the installer.
|
|
1670
|
+
// Only a known target that ships the installer runs it: `npm exec --package <a release without agend-install>` would
|
|
1671
|
+
// run whatever agend-install PATH has (#2264 review). An older target, or one npm cannot describe, takes the
|
|
1672
|
+
// compatibility path below; `--target` makes any other installer refuse.
|
|
1673
|
+
const shipsInstaller = () => {
|
|
1674
|
+
const viewed = spawnSync("npm", ["view", pkg, "bin", "--json"], { encoding: "utf-8", timeout: 60_000, stdio: ["ignore", "pipe", "ignore"] });
|
|
1675
|
+
try {
|
|
1676
|
+
const parsed = JSON.parse(viewed.stdout || "null");
|
|
1677
|
+
const bin = Array.isArray(parsed) ? parsed[parsed.length - 1] : parsed;
|
|
1678
|
+
return viewed.status === 0 && !!bin && typeof bin === "object" && Object.hasOwn(bin, "agend-install");
|
|
1679
|
+
}
|
|
1680
|
+
catch {
|
|
1681
|
+
return false;
|
|
1682
|
+
}
|
|
1683
|
+
};
|
|
1684
|
+
const viaInstaller = !needsSudo && targetVersion !== null && shipsInstaller();
|
|
1685
|
+
if (!needsSudo && !viaInstaller)
|
|
1686
|
+
console.log(t("cli.no_own_installer", pkg));
|
|
1687
|
+
if (viaInstaller) {
|
|
1688
|
+
console.log(`\n Updating AgEnD v${pkgVersion} → v${targetVersion} (its own installer)...\n`);
|
|
1689
|
+
markUpdateInProgress(DATA_DIR);
|
|
1690
|
+
setUpdateProgressStage(DATA_DIR, "downloading", { version: targetVersion });
|
|
1691
|
+
// AGEND_UPDATE_OWNER_PID: the marker this process just wrote is the installer's to carry on (and no one else's).
|
|
1692
|
+
const installer = spawnSync("npm", ["exec", "--yes", "--package", pkg, "--", "agend-install", "--upgrade", "--target", targetVersion], {
|
|
1693
|
+
stdio: "inherit", env: { ...withOrigin("agend-update"), AGEND_UPDATE_OWNER_PID: String(process.pid) },
|
|
1694
|
+
});
|
|
1695
|
+
if (installer.status === 0 || installer.status === 75) {
|
|
1696
|
+
process.exitCode = installer.status ?? 0;
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1699
|
+
// The installer records its own failure; one that never started (npm could not fetch it) is recorded here.
|
|
1700
|
+
const progress = readUpdateProgress(DATA_DIR)?.progress;
|
|
1701
|
+
if (progress && progress.stage !== "failed" && progress.stage !== "complete") {
|
|
1702
|
+
setUpdateProgressStage(DATA_DIR, "failed", { error: `the installer for ${pkg} did not run (npm exec exited ${installer.status ?? installer.signal ?? installer.error?.message}); nothing was changed` });
|
|
1703
|
+
}
|
|
1704
|
+
process.exitCode = installer.status || 1;
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1799
1707
|
if (targetVersion) {
|
|
1800
1708
|
console.log(`\n Updating AgEnD v${pkgVersion} → v${targetVersion}...\n`);
|
|
1801
1709
|
}
|
|
@@ -1906,9 +1814,12 @@ program
|
|
|
1906
1814
|
program
|
|
1907
1815
|
.command("install")
|
|
1908
1816
|
.description("Install the AgEnD system service and start it by default")
|
|
1909
|
-
.
|
|
1817
|
+
.addOption(new Option("--activate").hideHelp())
|
|
1910
1818
|
.option("--no-activate", "Write the service file without activating it")
|
|
1911
1819
|
.action(async (opts) => {
|
|
1820
|
+
if (process.argv.includes("--activate")) {
|
|
1821
|
+
console.error(t("cli.install_activate_removed"));
|
|
1822
|
+
}
|
|
1912
1823
|
const { installService, activateService, detectPlatform, renderLaunchdPlist, launchdPlistPath, getServicePath, getSystemServicePath, serviceHomeFor } = await import("./service-installer.js");
|
|
1913
1824
|
// #1631 B: an older updater (2.2.0-beta.1 and before) refreshes a hand-started fleet's service too, through this
|
|
1914
1825
|
// command — which would CREATE a unit or plist, and every later update would then take a manager it may not reach
|
|
@@ -1940,9 +1851,9 @@ program
|
|
|
1940
1851
|
// #1450 C6: on launchd, writing a new plist without activating is a PLANNED activation — proven, recorded, and
|
|
1941
1852
|
// left for `agend restart` (a reload there would itself start the job). See service-plan.ts.
|
|
1942
1853
|
if (opts.activate === false && detectPlatform() === "macos") {
|
|
1943
|
-
const { refreshLaunchdWithoutActivating,
|
|
1854
|
+
const { refreshLaunchdWithoutActivating, revokePlan } = await import("./service-plan.js");
|
|
1944
1855
|
// A refresh revokes any earlier plan first, whatever it comes to (a failed refresh leaves nothing to activate).
|
|
1945
|
-
planDeps()
|
|
1856
|
+
revokePlan(DATA_DIR, planDeps());
|
|
1946
1857
|
const { expectedTuple } = await import("./restart-guard.js");
|
|
1947
1858
|
const expectation = expectedTuple();
|
|
1948
1859
|
if (!expectation.ok) {
|
|
@@ -1989,6 +1900,13 @@ program
|
|
|
1989
1900
|
process.exitCode = 1;
|
|
1990
1901
|
}
|
|
1991
1902
|
}
|
|
1903
|
+
// #2331: a host whose fleet runs under the system unit gets no second, user unit from the refresh — it would only
|
|
1904
|
+
// sit beside it unused, and be named as a leftover on every update after.
|
|
1905
|
+
if (systemUnit) {
|
|
1906
|
+
console.log(t("install.path", systemUnit));
|
|
1907
|
+
console.log(t("install.updated"));
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1992
1910
|
const svcPath = installService(serviceVars);
|
|
1993
1911
|
console.log(t("install.path", svcPath));
|
|
1994
1912
|
if (opts.activate !== false) {
|
|
@@ -2013,6 +1931,19 @@ program
|
|
|
2013
1931
|
console.log(t("install.updated"));
|
|
2014
1932
|
}
|
|
2015
1933
|
});
|
|
1934
|
+
program
|
|
1935
|
+
.command("shortcuts")
|
|
1936
|
+
.description("WSL: create or update the Windows desktop shortcuts (the dashboard and restart)")
|
|
1937
|
+
.action(async () => {
|
|
1938
|
+
// #1853: for an install that predates the installer's shortcuts, or that is only ever updated with `agend update`.
|
|
1939
|
+
const { runShortcuts, realShortcutsDeps } = await import("./windows-shortcuts.js");
|
|
1940
|
+
const { spawnSync } = await import("node:child_process");
|
|
1941
|
+
const { userInfo } = await import("node:os");
|
|
1942
|
+
process.exitCode = await runShortcuts(realShortcutsDeps(DATA_DIR, userInfo().username, (command, args) => {
|
|
1943
|
+
const r = spawnSync(command, args, { encoding: "utf-8", timeout: 120_000, stdio: ["ignore", "pipe", "pipe"] });
|
|
1944
|
+
return { status: r.status, stdout: r.stdout ?? "", stderr: r.stderr ?? "", error: r.error };
|
|
1945
|
+
}));
|
|
1946
|
+
});
|
|
2016
1947
|
program
|
|
2017
1948
|
.command("uninstall")
|
|
2018
1949
|
.description("Remove the AgEnD system service")
|
|
@@ -2074,7 +2005,22 @@ program
|
|
|
2074
2005
|
.action(async (opts) => {
|
|
2075
2006
|
if (!gateFleetControl(DATA_DIR, "stop", { yes: opts.yes }))
|
|
2076
2007
|
process.exit(1);
|
|
2077
|
-
|
|
2008
|
+
// #2481: a deliberate stop — the start attempts so far are not a crash loop.
|
|
2009
|
+
{
|
|
2010
|
+
const { clearStartAttempts } = await import("./start-failure.js");
|
|
2011
|
+
clearStartAttempts(DATA_DIR);
|
|
2012
|
+
}
|
|
2013
|
+
const { getServicePath, getSystemServicePath, stopService, stopSystemService, serviceStopReport } = await import("./service-installer.js");
|
|
2014
|
+
// #2356: the system unit first, as `agend start` and `agend restart` choose it; a SIGTERM would only stop the process.
|
|
2015
|
+
if (getSystemServicePath()) {
|
|
2016
|
+
if (stopSystemService()) {
|
|
2017
|
+
console.log(t("cli.system_service_stopped"));
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
console.error(t("cli.system_service_stop_failed"));
|
|
2021
|
+
process.exitCode = 1;
|
|
2022
|
+
return;
|
|
2023
|
+
}
|
|
2078
2024
|
if (!getServicePath()) {
|
|
2079
2025
|
// No service — try killing by PID
|
|
2080
2026
|
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
@@ -2093,8 +2039,11 @@ program
|
|
|
2093
2039
|
}
|
|
2094
2040
|
return;
|
|
2095
2041
|
}
|
|
2096
|
-
|
|
2097
|
-
|
|
2042
|
+
const report = serviceStopReport(stopService()); // #2505: "unloading" is not stopped
|
|
2043
|
+
if (report.kind !== "fallback") {
|
|
2044
|
+
console.log(report.line);
|
|
2045
|
+
if (report.exitCode)
|
|
2046
|
+
process.exitCode = report.exitCode;
|
|
2098
2047
|
}
|
|
2099
2048
|
else {
|
|
2100
2049
|
// systemd/launchd failed (e.g. no D-Bus user session) — fallback to PID kill
|
|
@@ -2123,10 +2072,10 @@ program
|
|
|
2123
2072
|
const systemServicePath = getSystemServicePath();
|
|
2124
2073
|
if (!userServicePath && !systemServicePath) {
|
|
2125
2074
|
console.log("No service installed. Starting fleet directly...");
|
|
2126
|
-
const { spawn } = await import("
|
|
2075
|
+
const { spawn } = await import("./child-process.js");
|
|
2127
2076
|
// This Node on this CLI, not `sh -c "agend fleet start"` through PATH (#1450 C5).
|
|
2128
2077
|
const start = selfCommand(["fleet", "start"]);
|
|
2129
|
-
const child = spawn(start.command, start.args, { detached: true, stdio: "ignore" });
|
|
2078
|
+
const child = spawn(start.command, start.args, { detached: true, stdio: "ignore", env: { ...process.env, [DIRECT_FLEET_START_ENV]: "1" } });
|
|
2130
2079
|
child.unref();
|
|
2131
2080
|
console.log("Fleet starting in background.");
|
|
2132
2081
|
return;
|
|
@@ -2139,16 +2088,79 @@ program
|
|
|
2139
2088
|
// A service file means the service manager owns this fleet. Falling back
|
|
2140
2089
|
// to a detached process here creates a second fleet when the bus recovers.
|
|
2141
2090
|
console.error("Failed to start the installed AgEnD service; refusing to start a detached duplicate.");
|
|
2142
|
-
console.error("
|
|
2091
|
+
console.error(t("cli.service_retry", process.platform === "darwin" ? "launchctl print gui/$(id -u)/com.agend.fleet" : systemServicePath ? "systemctl status agend" : "systemctl --user status com.agend.fleet"));
|
|
2092
|
+
// #2356: a service file that cannot run here (never activated, no session for it) would otherwise leave no start.
|
|
2093
|
+
console.error(t("cli.service_direct_hint"));
|
|
2143
2094
|
process.exitCode = 1;
|
|
2144
2095
|
}
|
|
2145
2096
|
});
|
|
2097
|
+
/**
|
|
2098
|
+
* #2356 (user decision): on a host with an AgEnD service installed, a hand-run `fleet start` / `fleet stop` would run or
|
|
2099
|
+
* kill a fleet the service manager does not own — a duplicate beside the unit, or a stop systemd undoes. Run `agend
|
|
2100
|
+
* start` / `agend stop` instead (this Node, this CLI; their own gate and exit code). The manager's own `fleet start`
|
|
2101
|
+
* (the unit's ExecStart, the launchd job) and AgEnD's marked detached start go ahead directly; so does every host
|
|
2102
|
+
* without a service (Docker, manual setups). Exits when it redirected; false to go on.
|
|
2103
|
+
*/
|
|
2104
|
+
function redirectToService(command, extra, directMarker) {
|
|
2105
|
+
let ownCgroup = null;
|
|
2106
|
+
try {
|
|
2107
|
+
ownCgroup = readFileSync("/proc/self/cgroup", "utf-8");
|
|
2108
|
+
}
|
|
2109
|
+
catch { /* not Linux */ }
|
|
2110
|
+
const byServiceManager = startedByServiceManager({ platform: process.platform, env: process.env, ownCgroup, ppid: process.ppid, launchdLabel: "com.agend.fleet" });
|
|
2111
|
+
const installed = getSystemServicePath() ?? getServicePath();
|
|
2112
|
+
if (!redirectsToService({ command, directMarker, byServiceManager, installedServicePath: installed }))
|
|
2113
|
+
return false;
|
|
2114
|
+
console.error(t("cli.service_redirect", String(installed), [command, ...extra].join(" ")));
|
|
2115
|
+
const self = selfCommand([command, ...extra]);
|
|
2116
|
+
const result = spawnSync(self.command, self.args, { stdio: "inherit" });
|
|
2117
|
+
process.exit(result.status ?? 1);
|
|
2118
|
+
}
|
|
2119
|
+
/** One instance, at once, through the running fleet's HTTP API; the fleet process keeps running. */
|
|
2120
|
+
async function restartOneInstance(instance) {
|
|
2121
|
+
recordInstanceControl(DATA_DIR, "instance-restart", instance);
|
|
2122
|
+
const { loadFleetConfig } = await import("./config.js");
|
|
2123
|
+
const fleet = loadFleetConfig(FLEET_CONFIG_PATH);
|
|
2124
|
+
const port = fleet.health_port ?? 19280;
|
|
2125
|
+
let token = "";
|
|
2126
|
+
try {
|
|
2127
|
+
token = readFileSync(join(DATA_DIR, "web.token"), "utf-8").trim();
|
|
2128
|
+
}
|
|
2129
|
+
catch { /* fleet may not be running */ }
|
|
2130
|
+
try {
|
|
2131
|
+
const resp = await fetch(`http://127.0.0.1:${port}/restart/${encodeURIComponent(instance)}`, {
|
|
2132
|
+
method: "POST",
|
|
2133
|
+
headers: token ? { "X-Agend-Token": token } : {},
|
|
2134
|
+
});
|
|
2135
|
+
const body = await resp.json();
|
|
2136
|
+
if (resp.ok) {
|
|
2137
|
+
console.log(t("cli.instance_restarted", instance));
|
|
2138
|
+
}
|
|
2139
|
+
else {
|
|
2140
|
+
console.error(t("cli.restart_failed", String(body.error ?? resp.statusText)));
|
|
2141
|
+
process.exit(1);
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
catch {
|
|
2145
|
+
console.error(t("cli.fleet_unreachable", port));
|
|
2146
|
+
process.exit(1);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2146
2149
|
program
|
|
2147
2150
|
.command("restart")
|
|
2148
|
-
.description("Restart the AgEnD service (auto-detects systemd/launchd/detached)")
|
|
2151
|
+
.description("Restart the AgEnD service (auto-detects systemd/launchd/detached) — the one full restart; or one instance")
|
|
2152
|
+
.argument("[instance]", "Restart only this instance, immediately; the fleet keeps running")
|
|
2149
2153
|
.option("-y, --yes", "Confirm when run from a fleet agent session (this affects every instance)")
|
|
2150
2154
|
.option("--force", "Restart even when the loaded service does not start this install on its selected Node (operators only)")
|
|
2151
|
-
.action(async (opts) => {
|
|
2155
|
+
.action(async (instance, opts) => {
|
|
2156
|
+
if (instance) {
|
|
2157
|
+
if (opts.force) {
|
|
2158
|
+
console.error(t("cli.force_whole_service"));
|
|
2159
|
+
process.exit(1);
|
|
2160
|
+
}
|
|
2161
|
+
await restartOneInstance(instance);
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2152
2164
|
// --force overrides the C6 guard: an operator's own decision, never a fleet agent's or a fleet-internal spawn's.
|
|
2153
2165
|
if (opts.force && !forceAllowed()) {
|
|
2154
2166
|
console.error(" ✗ Not restarting: --force is for an operator's own shell, not a fleet agent session or the fleet's own commands. Nothing was stopped.");
|
|
@@ -2198,8 +2210,9 @@ program
|
|
|
2198
2210
|
// service's own HOME, which may differ from what this command resolves (sudo,
|
|
2199
2211
|
// AGEND_HOME) — an absent pid file does NOT mean it's stopped. Ask the service
|
|
2200
2212
|
// manager first. This is the canonical restart the `update` flow spawns.
|
|
2201
|
-
const { detectPlatform, getServicePath, getSystemServicePath, getSystemdServiceState, systemdRestartOutcome, ensureSystemdUnitHardening, effectiveUnitDropIns, unitCoredumpFilterState, } = await import("./service-installer.js");
|
|
2202
|
-
const {
|
|
2213
|
+
const { detectPlatform, getServicePath, getSystemServicePath, getSystemdServiceState, systemdRestartOutcome, ensureSystemdUnitHardening, effectiveUnitDropIns, unitCoredumpFilterState, loadedUnitCheck, } = await import("./service-installer.js");
|
|
2214
|
+
const { spawnSync } = await import("node:child_process");
|
|
2215
|
+
const { spawn } = await import("./child-process.js");
|
|
2203
2216
|
const plat = detectPlatform();
|
|
2204
2217
|
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
2205
2218
|
const run = (cmd) => {
|
|
@@ -2328,7 +2341,11 @@ program
|
|
|
2328
2341
|
.filter(([key, state]) => key !== "KillMode" && (state === "added" || state === "upgraded"))
|
|
2329
2342
|
.map(([key]) => key);
|
|
2330
2343
|
if (updated.length > 0)
|
|
2331
|
-
console.log(
|
|
2344
|
+
console.log(t("cli.unit_updated", String(unitPath), updated.join(", ")));
|
|
2345
|
+
// #2331: what systemd LOADED — a drop-in that refuses the fleet's READY is overridden by AgEnD's own, leftovers
|
|
2346
|
+
// are named. Not a gate: the fleet still restarts, and the line says what will happen and what to remove.
|
|
2347
|
+
for (const line of loadedUnitCheck({ user: systemdTarget.user, unit: systemdTarget.unit, unitPath }))
|
|
2348
|
+
console.log(line);
|
|
2332
2349
|
// Re-judged after the reload, against what systemd now applies: an
|
|
2333
2350
|
// operator's own mask (anywhere — main file, unit or type drop-in, or a
|
|
2334
2351
|
// trailing empty assignment that restores the inherited one) is warned
|
|
@@ -2399,13 +2416,11 @@ program
|
|
|
2399
2416
|
if (printed.status === 0) {
|
|
2400
2417
|
const plistPath = getServicePath() ?? join(homedir(), "Library", "LaunchAgents", `${label}.plist`);
|
|
2401
2418
|
// Path 2 (#1450 C6): a proven new plist waits on disk with its plan — exactly one bootout + bootstrap.
|
|
2402
|
-
const {
|
|
2403
|
-
|
|
2404
|
-
//
|
|
2405
|
-
|
|
2406
|
-
const plan =
|
|
2407
|
-
if (recorded && !plan)
|
|
2408
|
-
console.log(" ℹ launchd already runs the job an interrupted update planned; restarting it as it is.");
|
|
2419
|
+
const { pendingPlan, admitPlan, planPath, consumeUnchangedPlan, consumeCarriedOutPlan } = await import("./service-plan.js");
|
|
2420
|
+
// #1871: a plan whose job launchd already runs (an interrupted update, then `agend start`) is done: restart that
|
|
2421
|
+
// job as an unchanged one (path 1) instead of refusing it for its new pid. #2375: quietly (no note on every restart).
|
|
2422
|
+
const published = deps.readFile(planPath(DATA_DIR));
|
|
2423
|
+
const plan = opts.force ? null : pendingPlan(DATA_DIR, target, deps);
|
|
2409
2424
|
if (plan && expectation.ok) {
|
|
2410
2425
|
const pkgDir = dirname(dirname(expectation.expected.entry));
|
|
2411
2426
|
const admitted = admitPlan(plan, { target, expected: expectation.expected, pkgDir }, deps);
|
|
@@ -2431,7 +2446,7 @@ program
|
|
|
2431
2446
|
log: message => console.log(message),
|
|
2432
2447
|
launchdPreimage: plan.preimage.plist,
|
|
2433
2448
|
});
|
|
2434
|
-
|
|
2449
|
+
consumeUnchangedPlan(DATA_DIR, published, deps);
|
|
2435
2450
|
if (outcome.ok) {
|
|
2436
2451
|
console.log("Service restarted (launchd loaded the planned job).");
|
|
2437
2452
|
return;
|
|
@@ -2440,7 +2455,9 @@ program
|
|
|
2440
2455
|
process.exitCode = 1;
|
|
2441
2456
|
return;
|
|
2442
2457
|
}
|
|
2443
|
-
// Path 1: an unchanged loaded job.
|
|
2458
|
+
// Path 1: an unchanged loaded job, or a leftover carried-out plan. Compare-and-delete that leftover (#2439);
|
|
2459
|
+
// pendingPlan itself stays read-only (#2376).
|
|
2460
|
+
consumeCarriedOutPlan(DATA_DIR, target, deps);
|
|
2444
2461
|
if (expectation.ok && refuses(guard.guardLaunchd(captureRun, target, plistPath, deps.readFile, expectation.expected, guardDeps)))
|
|
2445
2462
|
return;
|
|
2446
2463
|
if (run(`launchctl kickstart -k ${target}`)) {
|
|
@@ -2565,7 +2582,7 @@ program
|
|
|
2565
2582
|
unlinkSync(pidPath);
|
|
2566
2583
|
}
|
|
2567
2584
|
catch { /* old owner already removed it */ }
|
|
2568
|
-
const child = spawn(start.command, start.args, { detached: true, stdio: "ignore" });
|
|
2585
|
+
const child = spawn(start.command, start.args, { detached: true, stdio: "ignore", env: { ...process.env, [DIRECT_FLEET_START_ENV]: "1" } });
|
|
2569
2586
|
child.unref();
|
|
2570
2587
|
console.log("Fleet restarting in background.");
|
|
2571
2588
|
return;
|
|
@@ -2582,7 +2599,7 @@ program
|
|
|
2582
2599
|
});
|
|
2583
2600
|
program
|
|
2584
2601
|
.command("setup")
|
|
2585
|
-
.description("
|
|
2602
|
+
.description("Browser first-run page, before a fleet exists (not the CLI wizard; see `agend quickstart`)")
|
|
2586
2603
|
.option("--reset", "Allow setup again after it has already been completed")
|
|
2587
2604
|
.option("--port <port>", "Port for the setup page (default: the health port)")
|
|
2588
2605
|
.option("--tunnel", "Expose the setup page through a Cloudflare quick tunnel so a phone can open it")
|
|
@@ -2677,14 +2694,14 @@ program
|
|
|
2677
2694
|
});
|
|
2678
2695
|
program
|
|
2679
2696
|
.command("quickstart")
|
|
2680
|
-
.description("
|
|
2697
|
+
.description("CLI guided setup: backend, chat channel, projects, and fleet service (recommended)")
|
|
2681
2698
|
.action(async () => {
|
|
2682
2699
|
const { runQuickstart } = await import("./quickstart.js");
|
|
2683
2700
|
await runQuickstart();
|
|
2684
2701
|
});
|
|
2685
2702
|
program
|
|
2686
2703
|
.command("init")
|
|
2687
|
-
.description("Interactive
|
|
2704
|
+
.description("Interactive advanced wizard (setup-wizard); for first-run use `agend quickstart` or `agend setup`")
|
|
2688
2705
|
.action(async () => {
|
|
2689
2706
|
const { runSetupWizard } = await import("./setup-wizard.js");
|
|
2690
2707
|
await runSetupWizard();
|
|
@@ -2733,7 +2750,7 @@ program
|
|
|
2733
2750
|
minutes = Math.max(1, Math.round(((body.expiresAt ?? Date.now()) - Date.now()) / 60_000));
|
|
2734
2751
|
}
|
|
2735
2752
|
catch {
|
|
2736
|
-
console.error(
|
|
2753
|
+
console.error(t("cli.fleet_unreachable", port));
|
|
2737
2754
|
process.exit(1);
|
|
2738
2755
|
}
|
|
2739
2756
|
const signin = `http://localhost:${port}/signin`;
|
|
@@ -2776,9 +2793,24 @@ program
|
|
|
2776
2793
|
program
|
|
2777
2794
|
.command("validate")
|
|
2778
2795
|
.description("Validate fleet.yaml and classicBot.yaml")
|
|
2779
|
-
.
|
|
2780
|
-
|
|
2796
|
+
.option("--connections", "Only print how many chat connections fleet.yaml has, as CONNECTIONS=<n> (for scripts; CONNECTIONS=unknown and exit 1 when it cannot be read)")
|
|
2797
|
+
.action(async (opts) => {
|
|
2798
|
+
const { validateFleetConfig, validateClassicBotConfig, configuredConnectionCount } = await import("./config-validator.js");
|
|
2781
2799
|
const yaml = (await import("js-yaml")).default;
|
|
2800
|
+
if (opts.connections) {
|
|
2801
|
+
// #2233: the Windows installer's question — did the setup page make a web-only fleet? Parsed, never grepped.
|
|
2802
|
+
let count = null;
|
|
2803
|
+
try {
|
|
2804
|
+
count = configuredConnectionCount(yaml.load(readFileSync(FLEET_CONFIG_PATH, "utf-8")));
|
|
2805
|
+
}
|
|
2806
|
+
catch {
|
|
2807
|
+
count = null;
|
|
2808
|
+
}
|
|
2809
|
+
console.log(`CONNECTIONS=${count ?? "unknown"}`);
|
|
2810
|
+
if (count === null)
|
|
2811
|
+
process.exit(1);
|
|
2812
|
+
return;
|
|
2813
|
+
}
|
|
2782
2814
|
const red = (s) => `\x1b[31m${s}\x1b[0m`;
|
|
2783
2815
|
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
2784
2816
|
const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
@@ -2990,11 +3022,11 @@ schedule
|
|
|
2990
3022
|
}
|
|
2991
3023
|
});
|
|
2992
3024
|
schedule
|
|
2993
|
-
.command("trigger")
|
|
2994
|
-
.
|
|
2995
|
-
.
|
|
2996
|
-
.
|
|
2997
|
-
|
|
3025
|
+
.command("trigger", { hidden: true })
|
|
3026
|
+
.argument("[id]", "Schedule ID")
|
|
3027
|
+
.action(() => {
|
|
3028
|
+
console.error(t("cli.schedule_trigger_removed"));
|
|
3029
|
+
process.exitCode = 1;
|
|
2998
3030
|
});
|
|
2999
3031
|
// === Chat Export ===
|
|
3000
3032
|
program
|
|
@@ -3081,26 +3113,88 @@ async function fuzzyMatch(query, names) {
|
|
|
3081
3113
|
}
|
|
3082
3114
|
async function resolveInstance(query, config) {
|
|
3083
3115
|
const namesRaw = await listInstanceNames(config);
|
|
3084
|
-
const names = [...new Set(namesRaw)];
|
|
3085
|
-
const {
|
|
3086
|
-
const entries = names.map(
|
|
3116
|
+
const names = [...new Set(namesRaw)];
|
|
3117
|
+
const { assignDisplayLabels } = await import("./topic-commands.js");
|
|
3118
|
+
const entries = names.map(name => ({
|
|
3087
3119
|
name,
|
|
3088
|
-
displayName: config.instances[name]?.display_name,
|
|
3120
|
+
displayName: config.instances[name]?.display_name ?? null,
|
|
3121
|
+
}));
|
|
3122
|
+
const labelMap = assignDisplayLabels(entries);
|
|
3123
|
+
// Build candidates with 1-based row index and status, matching ls order.
|
|
3124
|
+
const candidates = names.map((name, i) => ({
|
|
3125
|
+
idx: i + 1,
|
|
3126
|
+
realName: name,
|
|
3127
|
+
displayLabel: labelMap.get(name) ?? name,
|
|
3128
|
+
teams: getTeamsForInstance(config, name),
|
|
3129
|
+
status: getInstanceStatusStandalone(name),
|
|
3089
3130
|
}));
|
|
3090
|
-
const
|
|
3091
|
-
|
|
3092
|
-
|
|
3131
|
+
const { resolveCandidate } = await import("./ls-attach-resolve.js");
|
|
3132
|
+
// No argument on a TTY: show interactive picker.
|
|
3133
|
+
if (query === undefined) {
|
|
3134
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
3135
|
+
console.error("No instance specified.");
|
|
3136
|
+
process.exit(1);
|
|
3137
|
+
}
|
|
3138
|
+
return interactivePicker(candidates);
|
|
3139
|
+
}
|
|
3140
|
+
const result = resolveCandidate(query, candidates);
|
|
3141
|
+
if (result.kind === "exact")
|
|
3142
|
+
return result.candidate.realName;
|
|
3093
3143
|
if (result.kind === "ambiguous") {
|
|
3094
|
-
|
|
3144
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
3145
|
+
console.log(`"${query}" matches multiple instances:`);
|
|
3146
|
+
const { ambiguityLine } = await import("./ls-attach-resolve.js");
|
|
3147
|
+
const { computeLsNameWidth: cnw } = await import("./ls-rows.js");
|
|
3148
|
+
const maxNameW = cnw(result.candidates.map(c => c.realName), 0);
|
|
3149
|
+
for (const c of result.candidates) {
|
|
3150
|
+
console.log(ambiguityLine(c, maxNameW));
|
|
3151
|
+
}
|
|
3152
|
+
return interactivePicker(result.candidates);
|
|
3153
|
+
}
|
|
3154
|
+
const names2 = result.candidates.map(c => `${c.displayLabel} (${c.realName})`).join(", ");
|
|
3155
|
+
console.error(`"${query}" matches multiple instances: ${names2}. Use the real name.`);
|
|
3095
3156
|
process.exit(1);
|
|
3096
3157
|
}
|
|
3097
|
-
//
|
|
3098
|
-
const
|
|
3099
|
-
if (
|
|
3100
|
-
console.error(`No instance matching "${query}".
|
|
3101
|
-
|
|
3158
|
+
// kind === "none" — show top-5 fuzzy suggestions, not the full list.
|
|
3159
|
+
const suggestions = result.suggestions;
|
|
3160
|
+
if (suggestions.length > 0) {
|
|
3161
|
+
console.error(`No instance matching "${query}". Did you mean:`);
|
|
3162
|
+
for (const c of suggestions) {
|
|
3163
|
+
console.error(` ${String(c.idx).padStart(2)}) ${c.displayLabel} (${c.realName})`);
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
else {
|
|
3167
|
+
console.error(`No instance matching "${query}". Run "agend ls" to see all instances.`);
|
|
3102
3168
|
}
|
|
3103
|
-
|
|
3169
|
+
process.exit(1);
|
|
3170
|
+
}
|
|
3171
|
+
async function interactivePicker(candidates) {
|
|
3172
|
+
const running = candidates.filter(c => c.status === "running");
|
|
3173
|
+
const rest = candidates.filter(c => c.status !== "running");
|
|
3174
|
+
const ordered = [...running, ...rest];
|
|
3175
|
+
const { pickerDefaultIdx } = await import("./ls-attach-resolve.js");
|
|
3176
|
+
const defaultIdx = pickerDefaultIdx(ordered);
|
|
3177
|
+
const { pickerLine } = await import("./ls-attach-resolve.js");
|
|
3178
|
+
const { computeLsNameWidth: cnwPicker } = await import("./ls-rows.js");
|
|
3179
|
+
const maxNameW = cnwPicker(ordered.map(c => c.realName), 0);
|
|
3180
|
+
console.log("Select an instance:");
|
|
3181
|
+
for (const c of ordered) {
|
|
3182
|
+
console.log(pickerLine(c, maxNameW));
|
|
3183
|
+
}
|
|
3184
|
+
const { createInterface } = await import("node:readline");
|
|
3185
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
3186
|
+
// Use the unambiguous #N form so Enter always selects the displayed-first
|
|
3187
|
+
// row, even when its global idx matches a digit-string real name.
|
|
3188
|
+
const answer = await new Promise(resolve => rl.question(`\nRow number or name [#${defaultIdx}]: `, resolve));
|
|
3189
|
+
rl.close();
|
|
3190
|
+
const trimmed = answer.trim() || `#${defaultIdx}`;
|
|
3191
|
+
// Accept a number or re-run resolution.
|
|
3192
|
+
const { resolveCandidate } = await import("./ls-attach-resolve.js");
|
|
3193
|
+
const reResult = resolveCandidate(trimmed, candidates);
|
|
3194
|
+
if (reResult.kind === "exact")
|
|
3195
|
+
return reResult.candidate.realName;
|
|
3196
|
+
console.error(`Invalid selection "${trimmed}".`);
|
|
3197
|
+
process.exit(1);
|
|
3104
3198
|
}
|
|
3105
3199
|
function getInstanceStatusStandalone(name) {
|
|
3106
3200
|
if (hasPausedMarker(join(DATA_DIR, "instances", name)))
|
|
@@ -3184,6 +3278,12 @@ async function lsAction(opts) {
|
|
|
3184
3278
|
// status work (a tab press should not wait on the fleet) and must print
|
|
3185
3279
|
// nothing but names — a "no instances" notice would become a candidate.
|
|
3186
3280
|
if (opts.namesOnly) {
|
|
3281
|
+
const { validateNamesOnlyFilters } = await import("./ls-attach-resolve.js");
|
|
3282
|
+
const filterErr = validateNamesOnlyFilters(opts);
|
|
3283
|
+
if (filterErr) {
|
|
3284
|
+
console.error(filterErr);
|
|
3285
|
+
process.exit(1);
|
|
3286
|
+
}
|
|
3187
3287
|
for (const n of await listInstanceNames(config))
|
|
3188
3288
|
console.log(n);
|
|
3189
3289
|
return;
|
|
@@ -3275,7 +3375,7 @@ async function lsAction(opts) {
|
|
|
3275
3375
|
};
|
|
3276
3376
|
// Row collection runs concurrently (see ls-rows.ts): the per-instance
|
|
3277
3377
|
// tmux captures overlap instead of stacking their 2s bounds serially.
|
|
3278
|
-
const { collectLsRows, capturePaneAsync, formatTimeSince, lsStatusIcon, lsStatusLabel, displayWidth } = await import("./ls-rows.js");
|
|
3378
|
+
const { collectLsRows, capturePaneAsync, formatTimeSince, lsStatusIcon, lsStatusLabel, displayWidth, computeLsNameWidth, padToDisplayWidth } = await import("./ls-rows.js");
|
|
3279
3379
|
const { getTmuxSocketName } = await import("./paths.js");
|
|
3280
3380
|
const socketName = getTmuxSocketName();
|
|
3281
3381
|
const rows = await collectLsRows(allNames.map(name => {
|
|
@@ -3337,8 +3437,25 @@ async function lsAction(opts) {
|
|
|
3337
3437
|
}
|
|
3338
3438
|
}
|
|
3339
3439
|
catch { /* fleet not running or API unreachable */ }
|
|
3440
|
+
// Assign stable global indices BEFORE any filtering (#P2-1 — filters must not
|
|
3441
|
+
// renumber rows, so `agend attach N` always resolves the same instance).
|
|
3442
|
+
const { applyLsFilters } = await import("./ls-attach-resolve.js");
|
|
3443
|
+
const allRowsIndexed = rows.map((r, i) => ({ ...r, globalIdx: i + 1 }));
|
|
3444
|
+
// Apply --running / --team / --backend CLI filters. Done before --json so
|
|
3445
|
+
// `ls --json --running` honours the flag (#P2-2).
|
|
3446
|
+
const filteredMeta = applyLsFilters(allRowsIndexed.map(r => ({
|
|
3447
|
+
globalIdx: r.globalIdx,
|
|
3448
|
+
realName: r.name,
|
|
3449
|
+
displayLabel: r.name,
|
|
3450
|
+
status: (r.status ?? "stopped"),
|
|
3451
|
+
teams: r.teams,
|
|
3452
|
+
backend: r.backend,
|
|
3453
|
+
})), { running: opts.running, team: opts.team, backend: opts.backend });
|
|
3454
|
+
const filteredNames = new Set(filteredMeta.map(m => m.realName));
|
|
3455
|
+
const displayRows = allRowsIndexed.filter(r => filteredNames.has(r.name));
|
|
3340
3456
|
if (opts.json) {
|
|
3341
|
-
|
|
3457
|
+
// Strip internal globalIdx from JSON output to keep the schema stable.
|
|
3458
|
+
console.log(JSON.stringify(displayRows.map(({ globalIdx: _idx, ...rest }) => rest), null, 2));
|
|
3342
3459
|
return;
|
|
3343
3460
|
}
|
|
3344
3461
|
// Merged State column (#1052): one glyph per lifecycle/execution state,
|
|
@@ -3350,19 +3467,24 @@ async function lsAction(opts) {
|
|
|
3350
3467
|
// across the fleet (#1305 P2-1). --json and --names-only above keep the
|
|
3351
3468
|
// real names (machine use + attach target).
|
|
3352
3469
|
const { assignDisplayLabels } = await import("./topic-commands.js");
|
|
3353
|
-
const
|
|
3470
|
+
const { lsDisplayAnnotation } = await import("./ls-attach-resolve.js");
|
|
3471
|
+
const lsLabels = assignDisplayLabels(displayRows.map((r) => ({
|
|
3354
3472
|
name: r.name,
|
|
3355
3473
|
displayName: config.instances[r.name]?.display_name,
|
|
3356
3474
|
})));
|
|
3357
|
-
const
|
|
3358
|
-
|
|
3475
|
+
const displayLabel = (row) => lsLabels.get(row.name) ?? row.name;
|
|
3476
|
+
// Columns: # (global row number), Name (real, full, copyable), then the rest.
|
|
3477
|
+
// Display name (if set) appears at the end of the row as context — secondary.
|
|
3478
|
+
const numW = 3;
|
|
3479
|
+
const nameW = computeLsNameWidth(displayRows.map(r => r.name));
|
|
3359
3480
|
const backendW = 14;
|
|
3360
3481
|
const statusW = 12;
|
|
3361
3482
|
const teamW = 20;
|
|
3362
3483
|
const srcW = 4;
|
|
3363
3484
|
const ctxW = 8;
|
|
3364
3485
|
const memW = 8;
|
|
3365
|
-
console.log("
|
|
3486
|
+
console.log("#".padEnd(numW) +
|
|
3487
|
+
"Name".padEnd(nameW) +
|
|
3366
3488
|
"Backend".padEnd(backendW) +
|
|
3367
3489
|
"Status".padEnd(statusW) +
|
|
3368
3490
|
"Team".padEnd(teamW) +
|
|
@@ -3370,25 +3492,28 @@ async function lsAction(opts) {
|
|
|
3370
3492
|
"Ctx".padEnd(ctxW) +
|
|
3371
3493
|
"Mem".padEnd(memW) +
|
|
3372
3494
|
"Activity");
|
|
3373
|
-
console.log("\u2500".repeat(nameW + backendW + statusW + teamW + srcW + ctxW + memW + 10));
|
|
3374
|
-
for (const r of
|
|
3495
|
+
console.log("\u2500".repeat(numW + nameW + backendW + statusW + teamW + srcW + ctxW + memW + 10));
|
|
3496
|
+
for (const r of displayRows) {
|
|
3375
3497
|
const teamStr = r.teams.length > 0 ? r.teams.join(",") : "-";
|
|
3376
3498
|
const ctxStr = r.context != null ? `${Math.round(r.context)}%` : "-";
|
|
3377
3499
|
const memStr = r.memMb != null ? `${r.memMb}MB` : "-";
|
|
3378
3500
|
const actStr = r.lastActivity ?? "-";
|
|
3379
|
-
|
|
3501
|
+
const dispAnnotation = lsDisplayAnnotation(r.name, displayLabel(r), opts.display ?? false);
|
|
3502
|
+
console.log(String(r.globalIdx).padEnd(numW) +
|
|
3503
|
+
padToDisplayWidth(r.name, nameW) +
|
|
3380
3504
|
r.backend.padEnd(backendW) +
|
|
3381
3505
|
statusIcon(r.status, r.idle, r.state) + " " + statusLabel(r.status, r.idle, r.state).padEnd(statusW - 2) +
|
|
3382
3506
|
padDisplay(teamStr, teamW) +
|
|
3383
3507
|
r.source.padEnd(srcW) +
|
|
3384
3508
|
ctxStr.padEnd(ctxW) +
|
|
3385
3509
|
memStr.padEnd(memW) +
|
|
3386
|
-
actStr
|
|
3510
|
+
actStr +
|
|
3511
|
+
dispAnnotation);
|
|
3387
3512
|
}
|
|
3388
3513
|
// System memory footer
|
|
3389
|
-
const totalMemMb =
|
|
3390
|
-
const runningCount =
|
|
3391
|
-
const pausedCount =
|
|
3514
|
+
const totalMemMb = displayRows.reduce((sum, r) => sum + (r.memMb ?? 0), 0);
|
|
3515
|
+
const runningCount = displayRows.filter(r => r.status === "running").length;
|
|
3516
|
+
const pausedCount = displayRows.filter(r => r.status === "paused").length;
|
|
3392
3517
|
const totalGB = totalmem() / (1024 ** 3);
|
|
3393
3518
|
const usedGB = (totalmem() - freemem()) / (1024 ** 3);
|
|
3394
3519
|
console.log(`\nInstances: ${runningCount} running, ${pausedCount} paused | Fleet Mem: ${(totalMemMb / 1024).toFixed(1)} GB | System Memory: ${usedGB.toFixed(1)} / ${totalGB.toFixed(1)} GB`);
|
|
@@ -3402,12 +3527,21 @@ async function lsAction(opts) {
|
|
|
3402
3527
|
console.log("Tip: agend completion install — then agend attach <TAB> completes instance names.");
|
|
3403
3528
|
}
|
|
3404
3529
|
}
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3530
|
+
function addLsOptions(cmd) {
|
|
3531
|
+
return cmd
|
|
3532
|
+
.option("--json", "Output as JSON")
|
|
3533
|
+
.option("--names-only", "Print instance names one per line (for shell completion)")
|
|
3534
|
+
.option("--resources", "Also report workspace disk usage, unregistered instance directories, and host memory/swap (text only); `agend fleet status` is a hidden alias of this")
|
|
3535
|
+
.option("--running", "Show only running instances")
|
|
3536
|
+
.option("--team <name>", "Filter by team name")
|
|
3537
|
+
.option("--backend <name>", "Filter by backend (exact match)")
|
|
3538
|
+
.option("--display", "Show display names as last column");
|
|
3539
|
+
}
|
|
3540
|
+
addLsOptions(program.command("ls").description("List all instances with status, backend, team, and last activity"))
|
|
3541
|
+
.action(async (opts) => {
|
|
3542
|
+
await lsAction(opts);
|
|
3543
|
+
});
|
|
3544
|
+
addLsOptions(program.command("status", { hidden: true }).description("Alias of `agend ls`"))
|
|
3411
3545
|
.action(async (opts) => {
|
|
3412
3546
|
await lsAction(opts);
|
|
3413
3547
|
});
|
|
@@ -3434,9 +3568,10 @@ Then reload the shell. Tab-completes instance names for \`agend attach\` and
|
|
|
3434
3568
|
// Subcommand names come from commander itself, so the script can't drift
|
|
3435
3569
|
// out of sync with the CLI the way a hardcoded list would.
|
|
3436
3570
|
const fleetCmd = program.commands.find(c => c.name() === "fleet");
|
|
3571
|
+
const visible = (cmds) => cmds.filter(c => !c._hidden).map(c => c.name());
|
|
3437
3572
|
const spec = {
|
|
3438
|
-
topLevel: program.commands
|
|
3439
|
-
fleetSub: fleetCmd?.commands
|
|
3573
|
+
topLevel: visible(program.commands),
|
|
3574
|
+
fleetSub: visible(fleetCmd?.commands ?? []),
|
|
3440
3575
|
instanceCommands: ["attach"],
|
|
3441
3576
|
fleetInstanceCommands: ["start", "stop", "restart"],
|
|
3442
3577
|
};
|
|
@@ -3493,7 +3628,7 @@ Then reload the shell. Tab-completes instance names for \`agend attach\` and
|
|
|
3493
3628
|
console.log(completionScript(target, spec));
|
|
3494
3629
|
});
|
|
3495
3630
|
program
|
|
3496
|
-
.command("health").description("
|
|
3631
|
+
.command("health").description("Live fleet health of running instances (HTTP, tmux, IPC); for host/setup diagnostics use `agend doctor`")
|
|
3497
3632
|
.option("--json", "Output as JSON")
|
|
3498
3633
|
.option("-q, --quiet", "One-line summary only")
|
|
3499
3634
|
.action(async (opts) => {
|
|
@@ -3642,8 +3777,8 @@ program
|
|
|
3642
3777
|
});
|
|
3643
3778
|
program
|
|
3644
3779
|
.command("attach")
|
|
3645
|
-
.description("Attach to an instance's tmux window
|
|
3646
|
-
.argument("
|
|
3780
|
+
.description("Attach to an instance's tmux window. Accepts display name, instance name, row number from ls, or a substring. No argument: interactive picker.")
|
|
3781
|
+
.argument("[name]", "Instance name, display name, row number, or substring (omit for interactive picker)")
|
|
3647
3782
|
.action(async (query) => {
|
|
3648
3783
|
const yaml = (await import("js-yaml")).default;
|
|
3649
3784
|
const config = yaml.load(readFileSync(FLEET_CONFIG_PATH, "utf-8"));
|
|
@@ -3731,7 +3866,7 @@ program
|
|
|
3731
3866
|
});
|
|
3732
3867
|
program
|
|
3733
3868
|
.command("logs")
|
|
3734
|
-
.description("Show fleet log (
|
|
3869
|
+
.description("Show fleet log (daemon.log, or fleet.log if the daemon log is not there yet)")
|
|
3735
3870
|
.option("-n, --lines <count>", "Number of lines to show", "50")
|
|
3736
3871
|
.option("-f, --follow", "Follow log output (like tail -f)")
|
|
3737
3872
|
.option("--instance <name>", "Filter by instance name")
|