@phnx-labs/agents-cli 1.22.35 → 1.22.38
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 +708 -2
- package/README.md +83 -43
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.d.ts +15 -0
- package/dist/bootstrap.js +1212 -0
- package/dist/commands/accounts.d.ts +4 -11
- package/dist/commands/accounts.js +159 -27
- package/dist/commands/artifacts-setup.d.ts +53 -0
- package/dist/commands/artifacts-setup.js +161 -0
- package/dist/commands/artifacts.d.ts +18 -0
- package/dist/commands/artifacts.js +58 -0
- package/dist/commands/attach.js +17 -4
- package/dist/commands/audit.d.ts +8 -8
- package/dist/commands/audit.js +57 -47
- package/dist/commands/browser.js +17 -11
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +0 -11
- package/dist/commands/computer-actions.js +33 -0
- package/dist/commands/computer-sessions-picker.d.ts +21 -0
- package/dist/commands/computer-sessions-picker.js +141 -0
- package/dist/commands/computer.d.ts +16 -0
- package/dist/commands/computer.js +37 -0
- package/dist/commands/config.d.ts +17 -0
- package/dist/commands/config.js +401 -0
- package/dist/commands/cp.d.ts +84 -0
- package/dist/commands/cp.js +231 -0
- package/dist/commands/daemon.js +243 -14
- package/dist/commands/detach-core.d.ts +1 -1
- package/dist/commands/detach-core.js +12 -2
- package/dist/commands/detach.js +1 -1
- package/dist/commands/doctor.js +64 -5
- package/dist/commands/events.d.ts +24 -12
- package/dist/commands/events.js +144 -28
- package/dist/commands/exec.js +86 -42
- package/dist/commands/feed.d.ts +1 -1
- package/dist/commands/feed.js +16 -8
- package/dist/commands/focus.d.ts +33 -1
- package/dist/commands/focus.js +177 -17
- package/dist/commands/funnel.d.ts +1 -1
- package/dist/commands/go.js +9 -8
- package/dist/commands/harness-wizard.d.ts +1 -0
- package/dist/commands/harness-wizard.js +18 -20
- package/dist/commands/harness.d.ts +2 -0
- package/dist/commands/harness.js +59 -26
- package/dist/commands/hooks.js +0 -11
- package/dist/commands/inspect.d.ts +94 -1
- package/dist/commands/inspect.js +866 -40
- package/dist/commands/lease.d.ts +4 -4
- package/dist/commands/lease.js +6 -6
- package/dist/commands/login.js +0 -13
- package/dist/commands/logs.d.ts +2 -2
- package/dist/commands/logs.js +2 -2
- package/dist/commands/mcp.js +7 -2
- package/dist/commands/memory.js +7 -2
- package/dist/commands/message.d.ts +1 -1
- package/dist/commands/message.js +37 -6
- package/dist/commands/models.js +71 -0
- package/dist/commands/monitors.d.ts +0 -1
- package/dist/commands/monitors.js +199 -16
- package/dist/commands/open.d.ts +18 -0
- package/dist/commands/open.js +57 -0
- package/dist/commands/packages.js +2 -107
- package/dist/commands/plugins.js +6 -3
- package/dist/commands/profiles.d.ts +1 -0
- package/dist/commands/profiles.js +16 -160
- package/dist/commands/projects.d.ts +28 -0
- package/dist/commands/projects.js +125 -5
- package/dist/commands/reconnect.js +9 -3
- package/dist/commands/repo.js +42 -1
- package/dist/commands/resource-view.d.ts +17 -0
- package/dist/commands/resource-view.js +36 -14
- package/dist/commands/resume.js +9 -2
- package/dist/commands/routines.d.ts +0 -2
- package/dist/commands/routines.js +473 -289
- package/dist/commands/secrets.js +52 -9
- package/dist/commands/sessions-export.d.ts +47 -0
- package/dist/commands/sessions-export.js +116 -6
- package/dist/commands/sessions-import.d.ts +17 -0
- package/dist/commands/sessions-import.js +114 -6
- package/dist/commands/sessions-migrate.d.ts +27 -0
- package/dist/commands/sessions-migrate.js +50 -9
- package/dist/commands/sessions-picker.js +23 -4
- package/dist/commands/sessions-resume.d.ts +5 -3
- package/dist/commands/sessions-resume.js +30 -8
- package/dist/commands/sessions-watch.d.ts +2 -0
- package/dist/commands/sessions-watch.js +53 -0
- package/dist/commands/sessions.d.ts +66 -3
- package/dist/commands/sessions.js +298 -47
- package/dist/commands/setup-browser.js +2 -2
- package/dist/commands/setup-mine.js +0 -1
- package/dist/commands/setup-preferences.js +1 -1
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.js +31 -5
- package/dist/commands/share.d.ts +87 -7
- package/dist/commands/share.js +320 -58
- package/dist/commands/skills.js +0 -11
- package/dist/commands/snapshot.js +1 -1
- package/dist/commands/ssh.d.ts +18 -0
- package/dist/commands/ssh.js +549 -210
- package/dist/commands/sync.d.ts +5 -0
- package/dist/commands/sync.js +212 -32
- package/dist/commands/teams.d.ts +13 -0
- package/dist/commands/teams.js +187 -30
- package/dist/commands/tickets.d.ts +2 -0
- package/dist/commands/tickets.js +43 -0
- package/dist/commands/update.js +2 -4
- package/dist/commands/usage.js +5 -3
- package/dist/commands/versions.js +11 -5
- package/dist/commands/view.js +15 -7
- package/dist/commands/webhook.d.ts +2 -2
- package/dist/commands/webhook.js +7 -7
- package/dist/index.d.ts +18 -2
- package/dist/index.js +53 -1264
- package/dist/lib/account-catalog.d.ts +18 -0
- package/dist/lib/account-catalog.js +38 -0
- package/dist/lib/account-provider-registry.d.ts +18 -0
- package/dist/lib/account-provider-registry.js +59 -0
- package/dist/lib/account-registry.d.ts +40 -0
- package/dist/lib/account-registry.js +239 -0
- package/dist/lib/account-schema.d.ts +44 -0
- package/dist/lib/account-schema.js +91 -0
- package/dist/lib/account-state-service.d.ts +21 -0
- package/dist/lib/account-state-service.js +60 -0
- package/dist/lib/activity.d.ts +1 -1
- package/dist/lib/activity.js +8 -1
- package/dist/lib/add-dir.d.ts +80 -0
- package/dist/lib/add-dir.js +241 -0
- package/dist/lib/agent-cli-commands.d.ts +11 -0
- package/dist/lib/agent-cli-commands.js +30 -0
- package/dist/lib/agents.js +44 -36
- package/dist/lib/answer-router.js +1 -1
- package/dist/lib/audit/log.d.ts +10 -27
- package/dist/lib/audit/log.js +20 -33
- package/dist/lib/auth-health.d.ts +9 -2
- package/dist/lib/auth-health.js +42 -9
- package/dist/lib/auto-pull-worker.js +7 -3
- package/dist/lib/auto-pull.d.ts +44 -3
- package/dist/lib/auto-pull.js +88 -5
- package/dist/lib/binary-shadow.d.ts +28 -0
- package/dist/lib/binary-shadow.js +121 -0
- package/dist/lib/brand.js +9 -3
- package/dist/lib/browser/hygiene.d.ts +90 -0
- package/dist/lib/browser/hygiene.js +146 -0
- package/dist/lib/browser/ipc.d.ts +30 -0
- package/dist/lib/browser/ipc.js +93 -4
- package/dist/lib/browser/profiles.d.ts +3 -2
- package/dist/lib/browser/profiles.js +65 -22
- package/dist/lib/browser/service.d.ts +79 -1
- package/dist/lib/browser/service.js +231 -14
- package/dist/lib/browser/sessions-list.d.ts +22 -2
- package/dist/lib/browser/sessions-list.js +54 -6
- package/dist/lib/browser/stream.d.ts +2 -0
- package/dist/lib/browser/stream.js +1 -0
- package/dist/lib/browser/types.d.ts +63 -1
- package/dist/lib/byok-usage.d.ts +9 -2
- package/dist/lib/byok-usage.js +133 -31
- package/dist/lib/cli-entry.d.ts +11 -0
- package/dist/lib/cli-entry.js +46 -0
- package/dist/lib/cloud/host.d.ts +1 -1
- package/dist/lib/cloud/host.js +2 -2
- package/dist/lib/cloud/registry.js +1 -1
- package/dist/lib/cloud/types.d.ts +1 -1
- package/dist/lib/commands.d.ts +2 -0
- package/dist/lib/commands.js +2 -0
- package/dist/lib/computer/sessions-list.d.ts +150 -0
- package/dist/lib/computer/sessions-list.js +363 -0
- package/dist/lib/config-keys.d.ts +86 -0
- package/dist/lib/config-keys.js +193 -0
- package/dist/lib/config-machine-keys.d.ts +12 -0
- package/dist/lib/config-machine-keys.js +17 -0
- package/dist/lib/config-transfer.js +3 -4
- package/dist/lib/crabbox/cli.d.ts +2 -2
- package/dist/lib/crabbox/cli.js +3 -3
- package/dist/lib/daemon-health.d.ts +22 -0
- package/dist/lib/daemon-health.js +33 -3
- package/dist/lib/daemon-services.d.ts +50 -0
- package/dist/lib/daemon-services.js +147 -0
- package/dist/lib/daemon-ticks.d.ts +35 -66
- package/dist/lib/daemon-ticks.js +77 -159
- package/dist/lib/daemon.d.ts +72 -4
- package/dist/lib/daemon.js +792 -202
- package/dist/lib/deeplink/register.d.ts +49 -0
- package/dist/lib/deeplink/register.js +253 -0
- package/dist/lib/deeplink/url.d.ts +34 -0
- package/dist/lib/deeplink/url.js +78 -0
- package/dist/lib/device-config.d.ts +124 -29
- package/dist/lib/device-config.js +346 -141
- package/dist/lib/devices/config-migration.d.ts +42 -0
- package/dist/lib/devices/config-migration.js +203 -0
- package/dist/lib/devices/connect.js +14 -7
- package/dist/lib/devices/doctor-findings.d.ts +4 -1
- package/dist/lib/devices/doctor-findings.js +20 -1
- package/dist/lib/devices/harness-inventory.d.ts +11 -2
- package/dist/lib/devices/harness-inventory.js +0 -0
- package/dist/lib/devices/health.d.ts +1 -1
- package/dist/lib/devices/health.js +1 -1
- package/dist/lib/devices/pending.d.ts +22 -1
- package/dist/lib/devices/pending.js +67 -2
- package/dist/lib/devices/registry.d.ts +0 -25
- package/dist/lib/devices/registry.js +2 -83
- package/dist/lib/devices/resolve-profile.d.ts +20 -0
- package/dist/lib/devices/resolve-profile.js +44 -0
- package/dist/lib/devices/rollout-verify.d.ts +101 -0
- package/dist/lib/devices/rollout-verify.js +193 -0
- package/dist/lib/devices/ssh-config.js +10 -6
- package/dist/lib/event-families.d.ts +28 -0
- package/dist/lib/event-families.js +159 -0
- package/dist/lib/event-stream.d.ts +9 -1
- package/dist/lib/event-stream.js +26 -9
- package/dist/lib/events.d.ts +9 -1
- package/dist/lib/events.js +21 -6
- package/dist/lib/exec.d.ts +30 -0
- package/dist/lib/exec.js +219 -121
- package/dist/lib/feed-broadcast.d.ts +25 -0
- package/dist/lib/feed-broadcast.js +33 -0
- package/dist/lib/feed.d.ts +1 -1
- package/dist/lib/feed.js +12 -2
- package/dist/lib/fleet/capture.js +15 -0
- package/dist/lib/fleet/manifest.js +9 -0
- package/dist/lib/fleet/types.d.ts +9 -0
- package/dist/lib/fleet-status.js +10 -8
- package/dist/lib/git.d.ts +21 -7
- package/dist/lib/git.js +122 -18
- package/dist/lib/hosts/dispatch.d.ts +8 -3
- package/dist/lib/hosts/dispatch.js +29 -3
- package/dist/lib/hosts/logs.d.ts +2 -2
- package/dist/lib/hosts/logs.js +2 -2
- package/dist/lib/hosts/option.js +1 -1
- package/dist/lib/hosts/passthrough.d.ts +2 -3
- package/dist/lib/hosts/passthrough.js +10 -24
- package/dist/lib/hosts/progress.js +2 -2
- package/dist/lib/hosts/providers/devices.d.ts +3 -3
- package/dist/lib/hosts/providers/devices.js +18 -12
- package/dist/lib/hosts/ready.d.ts +5 -1
- package/dist/lib/hosts/ready.js +9 -3
- package/dist/lib/hosts/reconcile.d.ts +2 -2
- package/dist/lib/hosts/reconcile.js +2 -2
- package/dist/lib/hosts/registry.js +14 -9
- package/dist/lib/hosts/remote-cmd.js +1 -1
- package/dist/lib/hosts/remote-os.d.ts +9 -6
- package/dist/lib/hosts/remote-os.js +13 -6
- package/dist/lib/hosts/routing-flag.d.ts +23 -0
- package/dist/lib/hosts/routing-flag.js +41 -0
- package/dist/lib/hosts/run-target.js +1 -1
- package/dist/lib/hosts/session-index.js +1 -1
- package/dist/lib/hosts/tasks.d.ts +6 -6
- package/dist/lib/hosts/tasks.js +4 -4
- package/dist/lib/hosts/types.js +1 -2
- package/dist/lib/installations/resolve.js +2 -8
- package/dist/lib/isolation-boundary-report.js +0 -1
- package/dist/lib/linear-cache.d.ts +7 -0
- package/dist/lib/linear-cache.js +31 -4
- package/dist/lib/linear-project-counts.d.ts +1 -1
- package/dist/lib/linear-project-counts.js +2 -3
- package/dist/lib/linear-projects.js +1 -1
- package/dist/lib/loop.d.ts +2 -2
- package/dist/lib/loop.js +1 -1
- package/dist/lib/mailbox-target.d.ts +1 -1
- package/dist/lib/mailbox-target.js +1 -1
- package/dist/lib/manifest.js +7 -4
- 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/snapshot.d.ts +3 -2
- package/dist/lib/menubar/snapshot.js +6 -2
- package/dist/lib/migrate-fold.d.ts +33 -0
- package/dist/lib/migrate-fold.js +130 -0
- package/dist/lib/migrate.d.ts +34 -34
- package/dist/lib/migrate.js +106 -128
- package/dist/lib/model-tier-overrides.d.ts +1 -1
- package/dist/lib/model-tier-overrides.js +15 -2
- package/dist/lib/monitors/config.d.ts +17 -3
- package/dist/lib/monitors/config.js +52 -18
- package/dist/lib/monitors/engine.d.ts +32 -1
- package/dist/lib/monitors/engine.js +94 -11
- package/dist/lib/monitors/fingerprint.d.ts +46 -0
- package/dist/lib/monitors/fingerprint.js +100 -0
- package/dist/lib/monitors/remote.d.ts +47 -0
- package/dist/lib/monitors/remote.js +81 -0
- package/dist/lib/monitors/state.d.ts +39 -0
- package/dist/lib/monitors/state.js +56 -0
- package/dist/lib/onepassword.d.ts +17 -0
- package/dist/lib/onepassword.js +52 -22
- package/dist/lib/open-url.js +1 -1
- package/dist/lib/picker.d.ts +14 -2
- package/dist/lib/picker.js +35 -13
- package/dist/lib/placement.d.ts +1 -1
- package/dist/lib/placement.js +1 -1
- package/dist/lib/pr-land-detach.d.ts +32 -0
- package/dist/lib/pr-land-detach.js +79 -0
- package/dist/lib/profiles-presets.js +13 -0
- package/dist/lib/profiles.d.ts +2 -0
- package/dist/lib/profiles.js +44 -1
- package/dist/lib/project-focus.d.ts +1 -1
- package/dist/lib/project-focus.js +1 -1
- package/dist/lib/project-probe.d.ts +4 -1
- package/dist/lib/project-probe.js +5 -4
- package/dist/lib/project-resources.js +2 -18
- package/dist/lib/project-root.d.ts +16 -0
- package/dist/lib/project-root.js +20 -2
- package/dist/lib/projects.d.ts +20 -1
- package/dist/lib/projects.js +78 -1
- package/dist/lib/refresh-coordinator.d.ts +24 -0
- package/dist/lib/refresh-coordinator.js +52 -0
- package/dist/lib/registry.d.ts +2 -2
- package/dist/lib/registry.js +1 -1
- package/dist/lib/resource-aliases.d.ts +13 -0
- package/dist/lib/resource-aliases.js +26 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.d.ts +16 -0
- package/dist/lib/resources.js +66 -10
- package/dist/lib/rotate.d.ts +3 -4
- package/dist/lib/rotate.js +4 -5
- package/dist/lib/routine-activation.d.ts +22 -2
- package/dist/lib/routine-activation.js +63 -16
- package/dist/lib/routine-context.d.ts +9 -2
- package/dist/lib/routine-context.js +21 -6
- package/dist/lib/routines-project.d.ts +58 -48
- package/dist/lib/routines-project.js +190 -159
- package/dist/lib/routines.d.ts +44 -7
- package/dist/lib/routines.js +92 -34
- package/dist/lib/run-defaults.d.ts +5 -0
- package/dist/lib/run-defaults.js +11 -1
- package/dist/lib/runner.d.ts +10 -8
- package/dist/lib/runner.js +122 -39
- 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.d.ts +10 -3
- package/dist/lib/secrets/agent.js +43 -8
- package/dist/lib/secrets/bundles.d.ts +1 -0
- package/dist/lib/secrets/bundles.js +92 -80
- package/dist/lib/secrets/index.js +32 -9
- package/dist/lib/secrets/install-helper.d.ts +4 -4
- package/dist/lib/secrets/install-helper.js +4 -4
- package/dist/lib/secrets/push.d.ts +40 -6
- package/dist/lib/secrets/push.js +58 -11
- package/dist/lib/secrets/read-backoff.d.ts +1 -1
- package/dist/lib/secrets/read-backoff.js +1 -1
- package/dist/lib/secrets/remote.d.ts +24 -0
- package/dist/lib/secrets/remote.js +54 -4
- package/dist/lib/self-update.d.ts +108 -0
- package/dist/lib/self-update.js +276 -1
- package/dist/lib/session/active.d.ts +89 -5
- package/dist/lib/session/active.js +165 -10
- package/dist/lib/session/actor-sidecar.d.ts +1 -1
- package/dist/lib/session/actor-sidecar.js +2 -1
- package/dist/lib/session/db.d.ts +176 -2
- package/dist/lib/session/db.js +484 -17
- package/dist/lib/session/discover.js +27 -4
- package/dist/lib/session/hook-sessions.js +2 -2
- package/dist/lib/session/host-link.d.ts +2 -2
- package/dist/lib/session/host-link.js +2 -2
- package/dist/lib/session/pid-registry.d.ts +21 -0
- package/dist/lib/session/pid-registry.js +57 -0
- package/dist/lib/session/remote-active.js +15 -1
- package/dist/lib/session/remote.js +2 -2
- package/dist/lib/session/session-cache.d.ts +14 -7
- package/dist/lib/session/session-cache.js +51 -9
- package/dist/lib/session/state.d.ts +2 -2
- package/dist/lib/session/state.js +1 -1
- package/dist/lib/session/sync/config.d.ts +10 -10
- package/dist/lib/session/sync/config.js +10 -10
- package/dist/lib/session/sync/r2.d.ts +34 -0
- package/dist/lib/session/sync/r2.js +123 -0
- package/dist/lib/session/throughput.d.ts +1 -1
- package/dist/lib/session/throughput.js +1 -1
- package/dist/lib/session/types.d.ts +23 -1
- package/dist/lib/session/types.js +15 -0
- package/dist/lib/session/viewing-in.d.ts +1 -1
- package/dist/lib/session/viewing-in.js +1 -1
- package/dist/lib/session/watch.d.ts +101 -0
- package/dist/lib/session/watch.js +242 -0
- package/dist/lib/share/analytics.js +1 -1
- package/dist/lib/share/capture.d.ts +1 -1
- package/dist/lib/share/capture.js +3 -3
- package/dist/lib/share/config.d.ts +6 -2
- package/dist/lib/share/config.js +6 -5
- package/dist/lib/share/delete.js +3 -3
- package/dist/lib/share/provision.d.ts +38 -0
- package/dist/lib/share/provision.js +51 -1
- package/dist/lib/share/publish.d.ts +40 -1
- package/dist/lib/share/publish.js +119 -6
- package/dist/lib/share/worker-template.d.ts +12 -1
- package/dist/lib/share/worker-template.js +83 -7
- package/dist/lib/shims.d.ts +17 -3
- package/dist/lib/shims.js +98 -26
- package/dist/lib/signin-badge.js +3 -2
- package/dist/lib/skills.js +2 -0
- package/dist/lib/smart-launch.d.ts +8 -8
- package/dist/lib/smart-launch.js +80 -59
- package/dist/lib/ssh-exec.d.ts +1 -1
- package/dist/lib/ssh-exec.js +1 -1
- package/dist/lib/staleness/prune.d.ts +88 -0
- package/dist/lib/staleness/prune.js +69 -0
- package/dist/lib/staleness/registry.d.ts +1 -1
- package/dist/lib/staleness/writers/commands.js +34 -2
- package/dist/lib/staleness/writers/hooks.js +16 -0
- package/dist/lib/staleness/writers/kinds.d.ts +6 -0
- package/dist/lib/staleness/writers/skills.js +19 -0
- package/dist/lib/staleness/writers/subagents.d.ts +2 -3
- package/dist/lib/staleness/writers/subagents.js +0 -4
- package/dist/lib/staleness/writers/types.d.ts +32 -0
- package/dist/lib/startup/command-registry.d.ts +16 -14
- package/dist/lib/startup/command-registry.js +26 -37
- package/dist/lib/startup/dev-build.d.ts +10 -0
- package/dist/lib/startup/dev-build.js +13 -1
- package/dist/lib/startup/spellcheck.d.ts +18 -0
- package/dist/lib/startup/spellcheck.js +45 -0
- package/dist/lib/state.d.ts +36 -9
- package/dist/lib/state.js +96 -46
- package/dist/lib/subagents-registry.d.ts +0 -7
- package/dist/lib/subagents-registry.js +38 -65
- package/dist/lib/subagents.d.ts +0 -33
- package/dist/lib/subagents.js +0 -75
- package/dist/lib/sync-umbrella.js +1 -1
- package/dist/lib/teams/agents.d.ts +41 -1
- package/dist/lib/teams/agents.js +187 -9
- package/dist/lib/teams/api.d.ts +11 -1
- package/dist/lib/teams/api.js +11 -2
- package/dist/lib/teams/delivery.d.ts +41 -0
- package/dist/lib/teams/delivery.js +60 -0
- package/dist/lib/teams/registry.d.ts +14 -0
- package/dist/lib/teams/registry.js +51 -1
- package/dist/lib/teams/remoteWorktree.d.ts +19 -0
- package/dist/lib/teams/remoteWorktree.js +29 -0
- package/dist/lib/teams/scheduler.d.ts +1 -1
- package/dist/lib/teams/scheduler.js +1 -1
- package/dist/lib/teams/worktree.d.ts +24 -0
- package/dist/lib/teams/worktree.js +42 -0
- package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
- package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
- package/dist/lib/terminal/engine.d.ts +4 -0
- package/dist/lib/terminal/engine.js +8 -2
- package/dist/lib/terminal/types.d.ts +21 -2
- package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
- package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
- package/dist/lib/tickets/list.d.ts +53 -0
- package/dist/lib/tickets/list.js +153 -0
- package/dist/lib/tmux/orphan-reap.d.ts +316 -0
- package/dist/lib/tmux/orphan-reap.js +638 -0
- package/dist/lib/tmux/session.d.ts +68 -3
- package/dist/lib/tmux/session.js +96 -5
- package/dist/lib/triggers/handlers.d.ts +20 -0
- package/dist/lib/triggers/handlers.js +16 -1
- package/dist/lib/triggers/webhook.js +10 -0
- package/dist/lib/types.d.ts +47 -35
- package/dist/lib/usage-fleet.d.ts +32 -0
- package/dist/lib/usage-fleet.js +125 -0
- package/dist/lib/usage-refresh.d.ts +3 -3
- package/dist/lib/usage-refresh.js +19 -16
- package/dist/lib/usage.d.ts +51 -47
- package/dist/lib/usage.js +145 -153
- package/dist/lib/version-duplicates.js +2 -2
- package/dist/lib/versions.d.ts +56 -13
- package/dist/lib/versions.js +195 -45
- package/dist/lib/watchdog/log.d.ts +1 -1
- package/dist/lib/watchdog/log.js +3 -3
- package/dist/lib/watchdog/rotate.d.ts +6 -6
- package/dist/lib/watchdog/rotate.js +6 -6
- package/dist/lib/workflows.d.ts +1 -1
- package/dist/lib/yaml-io.d.ts +47 -0
- package/dist/lib/yaml-io.js +55 -0
- package/package.json +2 -1
- package/scripts/install-helper.js +2 -2
- package/scripts/postinstall.js +23 -20
- package/dist/commands/defaults.d.ts +0 -7
- package/dist/commands/defaults.js +0 -107
- package/dist/commands/export.d.ts +0 -11
- package/dist/commands/export.js +0 -215
- package/dist/commands/helper.d.ts +0 -12
- package/dist/commands/helper.js +0 -87
- package/dist/commands/hosts.d.ts +0 -11
- package/dist/commands/hosts.js +0 -330
- package/dist/commands/lock.d.ts +0 -12
- package/dist/commands/lock.js +0 -70
- package/dist/commands/pull.d.ts +0 -17
- package/dist/commands/pull.js +0 -39
- package/dist/commands/push.d.ts +0 -14
- package/dist/commands/push.js +0 -30
- package/dist/commands/set.d.ts +0 -15
- package/dist/commands/set.js +0 -79
- package/dist/commands/setup-share.d.ts +0 -17
- package/dist/commands/setup-share.js +0 -85
- package/dist/commands/wallet.d.ts +0 -20
- package/dist/commands/wallet.js +0 -216
- package/dist/commands/worktree.d.ts +0 -19
- package/dist/commands/worktree.js +0 -272
- package/dist/lib/account-labels.d.ts +0 -24
- package/dist/lib/account-labels.js +0 -72
- package/dist/lib/auto-dispatch-linear.d.ts +0 -18
- package/dist/lib/auto-dispatch-linear.js +0 -107
- package/dist/lib/auto-dispatch-provider.d.ts +0 -10
- package/dist/lib/auto-dispatch-provider.js +0 -30
- package/dist/lib/auto-dispatch.d.ts +0 -93
- package/dist/lib/auto-dispatch.js +0 -128
- package/dist/lib/export.d.ts +0 -72
- package/dist/lib/export.js +0 -269
- package/dist/lib/lock.d.ts +0 -93
- package/dist/lib/lock.js +0 -207
- package/dist/lib/wallet/index.d.ts +0 -78
- package/dist/lib/wallet/index.js +0 -253
package/dist/lib/teams/agents.js
CHANGED
|
@@ -33,7 +33,7 @@ import { remoteShellFor } from '../hosts/remote-cmd.js';
|
|
|
33
33
|
import { resolveRemoteOsSync } from '../hosts/remote-os.js';
|
|
34
34
|
import { pullRemoteLogDelta, REMOTE_MIRROR_MAX_BYTES } from '../hosts/progress.js';
|
|
35
35
|
import { createRemoteWorktree, ensureRemoteRepo } from './remoteWorktree.js';
|
|
36
|
-
import { getTeam } from './registry.js';
|
|
36
|
+
import { getTeam, isTeamDisbanded } from './registry.js';
|
|
37
37
|
import { resolvePlacement, classifyExclusions, NoViableDeviceError } from './scheduler.js';
|
|
38
38
|
import { probePoolSignals } from './placement-probe.js';
|
|
39
39
|
import { readMaxConcurrentCaps } from '../device-config.js';
|
|
@@ -321,6 +321,24 @@ function extractTimestamp(raw) {
|
|
|
321
321
|
}
|
|
322
322
|
return null;
|
|
323
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Atomic JSON write: writes to a unique sibling tmp file then renames over the
|
|
326
|
+
* target. rename(2) is atomic on POSIX, so a process killed mid-write leaves
|
|
327
|
+
* either the previous valid meta.json or the new one, never a torn,
|
|
328
|
+
* unparseable file (RUSH-2429). Mirrors the identical pattern already used by
|
|
329
|
+
* `teams/registry.ts`'s `atomicWriteJson`.
|
|
330
|
+
*/
|
|
331
|
+
async function atomicWriteJson(p, data) {
|
|
332
|
+
const tmp = `${p}.tmp.${process.pid}.${randomUUID()}`;
|
|
333
|
+
await fs.writeFile(tmp, JSON.stringify(data, null, 2));
|
|
334
|
+
try {
|
|
335
|
+
await fs.rename(tmp, p);
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
await fs.unlink(tmp).catch(() => { });
|
|
339
|
+
throw err;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
324
342
|
/** Resolve a mode string to a validated Mode, falling back to the given default. */
|
|
325
343
|
export function resolveMode(requestedMode, defaultMode = 'plan') {
|
|
326
344
|
const normalizedDefault = normalizeModeValue(defaultMode);
|
|
@@ -526,6 +544,13 @@ export class AgentProcess {
|
|
|
526
544
|
// Worktree isolation: when non-null, this teammate runs in its own git worktree.
|
|
527
545
|
worktreeName = null;
|
|
528
546
|
worktreePath = null;
|
|
547
|
+
// The team's `--project`, if it has one. Stored as the NAME, not as resolved
|
|
548
|
+
// directories: an unpinned teammate on a `--devices` pool is placed at LAUNCH
|
|
549
|
+
// (maybeSchedulePlacement), so grants resolved at add time would carry this
|
|
550
|
+
// box's absolute paths onto whatever host the scheduler later picked — and
|
|
551
|
+
// would already have dropped any directory that exists only there. Resolving
|
|
552
|
+
// per launch is what makes local and remote placement both correct.
|
|
553
|
+
project = null;
|
|
529
554
|
// Distributed teams: when hostName is non-null, this teammate runs on another
|
|
530
555
|
// machine over SSH (the "remote-host" backend), not as a local process. These
|
|
531
556
|
// are set post-construction (like startTime/pid) — placement config at add
|
|
@@ -930,6 +955,18 @@ export class AgentProcess {
|
|
|
930
955
|
}
|
|
931
956
|
}
|
|
932
957
|
async saveMeta() {
|
|
958
|
+
// RUSH-2450: a long-lived supervisor (teams start --watch) holds AgentProcess
|
|
959
|
+
// objects in memory. After another process disbands the team and deletes
|
|
960
|
+
// every meta.json, the supervisor's next status refresh would re-write those
|
|
961
|
+
// files via saveMeta — resurrecting PENDING teammates the operator just
|
|
962
|
+
// disbanded, and making `teams start` re-launch already-merged work. Refuse
|
|
963
|
+
// when a disband tombstone is present (set by removeTeam / markTeamDisbanded).
|
|
964
|
+
// Not gated on "team not in registry" alone: tests and mid-add paths write
|
|
965
|
+
// meta before/without a registry entry, and those must keep working.
|
|
966
|
+
if (this.taskName && (await isTeamDisbanded(this.taskName))) {
|
|
967
|
+
debug(`saveMeta: refusing to re-persist ${this.agentId} — team '${this.taskName}' was disbanded`);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
933
970
|
const agentDir = await this.getAgentDir();
|
|
934
971
|
await fs.mkdir(agentDir, { recursive: true });
|
|
935
972
|
const meta = {
|
|
@@ -963,6 +1000,7 @@ export class AgentProcess {
|
|
|
963
1000
|
cloud_branch: this.cloudBranch,
|
|
964
1001
|
worktree_name: this.worktreeName,
|
|
965
1002
|
worktree_path: this.worktreePath,
|
|
1003
|
+
project: this.project,
|
|
966
1004
|
host_name: this.hostName,
|
|
967
1005
|
host_target: this.hostTarget,
|
|
968
1006
|
host_identity_file: this.hostIdentityFile,
|
|
@@ -973,20 +1011,61 @@ export class AgentProcess {
|
|
|
973
1011
|
remote_log_offset: this.remoteLogOffset,
|
|
974
1012
|
};
|
|
975
1013
|
const metaPath = await this.getMetaPath();
|
|
976
|
-
await
|
|
1014
|
+
await atomicWriteJson(metaPath, meta);
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Rename an unreadable meta.json out of the way so it stops silently
|
|
1018
|
+
* masquerading as "no record" (RUSH-2429). Before saveMeta() wrote atomically,
|
|
1019
|
+
* a process killed mid-write left a truncated, unparseable meta.json that
|
|
1020
|
+
* loadFromDisk() returned null for -- indistinguishable from ENOENT -- so
|
|
1021
|
+
* retention (loadExistingAgents/rescanFromDisk) never reaped it and
|
|
1022
|
+
* isWorktreeClaimed() (which reads meta.json directly, not through this
|
|
1023
|
+
* method) failed CLOSED on it forever: it scans every record and answers
|
|
1024
|
+
* "claimed" for every worktree name in every team the first time it cannot
|
|
1025
|
+
* read one. Quarantining removes meta.json so the NEXT read of this record
|
|
1026
|
+
* sees ENOENT (genuinely absent) instead of "unreadable" -- that is what lets
|
|
1027
|
+
* isWorktreeClaimed's fail-closed guard recover once the corrupt record is
|
|
1028
|
+
* gone, without weakening the guard itself for a record that is still
|
|
1029
|
+
* present-but-unreadable at decision time.
|
|
1030
|
+
*
|
|
1031
|
+
* Best-effort: if the rename itself fails (e.g. EACCES on the directory),
|
|
1032
|
+
* the record is left in place and the fail-closed guard keeps protecting
|
|
1033
|
+
* worktree removal -- quarantine only ever ADDS a recovery path.
|
|
1034
|
+
*/
|
|
1035
|
+
static async quarantineCorruptMeta(metaPath, cause) {
|
|
1036
|
+
const quarantinePath = `${metaPath}.corrupt`;
|
|
1037
|
+
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
1038
|
+
try {
|
|
1039
|
+
await fs.rename(metaPath, quarantinePath);
|
|
1040
|
+
console.warn(`[teams] quarantined unreadable meta.json (${reason}): ${metaPath} -> ${quarantinePath}`);
|
|
1041
|
+
}
|
|
1042
|
+
catch (renameErr) {
|
|
1043
|
+
console.warn(`[teams] found unreadable meta.json but could not quarantine it (${reason}): ${metaPath}: ` +
|
|
1044
|
+
`${renameErr?.message ?? renameErr}`);
|
|
1045
|
+
}
|
|
977
1046
|
}
|
|
978
1047
|
static async loadFromDisk(agentId, baseDir = null) {
|
|
979
1048
|
const base = baseDir || await getAgentsDir();
|
|
980
1049
|
const agentDir = path.join(base, agentId);
|
|
981
1050
|
const metaPath = path.join(agentDir, 'meta.json');
|
|
1051
|
+
let metaContent;
|
|
982
1052
|
try {
|
|
983
|
-
await fs.
|
|
1053
|
+
metaContent = await fs.readFile(metaPath, 'utf-8');
|
|
984
1054
|
}
|
|
985
|
-
catch {
|
|
1055
|
+
catch (err) {
|
|
1056
|
+
// A READ error is not a corrupt record. ENOENT proves the record is
|
|
1057
|
+
// genuinely ABSENT; anything else -- EACCES, EIO, a transient EMFILE
|
|
1058
|
+
// under fd pressure -- means the file exists and could not be read THIS
|
|
1059
|
+
// time, but its contents are intact. We MUST NOT quarantine (rename) it:
|
|
1060
|
+
// renaming a valid record away is exactly the fail-open that RUSH-2429
|
|
1061
|
+
// forbids -- isWorktreeClaimed() reads meta.json directly and fails
|
|
1062
|
+
// CLOSED on the same read error (safe), but a rename here would delete
|
|
1063
|
+
// the record it relies on and turn a live teammate's worktree into
|
|
1064
|
+
// "unclaimed", re-arming `git worktree remove --force` over uncommitted
|
|
1065
|
+
// work. Return null (skip this scan); the file stays for the next read.
|
|
986
1066
|
return null;
|
|
987
1067
|
}
|
|
988
1068
|
try {
|
|
989
|
-
const metaContent = await fs.readFile(metaPath, 'utf-8');
|
|
990
1069
|
const meta = JSON.parse(metaContent);
|
|
991
1070
|
// Legacy teammates may have mode='ralph', 'cloud', or 'full' from before
|
|
992
1071
|
// modes were narrowed/renamed. Coerce to the closest current mode so they
|
|
@@ -1026,9 +1105,15 @@ export class AgentProcess {
|
|
|
1026
1105
|
agent.remoteLog = meta.remote_log || null;
|
|
1027
1106
|
agent.remoteExit = meta.remote_exit || null;
|
|
1028
1107
|
agent.remoteLogOffset = typeof meta.remote_log_offset === 'number' ? meta.remote_log_offset : 0;
|
|
1108
|
+
// The team's project. Absent on every teammate added before `--project`.
|
|
1109
|
+
agent.project = typeof meta.project === 'string' ? meta.project : null;
|
|
1029
1110
|
return agent;
|
|
1030
1111
|
}
|
|
1031
|
-
catch {
|
|
1112
|
+
catch (err) {
|
|
1113
|
+
// The file exists but is not valid JSON (or fails a constructor
|
|
1114
|
+
// invariant) -- most likely a torn write from before saveMeta() became
|
|
1115
|
+
// atomic. Quarantine it; see quarantineCorruptMeta() above.
|
|
1116
|
+
await AgentProcess.quarantineCorruptMeta(metaPath, err);
|
|
1032
1117
|
return null;
|
|
1033
1118
|
}
|
|
1034
1119
|
}
|
|
@@ -1262,6 +1347,34 @@ export class AgentProcess {
|
|
|
1262
1347
|
}
|
|
1263
1348
|
}
|
|
1264
1349
|
}
|
|
1350
|
+
/**
|
|
1351
|
+
* The directories, beyond its cwd, a teammate may reach because of the team's
|
|
1352
|
+
* `--project`. Resolved at LAUNCH, from the project name on the record.
|
|
1353
|
+
*
|
|
1354
|
+
* Resolving here rather than at `teams add` is load-bearing for a pooled team:
|
|
1355
|
+
* an unpinned teammate has no host until `maybeSchedulePlacement` runs, so add
|
|
1356
|
+
* time cannot know whether to produce absolute local paths or `~/…` — and the
|
|
1357
|
+
* local form would additionally have dropped any directory that exists only on
|
|
1358
|
+
* the host it later landed on.
|
|
1359
|
+
*
|
|
1360
|
+
* A project that no longer resolves (renamed, definition deleted) yields no
|
|
1361
|
+
* grants rather than failing the launch: the teammate still gets its cwd.
|
|
1362
|
+
*/
|
|
1363
|
+
async function resolveTeammateGrants(agent, opts) {
|
|
1364
|
+
if (!agent.project)
|
|
1365
|
+
return [];
|
|
1366
|
+
try {
|
|
1367
|
+
const { resolveProjectDirs } = await import('../project-root.js');
|
|
1368
|
+
const { extraDirs } = await resolveProjectDirs(agent.project, opts);
|
|
1369
|
+
return extraDirs;
|
|
1370
|
+
}
|
|
1371
|
+
catch (err) {
|
|
1372
|
+
// Degrading is deliberate, but silently degrading is not: a teammate that
|
|
1373
|
+
// lost its grants to a renamed or deleted definition should leave a trace.
|
|
1374
|
+
debug(`teammate ${agent.agentId}: project '${agent.project}' did not resolve, no grants: ${err.message}`);
|
|
1375
|
+
return [];
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1265
1378
|
export async function beginResumeLogTransaction(agent) {
|
|
1266
1379
|
const stdoutPath = await agent.getStdoutPath();
|
|
1267
1380
|
const backupPath = `${stdoutPath}.resume-backup-${randomUUID()}`;
|
|
@@ -1608,7 +1721,7 @@ export class AgentManager {
|
|
|
1608
1721
|
}
|
|
1609
1722
|
return false;
|
|
1610
1723
|
}
|
|
1611
|
-
async spawn(taskName, agentType, prompt, cwd = null, mode = null, effort = 'medium', parentSessionId = null, workspaceDir = null, version = null, name = null, after = [], model = null, envOverrides = null, taskType = null, cloudProvider = null, cloudSessionId = null, cloudRepo = null, cloudBranch = null, worktreeName = null, worktreePath = null, profileName = null, hostName = null, hostTarget = null, repoPath = null) {
|
|
1724
|
+
async spawn(taskName, agentType, prompt, cwd = null, mode = null, effort = 'medium', parentSessionId = null, workspaceDir = null, version = null, name = null, after = [], model = null, envOverrides = null, taskType = null, cloudProvider = null, cloudSessionId = null, cloudRepo = null, cloudBranch = null, worktreeName = null, worktreePath = null, profileName = null, hostName = null, hostTarget = null, repoPath = null, project = null) {
|
|
1612
1725
|
await this.initialize();
|
|
1613
1726
|
const resolvedMode = resolveMode(mode, this.defaultMode);
|
|
1614
1727
|
// Lineage (RUSH-2019): when the caller didn't name a parent, inherit the
|
|
@@ -1666,6 +1779,10 @@ export class AgentManager {
|
|
|
1666
1779
|
agent.hostName = hostName;
|
|
1667
1780
|
agent.hostTarget = hostTarget;
|
|
1668
1781
|
agent.repoPath = repoPath;
|
|
1782
|
+
// Must be set BEFORE the launch below — this method launches inline for a
|
|
1783
|
+
// teammate with no unmet --after deps, so assigning it after spawn()
|
|
1784
|
+
// returns would miss the only launch that matters.
|
|
1785
|
+
agent.project = project;
|
|
1669
1786
|
const agentDir = await agent.getAgentDir();
|
|
1670
1787
|
try {
|
|
1671
1788
|
await fs.mkdir(agentDir, { recursive: true });
|
|
@@ -1818,7 +1935,7 @@ export class AgentManager {
|
|
|
1818
1935
|
// forwarded). Effort is a separate knob wired into buildReasoningFlags
|
|
1819
1936
|
// inside buildCommand.
|
|
1820
1937
|
const resolvedModel = agent.model ?? null;
|
|
1821
|
-
const cmd = this.buildCommand(agent.agentType, agent.prompt, agent.mode, resolvedModel, agent.cwd, agent.agentId, effort, agent.version, agent.profileName, resume);
|
|
1938
|
+
const cmd = this.buildCommand(agent.agentType, agent.prompt, agent.mode, resolvedModel, agent.cwd, agent.agentId, effort, agent.version, agent.profileName, resume, await resolveTeammateGrants(agent, { forRemote: false }));
|
|
1822
1939
|
debug(`Launching ${agent.agentType} agent ${agent.agentId} [${agent.mode}]${resume ? ' (resume)' : ''}: ${cmd.slice(0, 3).join(' ')}...`);
|
|
1823
1940
|
let childProcess = null;
|
|
1824
1941
|
let stdoutFile = null;
|
|
@@ -1954,6 +2071,15 @@ export class AgentManager {
|
|
|
1954
2071
|
// — the supervisor polls the host, we don't block here.
|
|
1955
2072
|
const effort = agent.effort ?? 'medium';
|
|
1956
2073
|
const forwardedArgs = this.buildRunArgv(agent.agentType, agent.prompt, agent.mode, agent.model ?? null, effort, agent.version, agent.profileName, resume);
|
|
2074
|
+
// Project grants for a remote teammate, resolved HERE rather than at add
|
|
2075
|
+
// time: an unpinned teammate only learns its host from the scheduler, which
|
|
2076
|
+
// runs at launch. `forRemote: true` keeps them `~/…` and skips this box's
|
|
2077
|
+
// existence check — the host has its own checkouts. The remote `agents run`
|
|
2078
|
+
// expands `~` against the host's HOME before handing it to the harness.
|
|
2079
|
+
for (const dir of await resolveTeammateGrants(agent, { forRemote: true })) {
|
|
2080
|
+
if (dir !== remoteCwd)
|
|
2081
|
+
forwardedArgs.push('--add-dir', dir);
|
|
2082
|
+
}
|
|
1957
2083
|
let dispatchedTask = null;
|
|
1958
2084
|
let resumeLog = null;
|
|
1959
2085
|
try {
|
|
@@ -2305,7 +2431,7 @@ export class AgentManager {
|
|
|
2305
2431
|
args.push('--env', 'AGENTS_RUNTIME=teams');
|
|
2306
2432
|
return args;
|
|
2307
2433
|
}
|
|
2308
|
-
buildCommand(agentType, prompt, mode, model, cwd = null, sessionId = null, effort = 'medium', version = null, profileName = null, resume) {
|
|
2434
|
+
buildCommand(agentType, prompt, mode, model, cwd = null, sessionId = null, effort = 'medium', version = null, profileName = null, resume, addDirs = []) {
|
|
2309
2435
|
// Route through getAgentsInvocation so a teammate launched by the compiled
|
|
2310
2436
|
// standalone binary (#315) doesn't relaunch as `agents /$bunfs/root/agents …`
|
|
2311
2437
|
// (process.argv[1] is the bun virtual entry there) → "unknown command".
|
|
@@ -2326,6 +2452,14 @@ export class AgentManager {
|
|
|
2326
2452
|
if (agentType === 'claude' && cwd) {
|
|
2327
2453
|
cmd.push('--add-dir', cwd);
|
|
2328
2454
|
}
|
|
2455
|
+
// The team's project directories, beyond the one the teammate sits in.
|
|
2456
|
+
// `agents run` re-dedupes, but skipping cwd here keeps the launch line
|
|
2457
|
+
// readable. Codex folds these into its workspace_roots; other harnesses
|
|
2458
|
+
// ignore --add-dir entirely.
|
|
2459
|
+
for (const dir of new Set(addDirs)) {
|
|
2460
|
+
if (dir !== cwd)
|
|
2461
|
+
cmd.push('--add-dir', dir);
|
|
2462
|
+
}
|
|
2329
2463
|
// Codex's workspace-write sandbox blocks writes outside cwd. Factory
|
|
2330
2464
|
// teammates need to run further `agents teams add` commands, which
|
|
2331
2465
|
// write to ~/.agents/. Grant that root so subprocess-issued
|
|
@@ -2407,6 +2541,50 @@ export class AgentManager {
|
|
|
2407
2541
|
const all = await this.listAll();
|
|
2408
2542
|
return all.filter(a => a.taskName === taskName);
|
|
2409
2543
|
}
|
|
2544
|
+
/**
|
|
2545
|
+
* Terminal removal of every teammate record for a team (RUSH-2450).
|
|
2546
|
+
*
|
|
2547
|
+
* `teams disband` used to delete log dirs and the registry entry, but left
|
|
2548
|
+
* the in-memory AgentProcess cache intact. A concurrent `teams start --watch`
|
|
2549
|
+
* supervisor then re-persisted those records via saveMeta, so a second
|
|
2550
|
+
* disband still found N logs to clear and `teams start` could re-launch
|
|
2551
|
+
* PENDING work that had already merged.
|
|
2552
|
+
*
|
|
2553
|
+
* This drops every matching record from the manager map AND removes its
|
|
2554
|
+
* durable state. With `keepLogs`, only `meta.json` is removed so the
|
|
2555
|
+
* teammate is no longer discoverable/startable while stdout/stderr logs
|
|
2556
|
+
* remain for postmortem.
|
|
2557
|
+
*
|
|
2558
|
+
* Returns the agent_ids that were purged.
|
|
2559
|
+
*/
|
|
2560
|
+
async purgeByTask(taskName, opts) {
|
|
2561
|
+
await this.initialize();
|
|
2562
|
+
const roster = await this.listByTask(taskName);
|
|
2563
|
+
const purged = [];
|
|
2564
|
+
const base = this.agentsDir || (await getAgentsDir());
|
|
2565
|
+
for (const agent of roster) {
|
|
2566
|
+
this.agents.delete(agent.agentId);
|
|
2567
|
+
const agentDir = path.join(base, agent.agentId);
|
|
2568
|
+
try {
|
|
2569
|
+
if (opts?.keepLogs) {
|
|
2570
|
+
// Keep log files; remove only the record that makes the teammate
|
|
2571
|
+
// reappear in list/status/start.
|
|
2572
|
+
await fs.rm(path.join(agentDir, 'meta.json'), { force: true });
|
|
2573
|
+
}
|
|
2574
|
+
else {
|
|
2575
|
+
await fs.rm(agentDir, { recursive: true, force: true });
|
|
2576
|
+
}
|
|
2577
|
+
purged.push(agent.agentId);
|
|
2578
|
+
}
|
|
2579
|
+
catch (err) {
|
|
2580
|
+
debug(`purgeByTask: failed to remove ${agent.agentId}: ${err}`);
|
|
2581
|
+
// Still count as purged from the roster — the in-memory drop above is
|
|
2582
|
+
// the load-bearing half against same-process resurrection.
|
|
2583
|
+
purged.push(agent.agentId);
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
return purged;
|
|
2587
|
+
}
|
|
2410
2588
|
async listByParentSession(parentSessionId) {
|
|
2411
2589
|
const all = await this.listAll();
|
|
2412
2590
|
return all.filter(a => a.parentSessionId === parentSessionId);
|
package/dist/lib/teams/api.d.ts
CHANGED
|
@@ -46,6 +46,12 @@ export interface AgentStatusDetail {
|
|
|
46
46
|
cloud_session_id?: string | null;
|
|
47
47
|
cloud_provider?: string | null;
|
|
48
48
|
pr_url?: string | null;
|
|
49
|
+
/**
|
|
50
|
+
* Delivery postcondition (RUSH-2380), distinct from process `status`.
|
|
51
|
+
* `pr_open` when the process completed but left an unmerged PR — orchestrators
|
|
52
|
+
* must not treat that as "work landed on main".
|
|
53
|
+
*/
|
|
54
|
+
delivery?: string;
|
|
49
55
|
version?: string | null;
|
|
50
56
|
remote_session_id?: string | null;
|
|
51
57
|
session_label?: string | null;
|
|
@@ -84,6 +90,8 @@ export interface AgentStatusSummary {
|
|
|
84
90
|
name: string | null;
|
|
85
91
|
agent_type: string;
|
|
86
92
|
status: string;
|
|
93
|
+
/** Delivery postcondition — see {@link AgentStatusDetail.delivery}. */
|
|
94
|
+
delivery?: string;
|
|
87
95
|
duration: string | null;
|
|
88
96
|
tool_count: number;
|
|
89
97
|
has_errors: boolean;
|
|
@@ -162,7 +170,9 @@ export interface TasksResult {
|
|
|
162
170
|
tasks: TaskInfo[];
|
|
163
171
|
}
|
|
164
172
|
/** Spawn a new teammate in a task and return its initial metadata. */
|
|
165
|
-
export declare function handleSpawn(manager: AgentManager, taskName: string, agentType: AgentType, prompt: string, cwd: string | null, mode: string | null, effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'auto' | null, parentSessionId?: string | null, workspaceDir?: string | null, version?: string | null, name?: string | null, after?: string[], model?: string | null, envOverrides?: Record<string, string> | null, taskType?: TaskType | null, cloudProvider?: string | null, cloudSessionId?: string | null, cloudRepo?: string | null, cloudBranch?: string | null, worktreeName?: string | null, worktreePath?: string | null, profileName?: string | null, hostName?: string | null, hostTarget?: string | null, repoPath?: string | null
|
|
173
|
+
export declare function handleSpawn(manager: AgentManager, taskName: string, agentType: AgentType, prompt: string, cwd: string | null, mode: string | null, effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'auto' | null, parentSessionId?: string | null, workspaceDir?: string | null, version?: string | null, name?: string | null, after?: string[], model?: string | null, envOverrides?: Record<string, string> | null, taskType?: TaskType | null, cloudProvider?: string | null, cloudSessionId?: string | null, cloudRepo?: string | null, cloudBranch?: string | null, worktreeName?: string | null, worktreePath?: string | null, profileName?: string | null, hostName?: string | null, hostTarget?: string | null, repoPath?: string | null,
|
|
174
|
+
/** The team's `--project`; grants resolve from it at launch. */
|
|
175
|
+
project?: string | null): Promise<SpawnResult>;
|
|
166
176
|
/** Retrieve the current status of all teammates in a task, with optional timestamp-based delta filtering. */
|
|
167
177
|
export declare function handleStatus(manager: AgentManager, taskName: string | null | undefined, filter?: string, since?: string, // Optional ISO timestamp - return only events after this time
|
|
168
178
|
parentSessionId?: string | null): Promise<TaskStatusResult>;
|
package/dist/lib/teams/api.js
CHANGED
|
@@ -2,6 +2,7 @@ import { AgentStatus, resolveMode } from './agents.js';
|
|
|
2
2
|
import { getDelta } from './summarizer.js';
|
|
3
3
|
import { debug } from './debug.js';
|
|
4
4
|
import { buildClaudeLabelMap } from '../session/discover.js';
|
|
5
|
+
import { resolveTeammateDelivery } from './delivery.js';
|
|
5
6
|
/**
|
|
6
7
|
* Truncate a bash command for status output.
|
|
7
8
|
* Handles heredocs specially - shows the redirect target instead of contents.
|
|
@@ -107,6 +108,8 @@ export function toAgentStatusSummary(detail) {
|
|
|
107
108
|
name: detail.name ?? null,
|
|
108
109
|
agent_type: detail.agent_type,
|
|
109
110
|
status: detail.status,
|
|
111
|
+
delivery: detail.delivery ??
|
|
112
|
+
resolveTeammateDelivery({ status: detail.status, prUrl: detail.pr_url }),
|
|
110
113
|
duration: detail.duration,
|
|
111
114
|
tool_count: detail.tool_count,
|
|
112
115
|
has_errors: detail.has_errors,
|
|
@@ -135,7 +138,9 @@ export function toTaskStatusSummary(result) {
|
|
|
135
138
|
};
|
|
136
139
|
}
|
|
137
140
|
/** Spawn a new teammate in a task and return its initial metadata. */
|
|
138
|
-
export async function handleSpawn(manager, taskName, agentType, prompt, cwd, mode, effort = 'medium', parentSessionId = null, workspaceDir = null, version = null, name = null, after = [], model = null, envOverrides = null, taskType = null, cloudProvider = null, cloudSessionId = null, cloudRepo = null, cloudBranch = null, worktreeName = null, worktreePath = null, profileName = null, hostName = null, hostTarget = null, repoPath = null
|
|
141
|
+
export async function handleSpawn(manager, taskName, agentType, prompt, cwd, mode, effort = 'medium', parentSessionId = null, workspaceDir = null, version = null, name = null, after = [], model = null, envOverrides = null, taskType = null, cloudProvider = null, cloudSessionId = null, cloudRepo = null, cloudBranch = null, worktreeName = null, worktreePath = null, profileName = null, hostName = null, hostTarget = null, repoPath = null,
|
|
142
|
+
/** The team's `--project`; grants resolve from it at launch. */
|
|
143
|
+
project = null) {
|
|
139
144
|
const defaultMode = manager.getDefaultMode();
|
|
140
145
|
const resolvedMode = resolveMode(mode, defaultMode);
|
|
141
146
|
const resolvedEffort = effort ?? 'medium';
|
|
@@ -160,7 +165,7 @@ export async function handleSpawn(manager, taskName, agentType, prompt, cwd, mod
|
|
|
160
165
|
throw new Error(`[budget] BLOCKED teammate "${taskName}" (${agentType}): ${gate.decision.reason}`);
|
|
161
166
|
}
|
|
162
167
|
}
|
|
163
|
-
const agent = await manager.spawn(taskName, agentType, prompt, cwd, resolvedMode, resolvedEffort, parentSessionId, workspaceDir, version, name, after, model, envOverrides, taskType, cloudProvider, cloudSessionId, cloudRepo, cloudBranch, worktreeName, worktreePath, profileName, hostName, hostTarget, repoPath);
|
|
168
|
+
const agent = await manager.spawn(taskName, agentType, prompt, cwd, resolvedMode, resolvedEffort, parentSessionId, workspaceDir, version, name, after, model, envOverrides, taskType, cloudProvider, cloudSessionId, cloudRepo, cloudBranch, worktreeName, worktreePath, profileName, hostName, hostTarget, repoPath, project);
|
|
164
169
|
debug(`[spawn] Spawned ${agentType} agent ${agent.agentId} for task "${taskName}"`);
|
|
165
170
|
return {
|
|
166
171
|
task_name: taskName,
|
|
@@ -252,6 +257,10 @@ parentSessionId) {
|
|
|
252
257
|
cloud_session_id: agent.cloudSessionId,
|
|
253
258
|
cloud_provider: agent.cloudProvider,
|
|
254
259
|
pr_url: agent.prUrl,
|
|
260
|
+
delivery: resolveTeammateDelivery({
|
|
261
|
+
status: agent.status,
|
|
262
|
+
prUrl: agent.prUrl,
|
|
263
|
+
}),
|
|
255
264
|
files_created: delta.new_files_created,
|
|
256
265
|
files_modified: delta.new_files_modified,
|
|
257
266
|
files_read: delta.new_files_read,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Teammate *delivery* vs process *lifecycle* (RUSH-2380).
|
|
3
|
+
*
|
|
4
|
+
* `AgentStatus.COMPLETED` means the process exited 0 — not that the PR merged.
|
|
5
|
+
* Orchestrators that treat COMPLETED as "work landed on main" compose on top of
|
|
6
|
+
* unmerged PRs. This module derives a delivery signal from process status +
|
|
7
|
+
* whether a PR URL is still open, so `teams status` can surface `PR OPEN`
|
|
8
|
+
* instead of bare COMPLETED.
|
|
9
|
+
*
|
|
10
|
+
* Process status still drives the DAG (`--after` deps): a finished process
|
|
11
|
+
* unblocks dependents. Delivery is the postcondition for "done end-to-end".
|
|
12
|
+
*/
|
|
13
|
+
import { AgentStatus } from './agents.js';
|
|
14
|
+
/** Postcondition-facing delivery of a teammate's work. */
|
|
15
|
+
export type TeammateDelivery = 'pending' | 'in_progress' | 'pr_open' | 'pr_merged' | 'no_pr' | 'failed' | 'stopped';
|
|
16
|
+
/**
|
|
17
|
+
* Derive delivery from process status and PR state.
|
|
18
|
+
*
|
|
19
|
+
* When the process completed with a `prUrl` and merge is unknown or false,
|
|
20
|
+
* delivery is `pr_open` — pessimistic: assume open until proven merged so an
|
|
21
|
+
* orchestrator never mistakes "agent stopped" for "work on main".
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveTeammateDelivery(opts: {
|
|
24
|
+
status: AgentStatus | string;
|
|
25
|
+
prUrl?: string | null;
|
|
26
|
+
/**
|
|
27
|
+
* When known from a probe or meta: true = merged, false = still open.
|
|
28
|
+
* `null`/`undefined` = unknown; with a `prUrl` that means `pr_open`.
|
|
29
|
+
*/
|
|
30
|
+
prMerged?: boolean | null;
|
|
31
|
+
}): TeammateDelivery;
|
|
32
|
+
/**
|
|
33
|
+
* Human label for `teams status` rows. Replaces bare COMPLETED with PR OPEN
|
|
34
|
+
* when delivery is still pending merge.
|
|
35
|
+
*/
|
|
36
|
+
export declare function deliveryDisplayLabel(delivery: TeammateDelivery, processStatus: AgentStatus | string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Color key for statusColor-style switches. `pr_open` is its own key so the
|
|
39
|
+
* row is visually distinct from green COMPLETED.
|
|
40
|
+
*/
|
|
41
|
+
export declare function deliveryColorKey(delivery: TeammateDelivery, processStatus: string): string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Teammate *delivery* vs process *lifecycle* (RUSH-2380).
|
|
3
|
+
*
|
|
4
|
+
* `AgentStatus.COMPLETED` means the process exited 0 — not that the PR merged.
|
|
5
|
+
* Orchestrators that treat COMPLETED as "work landed on main" compose on top of
|
|
6
|
+
* unmerged PRs. This module derives a delivery signal from process status +
|
|
7
|
+
* whether a PR URL is still open, so `teams status` can surface `PR OPEN`
|
|
8
|
+
* instead of bare COMPLETED.
|
|
9
|
+
*
|
|
10
|
+
* Process status still drives the DAG (`--after` deps): a finished process
|
|
11
|
+
* unblocks dependents. Delivery is the postcondition for "done end-to-end".
|
|
12
|
+
*/
|
|
13
|
+
import { AgentStatus } from './agents.js';
|
|
14
|
+
/**
|
|
15
|
+
* Derive delivery from process status and PR state.
|
|
16
|
+
*
|
|
17
|
+
* When the process completed with a `prUrl` and merge is unknown or false,
|
|
18
|
+
* delivery is `pr_open` — pessimistic: assume open until proven merged so an
|
|
19
|
+
* orchestrator never mistakes "agent stopped" for "work on main".
|
|
20
|
+
*/
|
|
21
|
+
export function resolveTeammateDelivery(opts) {
|
|
22
|
+
const status = String(opts.status);
|
|
23
|
+
if (status === AgentStatus.PENDING || status === 'pending')
|
|
24
|
+
return 'pending';
|
|
25
|
+
if (status === AgentStatus.RUNNING || status === 'running')
|
|
26
|
+
return 'in_progress';
|
|
27
|
+
if (status === AgentStatus.FAILED || status === 'failed')
|
|
28
|
+
return 'failed';
|
|
29
|
+
if (status === AgentStatus.STOPPED || status === 'stopped')
|
|
30
|
+
return 'stopped';
|
|
31
|
+
if (status === AgentStatus.COMPLETED || status === 'completed') {
|
|
32
|
+
const prUrl = opts.prUrl?.trim();
|
|
33
|
+
if (!prUrl)
|
|
34
|
+
return 'no_pr';
|
|
35
|
+
if (opts.prMerged === true)
|
|
36
|
+
return 'pr_merged';
|
|
37
|
+
return 'pr_open';
|
|
38
|
+
}
|
|
39
|
+
return 'in_progress';
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Human label for `teams status` rows. Replaces bare COMPLETED with PR OPEN
|
|
43
|
+
* when delivery is still pending merge.
|
|
44
|
+
*/
|
|
45
|
+
export function deliveryDisplayLabel(delivery, processStatus) {
|
|
46
|
+
if (delivery === 'pr_open')
|
|
47
|
+
return 'PR OPEN';
|
|
48
|
+
if (delivery === 'pr_merged')
|
|
49
|
+
return 'COMPLETED';
|
|
50
|
+
return String(processStatus).toUpperCase();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Color key for statusColor-style switches. `pr_open` is its own key so the
|
|
54
|
+
* row is visually distinct from green COMPLETED.
|
|
55
|
+
*/
|
|
56
|
+
export function deliveryColorKey(delivery, processStatus) {
|
|
57
|
+
if (delivery === 'pr_open')
|
|
58
|
+
return 'pr_open';
|
|
59
|
+
return String(processStatus);
|
|
60
|
+
}
|
|
@@ -18,6 +18,12 @@ export interface TeamMeta {
|
|
|
18
18
|
* `origin` at create time. Used by `ensureRemoteRepo` to provision the repo.
|
|
19
19
|
*/
|
|
20
20
|
repo?: string;
|
|
21
|
+
/**
|
|
22
|
+
* The project (`agents projects`) this team works on. Its primary directory
|
|
23
|
+
* is a local teammate's base cwd when neither `--cwd` nor a worktree gives
|
|
24
|
+
* one, and its other bound directories become `--add-dir` grants.
|
|
25
|
+
*/
|
|
26
|
+
project?: string;
|
|
21
27
|
}
|
|
22
28
|
/** Map of team name to team metadata. */
|
|
23
29
|
export type TeamRegistry = Record<string, TeamMeta>;
|
|
@@ -37,11 +43,19 @@ export interface CreateTeamOptions {
|
|
|
37
43
|
devices?: string[];
|
|
38
44
|
/** How each device gets the code (git URL to clone, or a path on the host). */
|
|
39
45
|
repo?: string;
|
|
46
|
+
/** The `agents projects` project this team works on. */
|
|
47
|
+
project?: string;
|
|
40
48
|
}
|
|
41
49
|
/** Create a new team. Throws if a team with the same name already exists. */
|
|
42
50
|
export declare function createTeam(name: string, options?: CreateTeamOptions): Promise<TeamMeta>;
|
|
43
51
|
/** Return existing team metadata or create a new team if it does not exist. */
|
|
44
52
|
export declare function ensureTeam(name: string): Promise<TeamMeta>;
|
|
53
|
+
/** Mark a team as disbanded so saveMeta will not resurrect its teammates. */
|
|
54
|
+
export declare function markTeamDisbanded(name: string): Promise<void>;
|
|
55
|
+
/** Clear a disband tombstone — called when the name is re-created. */
|
|
56
|
+
export declare function clearTeamDisbanded(name: string): Promise<void>;
|
|
57
|
+
/** True when the team was disbanded and has not been re-created since. */
|
|
58
|
+
export declare function isTeamDisbanded(name: string): Promise<boolean>;
|
|
45
59
|
/** Remove a team from the registry. Returns false if the team did not exist. */
|
|
46
60
|
export declare function removeTeam(name: string): Promise<boolean>;
|
|
47
61
|
/** Check whether a team with the given name exists in the registry. */
|
|
@@ -111,11 +111,15 @@ export async function createTeam(name, options) {
|
|
|
111
111
|
...(options?.useWorktree ? { use_worktree: options.useWorktree } : {}),
|
|
112
112
|
...(options?.devices && options.devices.length ? { devices: options.devices } : {}),
|
|
113
113
|
...(options?.repo ? { repo: options.repo } : {}),
|
|
114
|
+
...(options?.project ? { project: options.project } : {}),
|
|
114
115
|
};
|
|
115
116
|
reg[name] = m;
|
|
116
117
|
await saveTeams(reg);
|
|
117
118
|
return m;
|
|
118
119
|
});
|
|
120
|
+
// A re-created name is a fresh team — drop any prior disband tombstone so
|
|
121
|
+
// saveMeta will persist new teammates again (RUSH-2450).
|
|
122
|
+
await clearTeamDisbanded(name);
|
|
119
123
|
// Audit the lifecycle boundary, not the CLI shell — captures every creation
|
|
120
124
|
// path (create + ensure) with team metadata the generic command log lacks.
|
|
121
125
|
emit('teams.create', { module: 'teams', team: name, worktrees: Boolean(options?.enableWorktrees || options?.useWorktree) });
|
|
@@ -137,10 +141,52 @@ export async function ensureTeam(name) {
|
|
|
137
141
|
});
|
|
138
142
|
// `teams add` auto-creates the team on first teammate — audit that creation
|
|
139
143
|
// too, but only when it actually happened (not the get-existing path).
|
|
140
|
-
if (created)
|
|
144
|
+
if (created) {
|
|
145
|
+
await clearTeamDisbanded(name);
|
|
141
146
|
emit('teams.create', { module: 'teams', team: name, worktrees: false });
|
|
147
|
+
}
|
|
142
148
|
return meta;
|
|
143
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Tombstone dir for disbanded teams (RUSH-2450). Lives next to the registry so
|
|
152
|
+
* a long-lived supervisor can see that a team was deliberately removed and
|
|
153
|
+
* refuse to re-persist its in-memory AgentProcess objects via saveMeta.
|
|
154
|
+
* Cleared on create/ensure so a re-used name is a fresh team.
|
|
155
|
+
*/
|
|
156
|
+
function disbandedDir() {
|
|
157
|
+
return path.join(path.dirname(getTeamsRegistryPath()), 'disbanded');
|
|
158
|
+
}
|
|
159
|
+
function disbandedPath(name) {
|
|
160
|
+
// Encode the name so a team called `../x` cannot escape the dir.
|
|
161
|
+
const safe = Buffer.from(name, 'utf8').toString('base64url');
|
|
162
|
+
return path.join(disbandedDir(), `${safe}.json`);
|
|
163
|
+
}
|
|
164
|
+
/** Mark a team as disbanded so saveMeta will not resurrect its teammates. */
|
|
165
|
+
export async function markTeamDisbanded(name) {
|
|
166
|
+
const dir = disbandedDir();
|
|
167
|
+
await fs.mkdir(dir, { recursive: true });
|
|
168
|
+
await fs.writeFile(disbandedPath(name), JSON.stringify({ team: name, disbanded_at: new Date().toISOString() }), 'utf-8');
|
|
169
|
+
}
|
|
170
|
+
/** Clear a disband tombstone — called when the name is re-created. */
|
|
171
|
+
export async function clearTeamDisbanded(name) {
|
|
172
|
+
try {
|
|
173
|
+
await fs.unlink(disbandedPath(name));
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
if (err?.code !== 'ENOENT')
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/** True when the team was disbanded and has not been re-created since. */
|
|
181
|
+
export async function isTeamDisbanded(name) {
|
|
182
|
+
try {
|
|
183
|
+
await fs.access(disbandedPath(name));
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
144
190
|
/** Remove a team from the registry. Returns false if the team did not exist. */
|
|
145
191
|
export async function removeTeam(name) {
|
|
146
192
|
const p = await registryPath();
|
|
@@ -152,6 +198,10 @@ export async function removeTeam(name) {
|
|
|
152
198
|
await saveTeams(reg);
|
|
153
199
|
return true;
|
|
154
200
|
});
|
|
201
|
+
// Always stamp the tombstone when removeTeam is invoked from disband — even
|
|
202
|
+
// if the registry entry was already gone, so a concurrent supervisor still
|
|
203
|
+
// sees the disband. Idempotent.
|
|
204
|
+
await markTeamDisbanded(name);
|
|
155
205
|
// "Disband" — only fires when a real team was removed, not a no-op.
|
|
156
206
|
if (existed)
|
|
157
207
|
emit('teams.disband', { module: 'teams', team: name });
|
|
@@ -34,6 +34,25 @@ export declare function remoteDefaultBranch(target: string, repoPath: string, op
|
|
|
34
34
|
* teammate off old code.
|
|
35
35
|
*/
|
|
36
36
|
export declare function createRemoteWorktree(target: string, repoPath: string, worktreeName: string, opts?: RemoteSshOptions): string;
|
|
37
|
+
/**
|
|
38
|
+
* How many commits the host checkout at `repoPath` is behind `origin/<default>` —
|
|
39
|
+
* the remote analog of the local {@link commitsBehindDefault} staleness probe, and
|
|
40
|
+
* the exact case from the incident this guard exists for (a distributed team
|
|
41
|
+
* pointed at a 71-commit-stale checkout on another box).
|
|
42
|
+
*
|
|
43
|
+
* `ensureRemoteRepo` already fetched `origin` when it provisioned/reused the
|
|
44
|
+
* checkout right before this runs, so the remote-tracking ref is usually fresh and
|
|
45
|
+
* this reads it WITHOUT a second fetch: resolve the default branch, then
|
|
46
|
+
* `rev-list --count HEAD..origin/<default>`. (That reuse fetch is best-effort —
|
|
47
|
+
* an offline host leaves the ref stale, so this under-reports rather than blocks;
|
|
48
|
+
* `createRemoteWorktree` re-fetches at launch so the teammate's base is still
|
|
49
|
+
* fresh regardless.) Returns null on any git/ssh error (unreachable host, non-repo
|
|
50
|
+
* path) — the caller treats null as "can't tell, don't block".
|
|
51
|
+
*/
|
|
52
|
+
export declare function remoteCommitsBehindDefault(target: string, repoPath: string, opts?: RemoteSshOptions): {
|
|
53
|
+
behind: number;
|
|
54
|
+
base: string;
|
|
55
|
+
} | null;
|
|
37
56
|
/**
|
|
38
57
|
* Ensure the team's repo is present on the host and return its absolute git
|
|
39
58
|
* root. The canonical location is `~/.agents/repos/<slug>` (slug = sanitized
|