@phnx-labs/agents-cli 1.22.39 → 1.22.41
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/CHANGELOG.md +316 -0
- package/README.md +116 -70
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.js +45 -27
- package/dist/browser.js +2 -2
- package/dist/cli/command-registry.d.ts +135 -0
- package/dist/cli/command-registry.js +259 -0
- package/dist/commands/accounts.d.ts +20 -0
- package/dist/commands/accounts.js +186 -25
- package/dist/commands/apply.d.ts +3 -3
- package/dist/commands/apply.js +20 -63
- package/dist/commands/browser.d.ts +15 -0
- package/dist/commands/browser.js +318 -131
- package/dist/commands/budget.d.ts +7 -6
- package/dist/commands/budget.js +8 -7
- package/dist/commands/cloud.js +17 -20
- package/dist/commands/commands.js +1 -1
- package/dist/commands/computer-actions.d.ts +1 -35
- package/dist/commands/computer-actions.js +13 -181
- package/dist/commands/computer.d.ts +28 -3
- package/dist/commands/computer.js +93 -65
- package/dist/commands/config.js +16 -3
- package/dist/commands/cost.d.ts +2 -1
- package/dist/commands/cost.js +7 -6
- package/dist/commands/daemon.js +151 -4
- package/dist/commands/detach.js +1 -1
- package/dist/commands/doctor.js +19 -11
- package/dist/commands/events.js +1 -1
- package/dist/commands/exec.d.ts +2 -50
- package/dist/commands/exec.js +160 -215
- package/dist/commands/factory.js +1 -1
- package/dist/commands/feed.d.ts +2 -2
- package/dist/commands/feed.js +12 -23
- package/dist/commands/fleet-capture.js +25 -27
- package/dist/commands/focus.d.ts +2 -3
- package/dist/commands/focus.js +34 -9
- package/dist/commands/go.js +15 -5
- package/dist/commands/harness.d.ts +3 -3
- package/dist/commands/harness.js +53 -5
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/import.js +2 -2
- package/dist/commands/insights.d.ts +5 -5
- package/dist/commands/insights.js +15 -9
- package/dist/commands/inspect.d.ts +2 -3
- package/dist/commands/inspect.js +4 -16
- package/dist/commands/logs.d.ts +2 -2
- package/dist/commands/logs.js +9 -9
- package/dist/commands/mcp.js +2 -2
- package/dist/commands/memory.js +1 -1
- package/dist/commands/message.d.ts +1 -1
- package/dist/commands/message.js +7 -7
- package/dist/commands/mine.d.ts +11 -8
- package/dist/commands/mine.js +11 -10
- package/dist/commands/models.js +1 -1
- package/dist/commands/modes.js +1 -1
- package/dist/commands/monitors.js +23 -6
- package/dist/commands/output.d.ts +7 -6
- package/dist/commands/output.js +11 -10
- package/dist/commands/packages.js +4 -4
- package/dist/commands/perf.js +1 -1
- package/dist/commands/permissions.js +49 -32
- package/dist/commands/plugins.d.ts +1 -1
- package/dist/commands/plugins.js +3 -3
- package/dist/commands/profiles.d.ts +6 -9
- package/dist/commands/profiles.js +8 -321
- package/dist/commands/projects.d.ts +9 -0
- package/dist/commands/projects.js +140 -8
- package/dist/commands/prune.js +5 -13
- package/dist/commands/refresh-rules.js +1 -1
- package/dist/commands/repo.d.ts +5 -7
- package/dist/commands/repo.js +34 -18
- package/dist/commands/resource-view.js +4 -0
- package/dist/commands/resume.d.ts +11 -7
- package/dist/commands/resume.js +82 -98
- package/dist/commands/route.d.ts +12 -0
- package/dist/commands/route.js +261 -0
- package/dist/commands/routines.d.ts +2 -3
- package/dist/commands/routines.js +120 -145
- package/dist/commands/rules.js +1 -1
- package/dist/commands/run-account-picker.d.ts +1 -1
- package/dist/commands/run-account-picker.js +2 -2
- package/dist/commands/run-broadcast.d.ts +21 -0
- package/dist/commands/run-broadcast.js +89 -0
- package/dist/commands/run-cloud.js +1 -1
- package/dist/commands/secrets-vault.d.ts +10 -0
- package/dist/commands/{login.js → secrets-vault.js} +34 -14
- package/dist/commands/secrets.d.ts +4 -4
- package/dist/commands/secrets.js +158 -159
- package/dist/commands/sessions-backfill.js +1 -1
- package/dist/commands/sessions-browser.d.ts +1 -1
- package/dist/commands/sessions-browser.js +9 -5
- package/dist/commands/sessions-export.js +2 -2
- package/dist/commands/sessions-inject.js +4 -5
- package/dist/commands/sessions-migrate.js +16 -27
- package/dist/commands/sessions-picker.d.ts +14 -0
- package/dist/commands/sessions-picker.js +209 -13
- package/dist/commands/sessions-resume.d.ts +7 -3
- package/dist/commands/sessions-resume.js +81 -33
- package/dist/commands/sessions-share.d.ts +25 -0
- package/dist/commands/sessions-share.js +166 -0
- package/dist/commands/sessions-stats.js +2 -2
- package/dist/commands/sessions.d.ts +75 -68
- package/dist/commands/sessions.js +144 -180
- package/dist/commands/setup-browser.js +1 -1
- package/dist/commands/setup-computer.js +1 -1
- package/dist/commands/setup-fleet.js +3 -0
- package/dist/commands/setup-mine.d.ts +7 -3
- package/dist/commands/setup-mine.js +13 -8
- package/dist/commands/setup-preferences.js +2 -2
- package/dist/commands/setup-secrets.js +2 -2
- package/dist/commands/setup-watchdog.js +2 -2
- package/dist/commands/setup.js +7 -2
- package/dist/commands/share.d.ts +65 -0
- package/dist/commands/share.js +253 -20
- package/dist/commands/skills.js +3 -3
- package/dist/commands/snapshot.d.ts +2 -2
- package/dist/commands/snapshot.js +9 -9
- package/dist/commands/ssh.d.ts +1 -1
- package/dist/commands/ssh.js +186 -64
- package/dist/commands/subagents.js +1 -1
- package/dist/commands/sync.js +24 -9
- package/dist/commands/teams.d.ts +2 -2
- package/dist/commands/teams.js +9 -18
- package/dist/commands/tmux.js +5 -1
- package/dist/commands/trash.js +1 -1
- package/dist/commands/usage.d.ts +1 -1
- package/dist/commands/usage.js +2 -2
- package/dist/commands/utils.d.ts +4 -14
- package/dist/commands/utils.js +6 -27
- package/dist/commands/versions.js +2 -2
- package/dist/commands/view.d.ts +9 -77
- package/dist/commands/view.js +23 -8
- package/dist/commands/watchdog.js +1 -1
- package/dist/commands/webhook.js +25 -34
- package/dist/commands/workflows.js +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/account-capabilities.d.ts +39 -0
- package/dist/lib/account-capabilities.js +59 -0
- package/dist/lib/account-catalog.js +1 -1
- package/dist/lib/account-registry.d.ts +66 -0
- package/dist/lib/account-registry.js +151 -5
- package/dist/lib/{rotate.d.ts → accounting/rotate.d.ts} +4 -4
- package/dist/lib/{rotate.js → accounting/rotate.js} +8 -8
- package/dist/lib/{usage.d.ts → accounting/usage.d.ts} +4 -4
- package/dist/lib/{usage.js → accounting/usage.js} +11 -11
- package/dist/lib/agent-spec/provider.js +1 -1
- package/dist/lib/agents.d.ts +72 -4
- package/dist/lib/agents.js +231 -199
- package/dist/lib/answer-router.d.ts +2 -2
- package/dist/lib/ask-classifier.d.ts +1 -1
- package/dist/lib/ask-classifier.js +1 -1
- package/dist/lib/audit/log.js +1 -1
- package/dist/lib/auth-health.d.ts +1 -1
- package/dist/lib/auth-health.js +2 -2
- package/dist/lib/brand.js +1 -1
- package/dist/lib/browser/caller-identity.d.ts +28 -0
- package/dist/lib/browser/caller-identity.js +156 -0
- package/dist/lib/browser/cdp.js +5 -1
- package/dist/lib/browser/chrome.js +12 -1
- package/dist/lib/browser/drivers/ssh.d.ts +1 -1
- package/dist/lib/browser/drivers/ssh.js +3 -2
- package/dist/lib/browser/hygiene.d.ts +10 -2
- package/dist/lib/browser/hygiene.js +7 -4
- package/dist/lib/browser/ipc.d.ts +22 -2
- package/dist/lib/browser/ipc.js +185 -21
- package/dist/lib/browser/profiles.d.ts +69 -5
- package/dist/lib/browser/profiles.js +135 -13
- package/dist/lib/browser/remote-control.d.ts +2 -2
- package/dist/lib/browser/remote-control.js +3 -3
- package/dist/lib/browser/runtime-state.d.ts +79 -0
- package/dist/lib/browser/runtime-state.js +119 -1
- package/dist/lib/browser/service.d.ts +137 -2
- package/dist/lib/browser/service.js +492 -54
- package/dist/lib/browser/sessions-list.d.ts +2 -1
- package/dist/lib/browser/sessions-list.js +4 -13
- package/dist/lib/browser/types.d.ts +19 -1
- package/dist/lib/budget/config.js +1 -1
- package/dist/lib/budget/ledger.js +1 -1
- package/dist/lib/byok-usage.js +1 -1
- package/dist/lib/capabilities.js +3 -15
- package/dist/lib/catchup.d.ts +1 -1
- package/dist/lib/catchup.js +1 -1
- package/dist/lib/cloud/dispatch.js +1 -1
- package/dist/lib/cloud/host.d.ts +3 -3
- package/dist/lib/cloud/host.js +5 -5
- package/dist/lib/cloud/rush.d.ts +9 -21
- package/dist/lib/cloud/rush.js +33 -120
- package/dist/lib/cloud/types.d.ts +2 -2
- package/dist/lib/commands.js +3 -13
- package/dist/lib/computer/actions.d.ts +36 -0
- package/dist/lib/computer/actions.js +162 -0
- package/dist/lib/computer/dispatch.d.ts +2 -2
- package/dist/lib/computer/dispatch.js +2 -2
- package/dist/lib/computer/sessions-list.d.ts +3 -3
- package/dist/lib/computer/sessions-list.js +2 -2
- package/dist/lib/config-keys.d.ts +2 -1
- package/dist/lib/config-keys.js +8 -4
- package/dist/lib/config-machine-keys.d.ts +4 -2
- package/dist/lib/config-machine-keys.js +5 -2
- package/dist/lib/crabbox/lease.js +9 -1
- package/dist/lib/crabbox/runtimes.d.ts +32 -7
- package/dist/lib/crabbox/runtimes.js +72 -30
- package/dist/lib/{daemon.d.ts → daemon/daemon.d.ts} +59 -1
- package/dist/lib/{daemon.js → daemon/daemon.js} +237 -49
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +5 -0
- package/dist/lib/daemon-ticks.d.ts +25 -0
- package/dist/lib/daemon-ticks.js +31 -1
- package/dist/lib/daemon-webhooks.d.ts +104 -0
- package/dist/lib/daemon-webhooks.js +215 -0
- package/dist/lib/device-config.d.ts +85 -75
- package/dist/lib/device-config.js +280 -142
- package/dist/lib/devices/config-migration.d.ts +29 -34
- package/dist/lib/devices/config-migration.js +209 -130
- package/dist/lib/devices/connect.d.ts +2 -2
- package/dist/lib/devices/connect.js +2 -2
- package/dist/lib/devices/discovery-policy.d.ts +30 -0
- package/dist/lib/devices/discovery-policy.js +101 -0
- package/dist/lib/devices/fleet-inventory.js +8 -3
- package/dist/lib/devices/harness-inventory.d.ts +1 -1
- package/dist/lib/devices/harness-inventory.js +12 -3
- package/dist/lib/devices/known-hosts.js +1 -1
- package/dist/lib/devices/pool.d.ts +10 -5
- package/dist/lib/devices/pool.js +5 -7
- package/dist/lib/devices/registry.d.ts +1 -1
- package/dist/lib/devices/registry.js +1 -1
- package/dist/lib/devices/resolve-profile.d.ts +2 -2
- package/dist/lib/devices/resolve-profile.js +2 -2
- package/dist/lib/devices/resolve-target.d.ts +1 -1
- package/dist/lib/devices/resolve-target.js +4 -4
- package/dist/lib/devices/self-host.d.ts +1 -1
- package/dist/lib/devices/self-host.js +3 -3
- package/dist/lib/devices/ssh-config.d.ts +1 -1
- package/dist/lib/devices/stats-cache.js +1 -1
- package/dist/lib/devices/sync.d.ts +3 -1
- package/dist/lib/devices/sync.js +3 -3
- package/dist/lib/doctor-diff.js +4 -4
- package/dist/lib/drift-sync.js +2 -2
- package/dist/lib/drift.js +2 -2
- package/dist/lib/event-families.d.ts +1 -1
- package/dist/lib/event-stream.d.ts +1 -1
- package/dist/lib/event-stream.js +2 -2
- package/dist/lib/events-ingest.js +2 -2
- package/dist/lib/exec.d.ts +4 -4
- package/dist/lib/exec.js +11 -11
- package/dist/lib/factory/snapshot.d.ts +1 -1
- package/dist/lib/factory/snapshot.js +1 -1
- package/dist/lib/{activity.d.ts → feed/activity.d.ts} +1 -1
- package/dist/lib/{activity.js → feed/activity.js} +7 -7
- package/dist/lib/{events.d.ts → feed/events.d.ts} +2 -2
- package/dist/lib/{events.js → feed/events.js} +5 -5
- package/dist/lib/{feed.js → feed/feed.js} +4 -4
- package/dist/lib/feed-outcome.d.ts +1 -1
- package/dist/lib/feed-policy.d.ts +1 -1
- package/dist/lib/feed-policy.js +1 -1
- package/dist/lib/feed-post.d.ts +1 -1
- package/dist/lib/feed-post.js +1 -1
- package/dist/lib/feed-ranking.d.ts +1 -1
- package/dist/lib/fleet/apply.d.ts +0 -6
- package/dist/lib/fleet/apply.js +18 -45
- package/dist/lib/fleet/auth-sync.d.ts +16 -35
- package/dist/lib/fleet/auth-sync.js +16 -75
- package/dist/lib/fleet/capture.js +8 -6
- package/dist/lib/fleet/manifest.js +23 -11
- package/dist/lib/fleet/types.d.ts +19 -7
- package/dist/lib/fleet-cache.d.ts +1 -1
- package/dist/lib/fleet-cache.js +1 -1
- package/dist/lib/format.d.ts +19 -0
- package/dist/lib/format.js +44 -1
- package/dist/lib/friction-heuristics.d.ts +1 -1
- package/dist/lib/git.d.ts +24 -1
- package/dist/lib/git.js +82 -38
- package/dist/lib/heal.js +3 -3
- package/dist/lib/hooks.d.ts +18 -0
- package/dist/lib/hooks.js +113 -1
- package/dist/lib/hosts/credentials.d.ts +30 -10
- package/dist/lib/hosts/credentials.js +38 -26
- package/dist/lib/hosts/dispatch.d.ts +3 -3
- package/dist/lib/hosts/dispatch.js +3 -3
- package/dist/lib/hosts/option.d.ts +3 -3
- package/dist/lib/hosts/option.js +7 -8
- package/dist/lib/hosts/passthrough.d.ts +17 -17
- package/dist/lib/hosts/passthrough.js +67 -50
- package/dist/lib/hosts/providers/devices.d.ts +1 -1
- package/dist/lib/hosts/providers/devices.js +1 -1
- package/dist/lib/hosts/reconcile.d.ts +1 -1
- package/dist/lib/hosts/reconcile.js +1 -1
- package/dist/lib/hosts/reconnect.d.ts +1 -1
- package/dist/lib/hosts/reconnect.js +2 -2
- package/dist/lib/hosts/registry.d.ts +5 -5
- package/dist/lib/hosts/registry.js +5 -5
- package/dist/lib/hosts/remote-cmd.d.ts +10 -10
- package/dist/lib/hosts/remote-cmd.js +25 -18
- package/dist/lib/hosts/remote-os.d.ts +4 -4
- package/dist/lib/hosts/remote-os.js +4 -4
- package/dist/lib/hosts/remote-session-id.d.ts +2 -2
- package/dist/lib/hosts/remote-session-id.js +2 -2
- package/dist/lib/hosts/routing-flag.d.ts +3 -3
- package/dist/lib/hosts/routing-flag.js +4 -5
- package/dist/lib/hosts/run-target.d.ts +4 -4
- package/dist/lib/hosts/run-target.js +4 -4
- package/dist/lib/hosts/session-index.d.ts +2 -2
- package/dist/lib/hosts/session-index.js +1 -1
- package/dist/lib/hosts/session-marker.d.ts +1 -1
- package/dist/lib/hosts/session-marker.js +1 -1
- package/dist/lib/hosts/types.d.ts +2 -2
- package/dist/lib/hosts/types.js +2 -2
- package/dist/lib/import.js +1 -1
- package/dist/lib/{migrate.d.ts → installations/migrate.d.ts} +13 -1
- package/dist/lib/{migrate.js → installations/migrate.js} +160 -40
- package/dist/lib/installations/resolve.js +1 -1
- package/dist/lib/installations/strategies.js +1 -1
- package/dist/lib/installations/update.js +2 -2
- package/dist/lib/{versions.d.ts → installations/versions.d.ts} +12 -3
- package/dist/lib/{versions.js → installations/versions.js} +51 -31
- package/dist/lib/isolation-boundary-report.js +1 -1
- package/dist/lib/linear-projects.d.ts +28 -0
- package/dist/lib/linear-projects.js +30 -0
- package/dist/lib/loop.js +1 -1
- package/dist/lib/mailbox-gc.js +1 -1
- package/dist/lib/mailbox.js +1 -1
- package/dist/lib/mcp-registry.d.ts +62 -0
- package/dist/lib/mcp-registry.js +177 -0
- package/dist/lib/mcp.d.ts +5 -0
- package/dist/lib/mcp.js +124 -307
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/install-menubar.d.ts +7 -0
- package/dist/lib/menubar/install-menubar.js +24 -6
- package/dist/lib/menubar/snapshot.d.ts +7 -0
- package/dist/lib/menubar/snapshot.js +8 -6
- package/dist/lib/models.js +1 -1
- package/dist/lib/monitors/config.d.ts +12 -0
- package/dist/lib/monitors/config.js +3 -0
- package/dist/lib/monitors/dispatch.js +26 -5
- package/dist/lib/monitors/engine.js +10 -0
- package/dist/lib/monitors/sources/webhook.d.ts +1 -1
- package/dist/lib/monitors/state.d.ts +42 -0
- package/dist/lib/monitors/state.js +30 -0
- package/dist/lib/notify.d.ts +1 -1
- package/dist/lib/observe-aliases.d.ts +3 -3
- package/dist/lib/observe-aliases.js +3 -21
- package/dist/lib/output/git-output.js +2 -2
- package/dist/lib/overdue.d.ts +1 -1
- package/dist/lib/overdue.js +1 -1
- package/dist/lib/permissions-registry.d.ts +65 -0
- package/dist/lib/permissions-registry.js +599 -0
- package/dist/lib/permissions.d.ts +24 -13
- package/dist/lib/permissions.js +52 -271
- package/dist/lib/picker.d.ts +16 -0
- package/dist/lib/picker.js +33 -3
- package/dist/lib/placement.d.ts +1 -1
- package/dist/lib/placement.js +4 -4
- package/dist/lib/platform/paths.d.ts +8 -0
- package/dist/lib/platform/paths.js +11 -0
- package/dist/lib/platform/posixpath.js +3 -3
- package/dist/lib/{plugin-marketplace.d.ts → plugins/plugin-marketplace.d.ts} +1 -1
- package/dist/lib/{plugin-marketplace.js → plugins/plugin-marketplace.js} +2 -2
- package/dist/lib/{plugins.d.ts → plugins/plugins.d.ts} +1 -1
- package/dist/lib/{plugins.js → plugins/plugins.js} +7 -7
- package/dist/lib/{skills.d.ts → plugins/skills.d.ts} +1 -1
- package/dist/lib/{skills.js → plugins/skills.js} +7 -7
- package/dist/lib/pricing/cost.d.ts +1 -1
- package/dist/lib/pricing/cost.js +1 -1
- package/dist/lib/profiles-presets.d.ts +1 -1
- package/dist/lib/profiles-presets.js +1 -1
- package/dist/lib/profiles.js +2 -2
- package/dist/lib/project-import.js +4 -1
- package/dist/lib/project-key.js +7 -0
- package/dist/lib/project-launch.d.ts +1 -1
- package/dist/lib/project-launch.js +3 -3
- package/dist/lib/project-pull.d.ts +128 -0
- package/dist/lib/project-pull.js +384 -0
- package/dist/lib/project-root.d.ts +2 -2
- package/dist/lib/project-root.js +2 -2
- package/dist/lib/project-status.js +1 -1
- package/dist/lib/projects.d.ts +23 -0
- package/dist/lib/projects.js +29 -6
- package/dist/lib/refresh.d.ts +12 -1
- package/dist/lib/refresh.js +16 -9
- package/dist/lib/registry.d.ts +9 -2
- package/dist/lib/registry.js +11 -4
- package/dist/lib/resources.d.ts +2 -2
- package/dist/lib/resources.js +2 -2
- package/dist/lib/routers.d.ts +81 -0
- package/dist/lib/routers.js +153 -0
- package/dist/lib/routine-context.d.ts +1 -0
- package/dist/lib/routine-context.js +7 -2
- package/dist/lib/routine-notify-owner.d.ts +1 -1
- package/dist/lib/routine-notify.d.ts +1 -1
- package/dist/lib/routine-notify.js +1 -1
- package/dist/lib/routine-process-cleanup.d.ts +1 -1
- package/dist/lib/routine-readiness.d.ts +1 -1
- package/dist/lib/routine-readiness.js +11 -4
- package/dist/lib/routines-placement.d.ts +12 -2
- package/dist/lib/routines-placement.js +20 -3
- package/dist/lib/routines-project.d.ts +1 -1
- package/dist/lib/routines-project.js +1 -1
- package/dist/lib/rules/compile.d.ts +1 -0
- package/dist/lib/rules/compile.js +10 -2
- package/dist/lib/rules/rules.js +1 -1
- package/dist/lib/run-notify.js +1 -1
- package/dist/lib/runner.d.ts +80 -2
- package/dist/lib/runner.js +261 -67
- package/dist/lib/sandbox.d.ts +1 -1
- package/dist/lib/scheduler.d.ts +1 -1
- package/dist/lib/scheduler.js +1 -1
- package/dist/lib/{routines.d.ts → scheduling/routines.d.ts} +54 -9
- package/dist/lib/{routines.js → scheduling/routines.js} +173 -14
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/agent.js +2 -2
- package/dist/lib/secrets/audit.js +1 -1
- package/dist/lib/secrets/bundles.d.ts +4 -4
- package/dist/lib/secrets/bundles.js +8 -8
- package/dist/lib/secrets/headless.d.ts +16 -0
- package/dist/lib/secrets/headless.js +21 -0
- package/dist/lib/secrets/index.js +1 -1
- package/dist/lib/secrets/list-filter.d.ts +1 -1
- package/dist/lib/secrets/list-filter.js +2 -2
- package/dist/lib/secrets/push.d.ts +1 -1
- package/dist/lib/secrets/push.js +10 -12
- package/dist/lib/secrets/remote.d.ts +21 -17
- package/dist/lib/secrets/remote.js +39 -23
- package/dist/lib/secrets/vault.js +2 -2
- package/dist/lib/self-heal/checks/shadowing.js +1 -1
- package/dist/lib/self-heal/checks/shims.js +1 -1
- package/dist/lib/self-update.d.ts +39 -4
- package/dist/lib/self-update.js +78 -25
- package/dist/lib/serve/control.d.ts +1 -1
- package/dist/lib/serve/control.js +4 -4
- package/dist/lib/serve/data.d.ts +1 -1
- package/dist/lib/serve/data.js +1 -1
- package/dist/lib/serve/stream.js +1 -1
- package/dist/lib/service-manifest.d.ts +29 -0
- package/dist/lib/service-manifest.js +80 -0
- package/dist/lib/session/active.d.ts +59 -7
- package/dist/lib/session/active.js +158 -17
- package/dist/lib/session/bash-command.js +1 -1
- package/dist/lib/session/claude-accounts.d.ts +1 -1
- package/dist/lib/session/claude-accounts.js +1 -1
- package/dist/lib/session/db.d.ts +10 -2
- package/dist/lib/session/db.js +25 -6
- package/dist/lib/session/discover.d.ts +77 -0
- package/dist/lib/session/discover.js +130 -25
- package/dist/lib/session/fork.js +1 -1
- package/dist/lib/session/inject.d.ts +1 -1
- package/dist/lib/session/insights.d.ts +1 -1
- package/dist/lib/session/insights.js +1 -1
- package/dist/lib/session/live-metadata.d.ts +15 -0
- package/dist/lib/session/live-metadata.js +76 -0
- package/dist/lib/session/migrate-targets.d.ts +1 -1
- package/dist/lib/session/recovery.d.ts +1 -1
- package/dist/lib/session/recovery.js +2 -2
- package/dist/lib/session/remote-active.d.ts +10 -1
- package/dist/lib/session/remote-active.js +8 -3
- package/dist/lib/session/remote-bundle.d.ts +1 -1
- package/dist/lib/session/remote-bundle.js +2 -2
- package/dist/lib/session/remote-list.d.ts +15 -4
- package/dist/lib/session/remote-list.js +40 -3
- package/dist/lib/session/remote.d.ts +5 -5
- package/dist/lib/session/remote.js +13 -17
- package/dist/lib/session/resume-command.d.ts +3 -2
- package/dist/lib/session/resume-command.js +4 -3
- package/dist/lib/session/resume-owner.d.ts +3 -3
- package/dist/lib/session/resume-owner.js +3 -3
- package/dist/lib/session/session-cache.d.ts +12 -0
- package/dist/lib/session/session-cache.js +2 -0
- package/dist/lib/session/share-html.d.ts +55 -0
- package/dist/lib/session/share-html.js +319 -0
- package/dist/lib/session/shell-programs.js +1 -1
- package/dist/lib/session/state.js +5 -5
- package/dist/lib/session/team-filter.d.ts +1 -1
- package/dist/lib/session/team-filter.js +1 -1
- package/dist/lib/session/types.d.ts +3 -3
- package/dist/lib/session/width.d.ts +2 -2
- package/dist/lib/session/width.js +2 -2
- package/dist/lib/settings-manifest.d.ts +2 -0
- package/dist/lib/settings-manifest.js +81 -3
- package/dist/lib/share/delete.d.ts +21 -0
- package/dist/lib/share/delete.js +42 -0
- package/dist/lib/share/publish.d.ts +120 -0
- package/dist/lib/share/publish.js +243 -18
- package/dist/lib/share/worker-template.js +172 -9
- package/dist/lib/shims.js +35 -7
- package/dist/lib/smart-launch.d.ts +4 -4
- package/dist/lib/smart-launch.js +6 -4
- package/dist/lib/snapshot.d.ts +4 -4
- package/dist/lib/snapshot.js +2 -2
- package/dist/lib/ssh-exec.d.ts +1 -1
- package/dist/lib/ssh-exec.js +2 -2
- package/dist/lib/ssh-tunnel.d.ts +10 -10
- package/dist/lib/ssh-tunnel.js +12 -12
- package/dist/lib/staleness/checkers/hooks.d.ts +1 -1
- package/dist/lib/staleness/checkers/hooks.js +1 -1
- package/dist/lib/staleness/detectors/permissions.js +0 -23
- package/dist/lib/staleness/detectors/plugins.js +1 -1
- package/dist/lib/staleness/fingerprint.js +1 -1
- package/dist/lib/staleness/layers.d.ts +1 -1
- package/dist/lib/staleness/layers.js +1 -1
- package/dist/lib/staleness/writers/mcp.js +3 -1
- package/dist/lib/staleness/writers/plugins.js +1 -1
- package/dist/lib/staleness/writers/types.d.ts +8 -0
- package/dist/lib/startup/command-registry.d.ts +6 -147
- package/dist/lib/startup/command-registry.js +40 -303
- package/dist/lib/startup/dev-build.d.ts +0 -21
- package/dist/lib/startup/dev-build.js +29 -8
- package/dist/lib/state.d.ts +19 -1
- package/dist/lib/state.js +120 -51
- package/dist/lib/subagents.js +1 -1
- package/dist/lib/sync-status.js +1 -1
- package/dist/lib/sync-umbrella.d.ts +6 -1
- package/dist/lib/sync-umbrella.js +9 -4
- package/dist/lib/teams/agents.js +2 -2
- package/dist/lib/teams/registry.js +1 -1
- package/dist/lib/terminal/backends/vscodium-agent.js +1 -1
- package/dist/lib/terminal/engine.js +1 -1
- package/dist/lib/terminal/index.d.ts +4 -0
- package/dist/lib/terminal/index.js +3 -0
- package/dist/lib/terminal/inject.d.ts +2 -2
- package/dist/lib/terminal/inject.js +2 -2
- package/dist/lib/terminal/transport.js +1 -1
- package/dist/lib/tmux/index.d.ts +1 -1
- package/dist/lib/tmux/index.js +1 -1
- package/dist/lib/tmux/session.d.ts +21 -5
- package/dist/lib/tmux/session.js +76 -22
- package/dist/lib/triggers/handlers.d.ts +38 -3
- package/dist/lib/triggers/handlers.js +58 -7
- package/dist/lib/triggers/webhook.d.ts +113 -5
- package/dist/lib/triggers/webhook.js +223 -44
- package/dist/lib/types.d.ts +19 -7
- package/dist/lib/usage-fleet.d.ts +1 -1
- package/dist/lib/usage-fleet.js +1 -1
- package/dist/lib/usage-refresh.d.ts +1 -1
- package/dist/lib/usage-refresh.js +3 -3
- package/dist/lib/version-duplicates.js +2 -2
- package/dist/lib/view-types.d.ts +56 -0
- package/dist/lib/view-types.js +1 -0
- package/dist/lib/watchdog/rotate.d.ts +2 -2
- package/dist/lib/watchdog/rotate.js +3 -3
- package/dist/lib/watchdog/runner.d.ts +2 -3
- package/dist/lib/watchdog/runner.js +3 -4
- package/dist/lib/workflows.js +1 -1
- package/dist/lib/wrap.d.ts +33 -0
- package/dist/lib/wrap.js +70 -0
- package/package.json +2 -1
- package/scripts/postinstall.js +2 -2
- package/dist/commands/bench.d.ts +0 -2
- package/dist/commands/bench.js +0 -101
- package/dist/commands/cp.d.ts +0 -84
- package/dist/commands/cp.js +0 -231
- package/dist/commands/login.d.ts +0 -2
- package/dist/lib/resources/commands.d.ts +0 -46
- package/dist/lib/resources/commands.js +0 -211
- package/dist/lib/resources/hooks.d.ts +0 -16
- package/dist/lib/resources/hooks.js +0 -153
- package/dist/lib/resources/mcp.d.ts +0 -34
- package/dist/lib/resources/mcp.js +0 -250
- package/dist/lib/resources/memory.d.ts +0 -15
- package/dist/lib/resources/memory.js +0 -46
- package/dist/lib/resources/permissions.d.ts +0 -13
- package/dist/lib/resources/permissions.js +0 -202
- package/dist/lib/resources/rules.d.ts +0 -46
- package/dist/lib/resources/rules.js +0 -179
- package/dist/lib/resources/skills.d.ts +0 -37
- package/dist/lib/resources/skills.js +0 -247
- package/dist/lib/resources/subagents.d.ts +0 -46
- package/dist/lib/resources/subagents.js +0 -202
- /package/dist/lib/{feed.d.ts → feed/feed.d.ts} +0 -0
|
@@ -10,29 +10,31 @@ import { spawn, execFileSync } from 'child_process';
|
|
|
10
10
|
import * as fs from 'fs';
|
|
11
11
|
import * as path from 'path';
|
|
12
12
|
import * as os from 'os';
|
|
13
|
-
import { getDaemonDir } from '
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
13
|
+
import { getDaemonDir } from '../state.js';
|
|
14
|
+
import { isolatedHomeSuffix, namespacedServiceLabel, serviceManifestHomeEnv } from '../service-manifest.js';
|
|
15
|
+
import { isAlive, killTree, backgroundSpawnOptions, waitForExit } from '../platform/index.js';
|
|
16
|
+
import { listJobs as listAllJobs } from '../scheduling/routines.js';
|
|
17
|
+
import { syncAllProjectRoutines } from '../routines-project.js';
|
|
18
|
+
import { JobScheduler } from '../scheduler.js';
|
|
19
|
+
import { MonitorEngine } from '../monitors/engine.js';
|
|
20
|
+
import { executeJobDetached, monitorRunningJobs, listLiveRoutineChildren } from '../runner.js';
|
|
21
|
+
import { detectOverdueJobs, notifyOverdue } from '../overdue.js';
|
|
22
|
+
import { runCatchup } from '../catchup.js';
|
|
23
|
+
import { notifyRoutineStart, notifyRoutineFinish, notifyRoutineStartFailed } from '../routine-notify.js';
|
|
24
|
+
import { notifyOwnerRoutineFinish, notifyOwnerRoutineStartFailed } from '../routine-notify-owner.js';
|
|
25
|
+
import { BrowserService } from '../browser/service.js';
|
|
26
|
+
import { BrowserIPCServer, getSocketPath as getBrowserIpcSocketPath } from '../browser/ipc.js';
|
|
27
|
+
import { startHostedWebhookReceivers } from '../daemon-webhooks.js';
|
|
28
|
+
import { secretsBrokerSocketPath, brokerPidAlive } from '../secrets/agent.js';
|
|
29
|
+
import { redactSecrets } from '../redact.js';
|
|
30
|
+
import { getAgentsBinPath, getCliLaunch, BUN_VIRTUAL_ROOT } from '../cli-entry.js';
|
|
31
|
+
import { isSchedulerEnabled, assertSchedulerEnabled, isDaemonEnabled, getConfigValue, resolveBrowserTaskIdleMs } from '../device-config.js';
|
|
32
|
+
import { reapTerminalRoutineProcesses } from '../routine-process-cleanup.js';
|
|
33
|
+
import { recordSubsystemOk, recordSubsystemError, recordSubsystemErrorReason, readSubsystemHealth, SUBSYSTEM_SECRETS_BROKER, SUBSYSTEM_BROWSER_IPC, SUBSYSTEM_DAEMON_START } from '../daemon-health.js';
|
|
34
|
+
import { startAccountStateService } from '../account-state-service.js';
|
|
35
|
+
import { runActiveSessionsWarmTick, runFleetCacheWarmTick, runSessionIndexWarmTick, runUsageRefreshTick } from '../daemon-ticks.js';
|
|
36
|
+
import { emit, emitRoutineEnd } from '../feed/events.js';
|
|
37
|
+
import { readDaemonServicesConfig } from '../daemon-services.js';
|
|
36
38
|
const PID_FILE = 'daemon.pid';
|
|
37
39
|
const LIFETIME_FILE = 'daemon.lifetime';
|
|
38
40
|
const LOCK_FILE = 'daemon.lock';
|
|
@@ -42,6 +44,46 @@ const LOG_MAX_SIZE = 5 * 1024 * 1024; // 5 MB
|
|
|
42
44
|
const LOG_ROTATE_COUNT = 3;
|
|
43
45
|
const PLIST_NAME = 'com.phnx-labs.agents-daemon';
|
|
44
46
|
const SYSTEMD_UNIT = 'agents-daemon.service';
|
|
47
|
+
/**
|
|
48
|
+
* RUSH-2639 (residual): launchd/systemd route `unload`/`load`/`list` by the
|
|
49
|
+
* service identifier ALONE, never by the plist/unit file's path. Baking the
|
|
50
|
+
* caller's HOME into the plist content (the earlier RUSH-2639 fix, above)
|
|
51
|
+
* keeps the STARTED daemon inside its sandbox, but every hermetic-test
|
|
52
|
+
* instance and every real interactive install still share the one literal
|
|
53
|
+
* `PLIST_NAME`/`SYSTEMD_UNIT` string. `startDaemonLocked`'s own `unload`
|
|
54
|
+
* before `load` is written to be a no-op ("not loaded, expected") for a
|
|
55
|
+
* plist that has never been loaded — but confirmed on darwin: when a
|
|
56
|
+
* DIFFERENT plist is already loaded under that same label, `unload
|
|
57
|
+
* <this-instance's-own-never-loaded-path>` still tears down the OTHER job
|
|
58
|
+
* (verified directly against real launchctl with two throwaway plists
|
|
59
|
+
* sharing one label — the second job's own `unload` silently kills the
|
|
60
|
+
* first, still alive under a different path). On a machine running several
|
|
61
|
+
* hermetic test forks at once (CI) — or a developer's own suite next to
|
|
62
|
+
* their real always-on daemon — that "other job" is a live daemon with
|
|
63
|
+
* DIFFERENT baked-in state.
|
|
64
|
+
*
|
|
65
|
+
* Namespace the identifier itself whenever HOME has been redirected away
|
|
66
|
+
* from the account's real home. `os.userInfo().homedir` reads the OS/passwd
|
|
67
|
+
* record directly and ignores `$HOME` (unlike `os.homedir()`, which honors
|
|
68
|
+
* it), so comparing the two detects exactly this redirection — true for
|
|
69
|
+
* every hermetic test process, false for every real interactive/production
|
|
70
|
+
* invocation, so a real user's daemon keeps registering under the unchanged
|
|
71
|
+
* production identifier.
|
|
72
|
+
*
|
|
73
|
+
* The rule itself now lives in `service-manifest.ts` — the daemon was the first
|
|
74
|
+
* manifest to need it, not the only one — and is re-exported here because it is
|
|
75
|
+
* part of this module's published surface.
|
|
76
|
+
*/
|
|
77
|
+
export { isolatedHomeSuffix };
|
|
78
|
+
/** launchd Label for this process's daemon — namespaced under a redirected HOME. */
|
|
79
|
+
export function daemonServiceLabel() {
|
|
80
|
+
return namespacedServiceLabel(PLIST_NAME);
|
|
81
|
+
}
|
|
82
|
+
/** systemd --user unit name for this process's daemon — namespaced under a redirected HOME. */
|
|
83
|
+
export function daemonSystemdUnitName() {
|
|
84
|
+
const suffix = isolatedHomeSuffix();
|
|
85
|
+
return suffix ? `agents-daemon-sandbox-${suffix}.service` : SYSTEMD_UNIT;
|
|
86
|
+
}
|
|
45
87
|
const MONITOR_TICK_MS = 60_000;
|
|
46
88
|
/**
|
|
47
89
|
* How often to re-scan for missed fires. Deliberately slower than the monitor
|
|
@@ -73,6 +115,8 @@ const BROKER_SELF_HEAL_TICK_MS = 60_000;
|
|
|
73
115
|
const KEYCHAIN_REAP_TICK_MS = 5 * 60_000;
|
|
74
116
|
// RUSH-2501: reap tmux sessions whose panes are all dead every 5 minutes.
|
|
75
117
|
const DEAD_PANE_REAP_TICK_MS = 5 * 60_000;
|
|
118
|
+
// RUSH-2622: close abandoned browser-task tabs every 5 minutes.
|
|
119
|
+
const BROWSER_TASK_REAP_TICK_MS = 5 * 60_000;
|
|
76
120
|
const STATE_DIR_CHECK_TICK_MS = 60_000;
|
|
77
121
|
// Watchdog nudges this host's own stalled sessions; device-probe refreshes
|
|
78
122
|
// registered devices' reachability and surfaces newly appeared tailnet nodes.
|
|
@@ -84,6 +128,10 @@ const DEVICE_PROBE_TICK_MS = 3 * 60_000;
|
|
|
84
128
|
// Matches DEFAULT_ACTIVE_CACHE_MAX_AGE_MS (15s) so long-lived watchers never
|
|
85
129
|
// outlive the publisher (RUSH-2484 — CLI-owned continuous publish).
|
|
86
130
|
const ACTIVE_SESSIONS_WARM_TICK_MS = 15_000;
|
|
131
|
+
// Incrementally scan this host's transcript dirs into the local index so a
|
|
132
|
+
// locally-started session is indexed within seconds, not on the next unrelated
|
|
133
|
+
// `agents sessions*` call (RUSH-2682 — indexing was lazy, nothing scheduled it).
|
|
134
|
+
const SESSION_INDEX_WARM_TICK_MS = 20_000;
|
|
87
135
|
const WEDGE_THRESHOLD_TICKS = 3;
|
|
88
136
|
/**
|
|
89
137
|
* Crash-loop prevention (RUSH-2418). Three layers, because none of them alone
|
|
@@ -221,10 +269,10 @@ export function getDaemonLogPath() {
|
|
|
221
269
|
return path.join(ensureDaemonDir(), LOG_FILE);
|
|
222
270
|
}
|
|
223
271
|
function getLaunchdPlistPath() {
|
|
224
|
-
return path.join(os.homedir(), 'Library', 'LaunchAgents', `${
|
|
272
|
+
return path.join(os.homedir(), 'Library', 'LaunchAgents', `${daemonServiceLabel()}.plist`);
|
|
225
273
|
}
|
|
226
274
|
function getSystemdUnitPath() {
|
|
227
|
-
return path.join(os.homedir(), '.config', 'systemd', 'user',
|
|
275
|
+
return path.join(os.homedir(), '.config', 'systemd', 'user', daemonSystemdUnitName());
|
|
228
276
|
}
|
|
229
277
|
/** Read the stored daemon PID from disk. Returns null if not present or invalid. */
|
|
230
278
|
export function readDaemonPid() {
|
|
@@ -668,6 +716,7 @@ export function warnEphemeralDaemonRoot(resolveBin = getAgentsBinPath) {
|
|
|
668
716
|
let healing = false;
|
|
669
717
|
let reapingKeychain = false;
|
|
670
718
|
let reapingDeadPanes = false;
|
|
719
|
+
let reapingBrowserTasks = false;
|
|
671
720
|
/**
|
|
672
721
|
* Resource self-heal: fill missing resources, repair invalid manifests, and
|
|
673
722
|
* fast-forward pristine stale plugins. Conservative 'safe' mode: never
|
|
@@ -684,7 +733,7 @@ async function runHealCheck() {
|
|
|
684
733
|
return;
|
|
685
734
|
healing = true;
|
|
686
735
|
try {
|
|
687
|
-
const { runSelfHeal, selfHealChangedAnything, selfHealNeedsAttention, summarizeSelfHeal } = await import('
|
|
736
|
+
const { runSelfHeal, selfHealChangedAnything, selfHealNeedsAttention, summarizeSelfHeal } = await import('../self-heal/registry.js');
|
|
688
737
|
if (!fs.existsSync(getDaemonDir()))
|
|
689
738
|
return;
|
|
690
739
|
const report = await runSelfHeal({ mode: 'safe' });
|
|
@@ -709,7 +758,7 @@ async function runKeychainReap() {
|
|
|
709
758
|
return;
|
|
710
759
|
reapingKeychain = true;
|
|
711
760
|
try {
|
|
712
|
-
const { reapOrphanedKeychainProcesses } = await import('
|
|
761
|
+
const { reapOrphanedKeychainProcesses } = await import('../secrets/reaper.js');
|
|
713
762
|
const result = reapOrphanedKeychainProcesses();
|
|
714
763
|
if (result.reaped > 0) {
|
|
715
764
|
log('WARN', `Reaped ${result.reaped} keychain orphan/stuck process(es)`);
|
|
@@ -738,8 +787,8 @@ async function runDeadPaneReap() {
|
|
|
738
787
|
return;
|
|
739
788
|
reapingDeadPanes = true;
|
|
740
789
|
try {
|
|
741
|
-
const { reapDeadTmuxPanes } = await import('
|
|
742
|
-
const { getDefaultSocketPath } = await import('
|
|
790
|
+
const { reapDeadTmuxPanes } = await import('../tmux/session.js');
|
|
791
|
+
const { getDefaultSocketPath } = await import('../tmux/paths.js');
|
|
743
792
|
const result = await reapDeadTmuxPanes(getDefaultSocketPath());
|
|
744
793
|
for (const w of result.warnings)
|
|
745
794
|
log('WARN', `Dead-pane reaper: ${w}`);
|
|
@@ -761,6 +810,35 @@ async function runDeadPaneReap() {
|
|
|
761
810
|
reapingDeadPanes = false;
|
|
762
811
|
}
|
|
763
812
|
}
|
|
813
|
+
/**
|
|
814
|
+
* RUSH-2622: close abandoned browser-task tabs — a task whose owning agent
|
|
815
|
+
* session has exited, or one idle past `browser.task-idle-minutes` (default 30,
|
|
816
|
+
* 0 disables idle reaping only). Same policy `agents browser gc` triggers on
|
|
817
|
+
* demand; this is the periodic side, and the daemon is the single executor so
|
|
818
|
+
* no UI surface can race it. `service` is the daemon's own long-lived
|
|
819
|
+
* BrowserService — the browser IPC server it started earlier in `runDaemon()`.
|
|
820
|
+
*
|
|
821
|
+
* Runs every BROWSER_TASK_REAP_TICK_MS (5 min).
|
|
822
|
+
*/
|
|
823
|
+
async function runBrowserTaskReap(service) {
|
|
824
|
+
if (reapingBrowserTasks)
|
|
825
|
+
return;
|
|
826
|
+
reapingBrowserTasks = true;
|
|
827
|
+
try {
|
|
828
|
+
const result = await service.reapAbandoned({ idleMs: resolveBrowserTaskIdleMs() });
|
|
829
|
+
if (result.closed.length > 0) {
|
|
830
|
+
log('INFO', `Browser-task reaper: closed ${result.closed.length} task(s)`);
|
|
831
|
+
for (const c of result.closed)
|
|
832
|
+
log('INFO', ` ${c.task} (${c.reason}, profile ${c.profile})`);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
catch (err) {
|
|
836
|
+
log('ERROR', `Browser-task reaper failed: ${err.message}`);
|
|
837
|
+
}
|
|
838
|
+
finally {
|
|
839
|
+
reapingBrowserTasks = false;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
764
842
|
/**
|
|
765
843
|
* One monitor tick: write heartbeat + drain the running-job monitor + reap
|
|
766
844
|
* stale terminal routine process groups. Runs on MONITOR_TICK_MS.
|
|
@@ -793,18 +871,37 @@ export async function runDaemon() {
|
|
|
793
871
|
log('INFO', `Daemon started (PID: ${process.pid})`);
|
|
794
872
|
anchorDaemonCwd();
|
|
795
873
|
warnEphemeralDaemonRoot();
|
|
796
|
-
//
|
|
797
|
-
//
|
|
798
|
-
//
|
|
799
|
-
//
|
|
800
|
-
// watchdog gates read the
|
|
874
|
+
// Converge the device-config/pins stores (legacy central block /
|
|
875
|
+
// auto-launch.json / tracked-doc pins → per-device docs + pins file).
|
|
876
|
+
// Idempotent, cheap no-op once folded. The daemon boots via
|
|
877
|
+
// `agents __daemon-run`, which bypasses bootstrap's migration sentinel — so
|
|
878
|
+
// the daemon runs this itself so its scheduler/watchdog gates read the
|
|
879
|
+
// converged store.
|
|
801
880
|
try {
|
|
802
|
-
const {
|
|
803
|
-
|
|
881
|
+
const { migrateDeviceConfigStores } = await import('../devices/config-migration.js');
|
|
882
|
+
migrateDeviceConfigStores();
|
|
804
883
|
}
|
|
805
884
|
catch (err) {
|
|
806
885
|
log('WARN', `device config migration failed: ${err.message}`);
|
|
807
886
|
}
|
|
887
|
+
// Version-skew one-shot (RUSH-2435): retrofit the current pane-died hook onto
|
|
888
|
+
// any managed tmux session a pre-fix binary left with a stale one. The 5-min
|
|
889
|
+
// `tmux-reconcile` routine that used to run this on a poll was deleted
|
|
890
|
+
// (RUSH-2495) — startup + `ensureSessionHookRepaired` at attach time
|
|
891
|
+
// (tmux/session.ts) now cover what that poll used to. Idempotent and
|
|
892
|
+
// non-destructive: a session already at the current schema is a no-op.
|
|
893
|
+
try {
|
|
894
|
+
const { reconcileSessionHooks } = await import('../tmux/session.js');
|
|
895
|
+
const { isTmuxInstalled } = await import('../tmux/binary.js');
|
|
896
|
+
if (isTmuxInstalled()) {
|
|
897
|
+
const r = await reconcileSessionHooks();
|
|
898
|
+
if (r.reconciled > 0)
|
|
899
|
+
log('INFO', `tmux: retrofitted pane-died hook on ${r.reconciled}/${r.scanned} session(s)`);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
catch (err) {
|
|
903
|
+
log('WARN', `tmux hook reconcile failed: ${err.message}`);
|
|
904
|
+
}
|
|
808
905
|
// Per-service toggles live outside device-config so they can be checked by
|
|
809
906
|
// service clients (e.g. secrets) without loading the whole config stack.
|
|
810
907
|
let servicesConfig = readDaemonServicesConfig();
|
|
@@ -842,7 +939,7 @@ export async function runDaemon() {
|
|
|
842
939
|
let hostedBroker = null;
|
|
843
940
|
if (isEnabled('secrets-broker')) {
|
|
844
941
|
try {
|
|
845
|
-
const { agentPing, startHostedBroker } = await import('
|
|
942
|
+
const { agentPing, startHostedBroker } = await import('../secrets/agent.js');
|
|
846
943
|
if ((await agentPing()).reachable) {
|
|
847
944
|
log('INFO', 'Secrets broker already running (standalone); daemon not hosting it');
|
|
848
945
|
}
|
|
@@ -1028,6 +1125,35 @@ export async function runDaemon() {
|
|
|
1028
1125
|
};
|
|
1029
1126
|
void runActiveSessionsWarm();
|
|
1030
1127
|
const activeSessionsWarmInterval = setInterval(() => { void runActiveSessionsWarm(); }, ACTIVE_SESSIONS_WARM_TICK_MS);
|
|
1128
|
+
// Session-index warm (RUSH-2682): keep THIS host's transcript index current so
|
|
1129
|
+
// a locally-started session is discoverable within seconds. Incremental +
|
|
1130
|
+
// single-flight (the DB scan claim), overlap-guarded so a slow scan never
|
|
1131
|
+
// stacks on the next tick.
|
|
1132
|
+
let sessionIndexWarmInFlight = false;
|
|
1133
|
+
const runSessionIndexWarm = async () => {
|
|
1134
|
+
if (sessionIndexWarmInFlight)
|
|
1135
|
+
return;
|
|
1136
|
+
sessionIndexWarmInFlight = true;
|
|
1137
|
+
try {
|
|
1138
|
+
const { indexed, claimed } = await runSessionIndexWarmTick();
|
|
1139
|
+
// Log only when the tick did something. A silent tick is what let it
|
|
1140
|
+
// report 0 forever unnoticed (RUSH-2691); a line on every idle 20s tick
|
|
1141
|
+
// would drown the log, so the steady state (claimed, nothing changed)
|
|
1142
|
+
// stays quiet and both interesting outcomes are visible.
|
|
1143
|
+
if (!claimed)
|
|
1144
|
+
log('INFO', 'session-index warm: skipped, another process holds the scan claim');
|
|
1145
|
+
else if (indexed > 0)
|
|
1146
|
+
log('INFO', `session-index warm: indexed ${indexed} transcript(s)`);
|
|
1147
|
+
}
|
|
1148
|
+
catch (err) {
|
|
1149
|
+
log('WARN', `session-index warm failed: ${err.message}`);
|
|
1150
|
+
}
|
|
1151
|
+
finally {
|
|
1152
|
+
sessionIndexWarmInFlight = false;
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
void runSessionIndexWarm();
|
|
1156
|
+
const sessionIndexWarmInterval = setInterval(() => { void runSessionIndexWarm(); }, SESSION_INDEX_WARM_TICK_MS);
|
|
1031
1157
|
// Watchdog: nudge this host's own stalled agent sessions. Gated on the
|
|
1032
1158
|
// `watchdog.enabled` device-config flag (`agents watchdog enable`), so the
|
|
1033
1159
|
// timer always fires but only does work when the user opted in. Overlap-safe
|
|
@@ -1042,7 +1168,7 @@ export async function runDaemon() {
|
|
|
1042
1168
|
try {
|
|
1043
1169
|
if (getConfigValue('watchdog.enabled').value !== true)
|
|
1044
1170
|
return;
|
|
1045
|
-
const { runWatchdogPass } = await import('
|
|
1171
|
+
const { runWatchdogPass } = await import('../watchdog/service.js');
|
|
1046
1172
|
const result = await runWatchdogPass({ nudge: true });
|
|
1047
1173
|
log('INFO', `watchdog: ${result.counts.total} live, ${result.counts.stalled} stalled, ${result.counts.nudged} nudged`);
|
|
1048
1174
|
emit('watchdog.action', {
|
|
@@ -1081,8 +1207,8 @@ export async function runDaemon() {
|
|
|
1081
1207
|
return;
|
|
1082
1208
|
deviceProbeInFlight = true;
|
|
1083
1209
|
try {
|
|
1084
|
-
const { runDeviceSync } = await import('
|
|
1085
|
-
const { reconcilePendingSentinels, pruneDismissedPendingSentinels, } = await import('
|
|
1210
|
+
const { runDeviceSync } = await import('../devices/sync.js');
|
|
1211
|
+
const { reconcilePendingSentinels, pruneDismissedPendingSentinels, } = await import('../devices/pending.js');
|
|
1086
1212
|
const dev = await runDeviceSync({ soft: true, mode: 'refresh' });
|
|
1087
1213
|
if (!dev.ok) {
|
|
1088
1214
|
await pruneDismissedPendingSentinels();
|
|
@@ -1204,7 +1330,7 @@ export async function runDaemon() {
|
|
|
1204
1330
|
// (cdp:// profile silently driven via stale ssh tunnel) or fail to
|
|
1205
1331
|
// bind because the ports are still claimed.
|
|
1206
1332
|
try {
|
|
1207
|
-
const { reapOrphanedProcesses } = await import('
|
|
1333
|
+
const { reapOrphanedProcesses } = await import('../browser/runtime-state.js');
|
|
1208
1334
|
const result = reapOrphanedProcesses();
|
|
1209
1335
|
if (result.reaped > 0) {
|
|
1210
1336
|
log('INFO', `Reaped ${result.reaped} orphan process(es) from prior daemon(s)`);
|
|
@@ -1232,6 +1358,25 @@ export async function runDaemon() {
|
|
|
1232
1358
|
else {
|
|
1233
1359
|
log('INFO', 'Browser IPC service disabled');
|
|
1234
1360
|
}
|
|
1361
|
+
// 5th hosted service: signed webhook receiver(s) + their funnel (RUSH-2548).
|
|
1362
|
+
// Started after the broker (above) so it resolves each receiver's signing
|
|
1363
|
+
// secret headlessly — no AGENTS_SECRETS_PASSPHRASE, no nohup. Binds nothing
|
|
1364
|
+
// unless daemon/webhooks.yaml declares a receiver, so an unconfigured box no-ops.
|
|
1365
|
+
let webhookReceivers = null;
|
|
1366
|
+
if (isEnabled('webhook-receiver')) {
|
|
1367
|
+
try {
|
|
1368
|
+
webhookReceivers = await startHostedWebhookReceivers({ log });
|
|
1369
|
+
log('INFO', webhookReceivers.count > 0
|
|
1370
|
+
? `Webhook receiver hosting ${webhookReceivers.count} receiver(s)`
|
|
1371
|
+
: 'Webhook receiver service enabled; no receivers declared in daemon/webhooks.yaml');
|
|
1372
|
+
}
|
|
1373
|
+
catch (err) {
|
|
1374
|
+
log('WARN', `Webhook receiver host skipped: ${err.message}`);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
else {
|
|
1378
|
+
log('INFO', 'Webhook receiver service disabled');
|
|
1379
|
+
}
|
|
1235
1380
|
runMonitorTick();
|
|
1236
1381
|
const monitorInterval = setInterval(runMonitorTick, MONITOR_TICK_MS);
|
|
1237
1382
|
// Resource safety check: see runHealCheck above. Runs ~every 6h plus once
|
|
@@ -1264,7 +1409,7 @@ export async function runDaemon() {
|
|
|
1264
1409
|
return;
|
|
1265
1410
|
selfHealingBroker = true;
|
|
1266
1411
|
try {
|
|
1267
|
-
const { agentPing, startHostedBroker } = await import('
|
|
1412
|
+
const { agentPing, startHostedBroker } = await import('../secrets/agent.js');
|
|
1268
1413
|
const reachable = (await agentPing()).reachable;
|
|
1269
1414
|
if (!shouldTakeOverBroker(hostedBroker != null, reachable))
|
|
1270
1415
|
return;
|
|
@@ -1296,6 +1441,15 @@ export async function runDaemon() {
|
|
|
1296
1441
|
// 5-min cadence as the keychain reaper. Daemon-only (single executor).
|
|
1297
1442
|
void runDeadPaneReap(); // kick-off on startup so the backlog clears immediately
|
|
1298
1443
|
const deadPaneReapInterval = setInterval(() => { void runDeadPaneReap(); }, DEAD_PANE_REAP_TICK_MS);
|
|
1444
|
+
// RUSH-2622: close abandoned browser-task tabs on the same 5-min cadence,
|
|
1445
|
+
// reusing the daemon's own long-lived BrowserService instead of a second
|
|
1446
|
+
// one. Only when browser IPC is actually up — there is no service to reap
|
|
1447
|
+
// through otherwise.
|
|
1448
|
+
let browserTaskReapInterval;
|
|
1449
|
+
if (browserService) {
|
|
1450
|
+
void runBrowserTaskReap(browserService); // kick-off on startup
|
|
1451
|
+
browserTaskReapInterval = setInterval(() => { void runBrowserTaskReap(browserService); }, BROWSER_TASK_REAP_TICK_MS);
|
|
1452
|
+
}
|
|
1299
1453
|
// RUSH-2367: self-terminate if this daemon's own state dir has been removed
|
|
1300
1454
|
// out from under it — the shape of a leaked test-fixture daemon whose /tmp
|
|
1301
1455
|
// HOME was deleted by its test's own cleanup while the process itself
|
|
@@ -1432,6 +1586,7 @@ export async function runDaemon() {
|
|
|
1432
1586
|
log('INFO', 'Daemon shutting down');
|
|
1433
1587
|
accountStateService?.stop();
|
|
1434
1588
|
clearInterval(activeSessionsWarmInterval);
|
|
1589
|
+
clearInterval(sessionIndexWarmInterval);
|
|
1435
1590
|
if (watchdogInterval)
|
|
1436
1591
|
clearInterval(watchdogInterval);
|
|
1437
1592
|
if (deviceProbeInterval)
|
|
@@ -1439,6 +1594,7 @@ export async function runDaemon() {
|
|
|
1439
1594
|
stopScheduler();
|
|
1440
1595
|
monitorEngine?.stop();
|
|
1441
1596
|
await browserIPC?.stop();
|
|
1597
|
+
await webhookReceivers?.close();
|
|
1442
1598
|
clearInterval(monitorInterval);
|
|
1443
1599
|
if (healInterval)
|
|
1444
1600
|
clearInterval(healInterval);
|
|
@@ -1449,6 +1605,8 @@ export async function runDaemon() {
|
|
|
1449
1605
|
if (keychainReapInterval)
|
|
1450
1606
|
clearInterval(keychainReapInterval);
|
|
1451
1607
|
clearInterval(deadPaneReapInterval);
|
|
1608
|
+
if (browserTaskReapInterval)
|
|
1609
|
+
clearInterval(browserTaskReapInterval);
|
|
1452
1610
|
if (stateDirCheckInterval)
|
|
1453
1611
|
clearInterval(stateDirCheckInterval);
|
|
1454
1612
|
try {
|
|
@@ -1500,16 +1658,32 @@ export function writeOwnerOnlyServiceManifest(filePath, content) {
|
|
|
1500
1658
|
* credential at all. Routine runs authenticate through the per-account
|
|
1501
1659
|
* CLAUDE_CONFIG_DIR login on this device, exactly like an interactive
|
|
1502
1660
|
* `agents run`, so no credential ever touches the service manifest.
|
|
1661
|
+
*
|
|
1662
|
+
* RUSH-2639: launchd does NOT inherit `launchctl load`'s caller's process
|
|
1663
|
+
* environment — a spawned daemon only ever sees the login session's default
|
|
1664
|
+
* env plus whatever this dict adds/overrides. Before this fix the dict carried
|
|
1665
|
+
* only PATH, so HOME resolved to the launchd session's own value regardless of
|
|
1666
|
+
* what HOME the process that generated (and loaded) the plist was running
|
|
1667
|
+
* under. In production that's a no-op (the login session's HOME already is the
|
|
1668
|
+
* real HOME), but under a hermetic test harness that redirects HOME to a
|
|
1669
|
+
* fork-private sandbox, a launchd-started daemon silently escaped the sandbox
|
|
1670
|
+
* and bootstrapped `~/.agents` (.cache/.history/.system/routines) in the
|
|
1671
|
+
* developer's/runner's REAL home. Baking HOME (and the AGENTS_REAL_HOME seam
|
|
1672
|
+
* every version-home consumer honors, see tests/setup.ts) into the plist at
|
|
1673
|
+
* generation time makes the launchd child inherit the SAME home the caller
|
|
1674
|
+
* resolved, exactly like the plain detached-spawn path already does via
|
|
1675
|
+
* `env: {...process.env}`.
|
|
1503
1676
|
*/
|
|
1504
1677
|
export function generateLaunchdPlist(agentsBin = getAgentsBinPath()) {
|
|
1505
1678
|
const launch = getDaemonLaunch(agentsBin);
|
|
1506
1679
|
const logPath = getDaemonLogPath();
|
|
1680
|
+
const { HOME: home, AGENTS_REAL_HOME: realHome } = serviceManifestHomeEnv();
|
|
1507
1681
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1508
1682
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
1509
1683
|
<plist version="1.0">
|
|
1510
1684
|
<dict>
|
|
1511
1685
|
<key>Label</key>
|
|
1512
|
-
<string>${
|
|
1686
|
+
<string>${daemonServiceLabel()}</string>
|
|
1513
1687
|
<key>ProgramArguments</key>
|
|
1514
1688
|
<array>
|
|
1515
1689
|
${[launch.command, ...launch.args].map((arg) => ` <string>${xmlEscape(arg)}</string>`).join('\n')}
|
|
@@ -1528,6 +1702,10 @@ ${[launch.command, ...launch.args].map((arg) => ` <string>${xmlEscape(arg)}</
|
|
|
1528
1702
|
<dict>
|
|
1529
1703
|
<key>PATH</key>
|
|
1530
1704
|
<string>${daemonPathValue(agentsBin, ['/usr/local/bin', '/usr/bin', '/bin', '/opt/homebrew/bin', `${os.homedir()}/.bun/bin`])}</string>
|
|
1705
|
+
<key>HOME</key>
|
|
1706
|
+
<string>${xmlEscape(home)}</string>
|
|
1707
|
+
<key>AGENTS_REAL_HOME</key>
|
|
1708
|
+
<string>${xmlEscape(realHome)}</string>
|
|
1531
1709
|
</dict>
|
|
1532
1710
|
</dict>
|
|
1533
1711
|
</plist>`;
|
|
@@ -1543,10 +1721,18 @@ function systemdExecArg(value) {
|
|
|
1543
1721
|
* credential at all. Routine runs authenticate through the per-account
|
|
1544
1722
|
* CLAUDE_CONFIG_DIR login on this device, exactly like an interactive
|
|
1545
1723
|
* `agents run`, so no credential ever touches the unit file.
|
|
1724
|
+
*
|
|
1725
|
+
* RUSH-2639: same seam as `generateLaunchdPlist` — a systemd --user unit is
|
|
1726
|
+
* started by the user's systemd instance, not the process that generated the
|
|
1727
|
+
* unit, so HOME is whatever that session provides unless this file pins it.
|
|
1728
|
+
* Baking HOME (and AGENTS_REAL_HOME) in at generation time keeps a
|
|
1729
|
+
* hermetic-test-started unit inside its sandbox instead of resolving against
|
|
1730
|
+
* the real account home.
|
|
1546
1731
|
*/
|
|
1547
1732
|
export function generateSystemdUnit(agentsBin = getAgentsBinPath()) {
|
|
1548
1733
|
const launch = getDaemonLaunch(agentsBin);
|
|
1549
1734
|
const execStart = [launch.command, ...launch.args].map(systemdExecArg).join(' ');
|
|
1735
|
+
const { HOME: home, AGENTS_REAL_HOME: realHome } = serviceManifestHomeEnv();
|
|
1550
1736
|
return `[Unit]
|
|
1551
1737
|
Description=Agents Daemon - Scheduled Job Runner
|
|
1552
1738
|
After=network.target
|
|
@@ -1559,6 +1745,8 @@ ExecStart=${execStart}
|
|
|
1559
1745
|
Restart=always
|
|
1560
1746
|
RestartSec=${DAEMON_THROTTLE_SECONDS}
|
|
1561
1747
|
Environment=PATH=${daemonPathValue(agentsBin, ['/usr/local/bin', '/usr/bin', '/bin'])}
|
|
1748
|
+
Environment=HOME=${home}
|
|
1749
|
+
Environment=AGENTS_REAL_HOME=${realHome}
|
|
1562
1750
|
|
|
1563
1751
|
[Install]
|
|
1564
1752
|
WantedBy=default.target`;
|
|
@@ -1577,12 +1765,12 @@ export { getAgentsBinPath };
|
|
|
1577
1765
|
function readServiceManagerPid(platform = os.platform()) {
|
|
1578
1766
|
try {
|
|
1579
1767
|
if (platform === 'linux') {
|
|
1580
|
-
const out = execFileSync('systemctl', ['--user', 'show', '-p', 'MainPID', '--value',
|
|
1768
|
+
const out = execFileSync('systemctl', ['--user', 'show', '-p', 'MainPID', '--value', daemonSystemdUnitName()], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
1581
1769
|
const pid = parseInt(out, 10);
|
|
1582
1770
|
return !isNaN(pid) && pid > 0 ? pid : null;
|
|
1583
1771
|
}
|
|
1584
1772
|
if (platform === 'darwin') {
|
|
1585
|
-
const out = execFileSync('launchctl', ['list',
|
|
1773
|
+
const out = execFileSync('launchctl', ['list', daemonServiceLabel()], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
1586
1774
|
const m = out.match(/"PID"\s*=\s*(\d+)/);
|
|
1587
1775
|
if (m) {
|
|
1588
1776
|
const pid = parseInt(m[1], 10);
|
|
@@ -1767,8 +1955,8 @@ function startDaemonLocked(agentsBin, releaseLock) {
|
|
|
1767
1955
|
// itself at startup); owner-only to keep the PATH/log surface private.
|
|
1768
1956
|
writeOwnerOnlyServiceManifest(unitPath, generateSystemdUnit(agentsBin));
|
|
1769
1957
|
execFileSync('systemctl', ['--user', 'daemon-reload'], { encoding: 'utf-8' });
|
|
1770
|
-
execFileSync('systemctl', ['--user', 'enable',
|
|
1771
|
-
execFileSync('systemctl', ['--user', 'start',
|
|
1958
|
+
execFileSync('systemctl', ['--user', 'enable', daemonSystemdUnitName()], { encoding: 'utf-8' });
|
|
1959
|
+
execFileSync('systemctl', ['--user', 'start', daemonSystemdUnitName()], { encoding: 'utf-8' });
|
|
1772
1960
|
// Launch issued — the child needs this lock to claim (RUSH-2417).
|
|
1773
1961
|
releaseLock();
|
|
1774
1962
|
const pid = waitForPid(3000) ?? readServiceManagerPid();
|
|
@@ -2089,8 +2277,8 @@ export function stopDaemon() {
|
|
|
2089
2277
|
}
|
|
2090
2278
|
if (platform === 'linux') {
|
|
2091
2279
|
try {
|
|
2092
|
-
execFileSync('systemctl', ['--user', 'stop',
|
|
2093
|
-
execFileSync('systemctl', ['--user', 'disable',
|
|
2280
|
+
execFileSync('systemctl', ['--user', 'stop', daemonSystemdUnitName()], { encoding: 'utf-8' });
|
|
2281
|
+
execFileSync('systemctl', ['--user', 'disable', daemonSystemdUnitName()], { encoding: 'utf-8' });
|
|
2094
2282
|
}
|
|
2095
2283
|
catch (err) {
|
|
2096
2284
|
if (process.env.AGENTS_DEBUG) {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* enabled without pulling in the whole daemon lifecycle.
|
|
8
8
|
*/
|
|
9
9
|
/** Every service the daemon can host. IDs are kebab-case and stable. */
|
|
10
|
-
export type DaemonServiceId = 'secrets-broker' | 'scheduler' | 'monitors' | 'browser-ipc' | 'self-heal' | 'keychain-reap' | 'account-state' | 'watchdog' | 'device-probe' | 'state-dir-check';
|
|
10
|
+
export type DaemonServiceId = 'secrets-broker' | 'scheduler' | 'monitors' | 'browser-ipc' | 'webhook-receiver' | 'self-heal' | 'keychain-reap' | 'account-state' | 'watchdog' | 'device-probe' | 'state-dir-check';
|
|
11
11
|
/** Human-readable metadata for each service. */
|
|
12
12
|
export interface DaemonServiceDef {
|
|
13
13
|
id: DaemonServiceId;
|
|
@@ -32,6 +32,11 @@ export const DAEMON_SERVICES = [
|
|
|
32
32
|
title: 'Browser IPC',
|
|
33
33
|
description: 'Keeps a supervised browser automation IPC socket available for sessions.',
|
|
34
34
|
},
|
|
35
|
+
{
|
|
36
|
+
id: 'webhook-receiver',
|
|
37
|
+
title: 'Webhook receiver',
|
|
38
|
+
description: 'Hosts signed GitHub/Linear webhook ingress declared in daemon/webhooks.yaml, drawing signing secrets from the broker; binds nothing when no receivers are declared.',
|
|
39
|
+
},
|
|
35
40
|
{
|
|
36
41
|
id: 'self-heal',
|
|
37
42
|
title: 'Self-heal registry',
|
|
@@ -48,3 +48,28 @@ export declare function runActiveSessionsWarmTick(opts?: {
|
|
|
48
48
|
}): Promise<{
|
|
49
49
|
sessions: number;
|
|
50
50
|
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Session-index warm (RUSH-2682): incrementally scan THIS host's transcript dirs
|
|
53
|
+
* into the local SQLite index on a timer, so a session started HERE reaches this
|
|
54
|
+
* box's index within seconds instead of on the next unrelated `agents sessions*`
|
|
55
|
+
* call. Indexing was otherwise lazy — only `discoverSessions` writes the index,
|
|
56
|
+
* and nothing scheduled it — which inverted freshness: a peer's session arrived
|
|
57
|
+
* via sync in ~0s while a locally-started one sat unindexed for minutes.
|
|
58
|
+
*
|
|
59
|
+
* The scan is incremental (only files whose mtime/size changed) and single-flight
|
|
60
|
+
* across processes via the DB scan claim, so a foreground `agents sessions*` and
|
|
61
|
+
* this tick never double-scan. The daemon is the single scheduled executor,
|
|
62
|
+
* consistent with the one-scheduler rule.
|
|
63
|
+
*
|
|
64
|
+
* Calls `scanSessionsIncremental`, NOT `discoverSessions` (RUSH-2691). A bare
|
|
65
|
+
* `discoverSessions()` ends in a listing query that defaults its cwd filter to
|
|
66
|
+
* `process.cwd()` — the daemon's, i.e. `$HOME` — and caps at 50, so its row count
|
|
67
|
+
* described "sessions whose cwd is exactly $HOME", which is 0 on a normal box no
|
|
68
|
+
* matter how much the scan indexed. The tick reported that 0 every 20s while
|
|
69
|
+
* still paying for the query's existence check and Linear fetch. Scanning
|
|
70
|
+
* directly reports what was actually parsed and skips the query entirely.
|
|
71
|
+
*/
|
|
72
|
+
export declare function runSessionIndexWarmTick(): Promise<{
|
|
73
|
+
indexed: number;
|
|
74
|
+
claimed: boolean;
|
|
75
|
+
}>;
|
package/dist/lib/daemon-ticks.js
CHANGED
|
@@ -77,7 +77,7 @@ export async function runUsageRefreshTick() {
|
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
79
|
const { runUsageRefresh, buildLocalUsageAccounts } = await import('./usage-refresh.js');
|
|
80
|
-
const { writeClaudeUsageCache } = await import('./usage.js');
|
|
80
|
+
const { writeClaudeUsageCache } = await import('./accounting/usage.js');
|
|
81
81
|
const { usageRateLimitedUntil } = await import('./usage-backoff.js');
|
|
82
82
|
const r = await runUsageRefresh({
|
|
83
83
|
listAccounts: buildLocalUsageAccounts,
|
|
@@ -106,3 +106,33 @@ export async function runActiveSessionsWarmTick(opts = {}) {
|
|
|
106
106
|
console.log(`active-sessions warm: ${r.sessions.length} session(s) published`);
|
|
107
107
|
return { sessions: r.sessions.length };
|
|
108
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Session-index warm (RUSH-2682): incrementally scan THIS host's transcript dirs
|
|
111
|
+
* into the local SQLite index on a timer, so a session started HERE reaches this
|
|
112
|
+
* box's index within seconds instead of on the next unrelated `agents sessions*`
|
|
113
|
+
* call. Indexing was otherwise lazy — only `discoverSessions` writes the index,
|
|
114
|
+
* and nothing scheduled it — which inverted freshness: a peer's session arrived
|
|
115
|
+
* via sync in ~0s while a locally-started one sat unindexed for minutes.
|
|
116
|
+
*
|
|
117
|
+
* The scan is incremental (only files whose mtime/size changed) and single-flight
|
|
118
|
+
* across processes via the DB scan claim, so a foreground `agents sessions*` and
|
|
119
|
+
* this tick never double-scan. The daemon is the single scheduled executor,
|
|
120
|
+
* consistent with the one-scheduler rule.
|
|
121
|
+
*
|
|
122
|
+
* Calls `scanSessionsIncremental`, NOT `discoverSessions` (RUSH-2691). A bare
|
|
123
|
+
* `discoverSessions()` ends in a listing query that defaults its cwd filter to
|
|
124
|
+
* `process.cwd()` — the daemon's, i.e. `$HOME` — and caps at 50, so its row count
|
|
125
|
+
* described "sessions whose cwd is exactly $HOME", which is 0 on a normal box no
|
|
126
|
+
* matter how much the scan indexed. The tick reported that 0 every 20s while
|
|
127
|
+
* still paying for the query's existence check and Linear fetch. Scanning
|
|
128
|
+
* directly reports what was actually parsed and skips the query entirely.
|
|
129
|
+
*/
|
|
130
|
+
export async function runSessionIndexWarmTick() {
|
|
131
|
+
const { scanSessionsIncremental } = await import('./session/discover.js');
|
|
132
|
+
const { claimed, scanned } = await scanSessionsIncremental();
|
|
133
|
+
// A skipped claim is not a failure — a foreground `agents sessions*` is
|
|
134
|
+
// scanning right now and this tick would be a duplicate.
|
|
135
|
+
if (!claimed)
|
|
136
|
+
return { indexed: 0, claimed: false };
|
|
137
|
+
return { indexed: scanned, claimed: true };
|
|
138
|
+
}
|