@phnx-labs/agents-cli 1.22.34 → 1.22.37
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 +672 -2
- package/README.md +82 -35
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.d.ts +15 -0
- package/dist/bootstrap.js +1211 -0
- package/dist/commands/accounts.d.ts +4 -11
- package/dist/commands/accounts.js +159 -27
- 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 +15 -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 +85 -41
- 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 +4 -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/set.d.ts +1 -1
- package/dist/commands/set.js +2 -2
- 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-share.js +34 -4
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.js +26 -0
- package/dist/commands/share.d.ts +85 -0
- package/dist/commands/share.js +379 -8
- 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/ipc.d.ts +30 -0
- package/dist/lib/browser/ipc.js +81 -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 +4 -0
- package/dist/lib/browser/service.js +30 -3
- 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 +19 -0
- 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/codex-policy.d.ts +9 -1
- package/dist/lib/codex-policy.js +17 -2
- 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 +220 -122
- 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 +20 -6
- package/dist/lib/git.js +121 -17
- 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-key.d.ts +17 -0
- package/dist/lib/project-key.js +26 -0
- 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 +41 -6
- 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/config.d.ts +4 -0
- package/dist/lib/share/config.js +1 -0
- package/dist/lib/share/delete.d.ts +93 -0
- package/dist/lib/share/delete.js +127 -0
- package/dist/lib/share/provision.d.ts +38 -0
- package/dist/lib/share/provision.js +50 -0
- package/dist/lib/share/publish.d.ts +40 -1
- package/dist/lib/share/publish.js +116 -3
- package/dist/lib/share/worker-template.js +71 -6
- package/dist/lib/shims.d.ts +17 -3
- package/dist/lib/shims.js +136 -27
- 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 +6 -12
- package/dist/lib/startup/command-registry.js +14 -31
- 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 +320 -0
- package/dist/lib/tmux/orphan-reap.js +644 -0
- package/dist/lib/tmux/session.d.ts +68 -3
- package/dist/lib/tmux/session.js +95 -5
- package/dist/lib/triggers/handlers.d.ts +20 -0
- package/dist/lib/triggers/handlers.js +6 -1
- package/dist/lib/types.d.ts +46 -34
- 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/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/subagents.js
CHANGED
|
@@ -356,81 +356,6 @@ export function transformSubagentForOpenCode(subagentDir) {
|
|
|
356
356
|
}
|
|
357
357
|
return `---\n${yaml.stringify(fm).trim()}\n---\n\n${systemPrompt}\n`;
|
|
358
358
|
}
|
|
359
|
-
/** Managed parent agent file for Kimi (underscore prefix avoids clobbering a user subagent named agents-cli). */
|
|
360
|
-
export const KIMI_SUBAGENTS_PARENT_FILE = '_agents-cli.yaml';
|
|
361
|
-
/**
|
|
362
|
-
* Transform a subagent into Kimi Code agent files.
|
|
363
|
-
*
|
|
364
|
-
* Kimi's schema (agentspec) only accepts `system_prompt_path` (path relative to
|
|
365
|
-
* the agent YAML) — there is no inline `system_prompt` key. We write:
|
|
366
|
-
* ~/.kimi-code/agents/<name>.yaml — agent YAML
|
|
367
|
-
* ~/.kimi-code/agents/<name>.system.md — system prompt body
|
|
368
|
-
* plus a managed parent `_agents-cli.yaml` that lists them under agent.subagents
|
|
369
|
-
* for `kimi --agent-file …/_agents-cli.yaml`.
|
|
370
|
-
* https://moonshotai.github.io/kimi-cli/en/customization/agents.html
|
|
371
|
-
*/
|
|
372
|
-
export function transformSubagentForKimi(subagentDir, fileBaseName) {
|
|
373
|
-
const agentMd = path.join(subagentDir, 'AGENT.md');
|
|
374
|
-
const frontmatter = parseSubagentFrontmatter(agentMd);
|
|
375
|
-
const body = getSubagentBody(agentMd);
|
|
376
|
-
if (!frontmatter) {
|
|
377
|
-
throw new Error(`Invalid AGENT.md in ${subagentDir}`);
|
|
378
|
-
}
|
|
379
|
-
let systemPrompt = body.trim();
|
|
380
|
-
const files = fs.readdirSync(subagentDir)
|
|
381
|
-
.filter(f => f.endsWith('.md') && f !== 'AGENT.md')
|
|
382
|
-
.sort();
|
|
383
|
-
for (const file of files) {
|
|
384
|
-
const content = fs.readFileSync(path.join(subagentDir, file), 'utf-8').trim();
|
|
385
|
-
const sectionName = file.replace('.md', '');
|
|
386
|
-
const title = sectionName.charAt(0).toUpperCase() + sectionName.slice(1).toLowerCase();
|
|
387
|
-
systemPrompt += `\n\n## ${title}\n\n${content}`;
|
|
388
|
-
}
|
|
389
|
-
const systemPromptFileName = `${fileBaseName}.system.md`;
|
|
390
|
-
const doc = {
|
|
391
|
-
version: 1,
|
|
392
|
-
agent: {
|
|
393
|
-
extend: 'default',
|
|
394
|
-
name: frontmatter.name,
|
|
395
|
-
description: frontmatter.description,
|
|
396
|
-
system_prompt_path: `./${systemPromptFileName}`,
|
|
397
|
-
},
|
|
398
|
-
};
|
|
399
|
-
if (frontmatter.model) {
|
|
400
|
-
doc.agent.model = frontmatter.model;
|
|
401
|
-
}
|
|
402
|
-
return {
|
|
403
|
-
yaml: yaml.stringify(doc),
|
|
404
|
-
systemPrompt,
|
|
405
|
-
systemPromptFileName,
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Build the managed parent agent YAML that declares all installed subagents
|
|
410
|
-
* so `kimi --agent-file ~/.kimi-code/agents/_agents-cli.yaml` can launch them.
|
|
411
|
-
*/
|
|
412
|
-
export function buildKimiSubagentsParentYaml(entries) {
|
|
413
|
-
const subagents = {};
|
|
414
|
-
for (const e of entries) {
|
|
415
|
-
subagents[e.name] = { path: e.relativePath, description: e.description };
|
|
416
|
-
}
|
|
417
|
-
return yaml.stringify({
|
|
418
|
-
version: 1,
|
|
419
|
-
agent: {
|
|
420
|
-
extend: 'default',
|
|
421
|
-
name: 'agents-cli',
|
|
422
|
-
description: 'Managed parent agent listing agents-cli synced subagents',
|
|
423
|
-
subagents,
|
|
424
|
-
},
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
/** Write a Kimi subagent YAML + sibling system-prompt md into agentsDir. */
|
|
428
|
-
export function writeKimiSubagentFiles(agentsDir, subagentDir, name) {
|
|
429
|
-
const { yaml: yml, systemPrompt, systemPromptFileName } = transformSubagentForKimi(subagentDir, name);
|
|
430
|
-
fs.mkdirSync(agentsDir, { recursive: true });
|
|
431
|
-
fs.writeFileSync(safeJoin(agentsDir, `${name}.yaml`), yml);
|
|
432
|
-
fs.writeFileSync(safeJoin(agentsDir, systemPromptFileName), systemPrompt);
|
|
433
|
-
}
|
|
434
359
|
/**
|
|
435
360
|
* Transform a subagent into a Codex custom-agent TOML file.
|
|
436
361
|
*
|
|
@@ -120,7 +120,7 @@ export async function runUmbrellaSync(args) {
|
|
|
120
120
|
const { reconcilePendingSentinels } = await import('./devices/pending.js');
|
|
121
121
|
const dev = await runDeviceSync({ soft: true, mode: 'refresh' });
|
|
122
122
|
if (dev.ok)
|
|
123
|
-
reconcilePendingSentinels(dev.pending);
|
|
123
|
+
await reconcilePendingSentinels(dev.pending);
|
|
124
124
|
result.devices = { synced: dev.synced, pending: dev.pending.length, skipped: !dev.ok };
|
|
125
125
|
if (dev.ok) {
|
|
126
126
|
log(`devices: ${dev.synced} refreshed${dev.pending.length ? `, ${dev.pending.length} new pending` : ''}`);
|
|
@@ -193,6 +193,7 @@ export declare class AgentProcess {
|
|
|
193
193
|
cloudBranch: string | null;
|
|
194
194
|
worktreeName: string | null;
|
|
195
195
|
worktreePath: string | null;
|
|
196
|
+
project: string | null;
|
|
196
197
|
hostName: string | null;
|
|
197
198
|
hostTarget: string | null;
|
|
198
199
|
hostIdentityFile: string | null;
|
|
@@ -304,6 +305,26 @@ export declare class AgentProcess {
|
|
|
304
305
|
*/
|
|
305
306
|
private capEventsCache;
|
|
306
307
|
saveMeta(): Promise<void>;
|
|
308
|
+
/**
|
|
309
|
+
* Rename an unreadable meta.json out of the way so it stops silently
|
|
310
|
+
* masquerading as "no record" (RUSH-2429). Before saveMeta() wrote atomically,
|
|
311
|
+
* a process killed mid-write left a truncated, unparseable meta.json that
|
|
312
|
+
* loadFromDisk() returned null for -- indistinguishable from ENOENT -- so
|
|
313
|
+
* retention (loadExistingAgents/rescanFromDisk) never reaped it and
|
|
314
|
+
* isWorktreeClaimed() (which reads meta.json directly, not through this
|
|
315
|
+
* method) failed CLOSED on it forever: it scans every record and answers
|
|
316
|
+
* "claimed" for every worktree name in every team the first time it cannot
|
|
317
|
+
* read one. Quarantining removes meta.json so the NEXT read of this record
|
|
318
|
+
* sees ENOENT (genuinely absent) instead of "unreadable" -- that is what lets
|
|
319
|
+
* isWorktreeClaimed's fail-closed guard recover once the corrupt record is
|
|
320
|
+
* gone, without weakening the guard itself for a record that is still
|
|
321
|
+
* present-but-unreadable at decision time.
|
|
322
|
+
*
|
|
323
|
+
* Best-effort: if the rename itself fails (e.g. EACCES on the directory),
|
|
324
|
+
* the record is left in place and the fail-closed guard keeps protecting
|
|
325
|
+
* worktree removal -- quarantine only ever ADDS a recovery path.
|
|
326
|
+
*/
|
|
327
|
+
private static quarantineCorruptMeta;
|
|
307
328
|
static loadFromDisk(agentId: string, baseDir?: string | null): Promise<AgentProcess | null>;
|
|
308
329
|
isProcessAlive(): boolean;
|
|
309
330
|
/**
|
|
@@ -478,7 +499,7 @@ export declare class AgentManager {
|
|
|
478
499
|
* asymmetry, not defensive coding: the caller acts destructively on `false`.
|
|
479
500
|
*/
|
|
480
501
|
isWorktreeClaimed(worktreeName: string): Promise<boolean>;
|
|
481
|
-
spawn(taskName: string, agentType: AgentType, prompt: string, cwd?: string | null, mode?: Mode | null, effort?: EffortLevel, 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): Promise<AgentProcess>;
|
|
502
|
+
spawn(taskName: string, agentType: AgentType, prompt: string, cwd?: string | null, mode?: Mode | null, effort?: EffortLevel, 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, project?: string | null): Promise<AgentProcess>;
|
|
482
503
|
/**
|
|
483
504
|
* Resume a STOPPED teammate (completed / failed / stopped) by re-entering its
|
|
484
505
|
* own session with `message` as the next user turn. Re-launches through the
|
|
@@ -613,6 +634,25 @@ export declare class AgentManager {
|
|
|
613
634
|
*/
|
|
614
635
|
listCompleted(): Promise<AgentProcess[]>;
|
|
615
636
|
listByTask(taskName: string): Promise<AgentProcess[]>;
|
|
637
|
+
/**
|
|
638
|
+
* Terminal removal of every teammate record for a team (RUSH-2450).
|
|
639
|
+
*
|
|
640
|
+
* `teams disband` used to delete log dirs and the registry entry, but left
|
|
641
|
+
* the in-memory AgentProcess cache intact. A concurrent `teams start --watch`
|
|
642
|
+
* supervisor then re-persisted those records via saveMeta, so a second
|
|
643
|
+
* disband still found N logs to clear and `teams start` could re-launch
|
|
644
|
+
* PENDING work that had already merged.
|
|
645
|
+
*
|
|
646
|
+
* This drops every matching record from the manager map AND removes its
|
|
647
|
+
* durable state. With `keepLogs`, only `meta.json` is removed so the
|
|
648
|
+
* teammate is no longer discoverable/startable while stdout/stderr logs
|
|
649
|
+
* remain for postmortem.
|
|
650
|
+
*
|
|
651
|
+
* Returns the agent_ids that were purged.
|
|
652
|
+
*/
|
|
653
|
+
purgeByTask(taskName: string, opts?: {
|
|
654
|
+
keepLogs?: boolean;
|
|
655
|
+
}): Promise<string[]>;
|
|
616
656
|
listByParentSession(parentSessionId: string): Promise<AgentProcess[]>;
|
|
617
657
|
stopByTask(taskName: string): Promise<{
|
|
618
658
|
stopped: string[];
|
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
|
+
}
|