@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
|
@@ -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
|
|
@@ -102,6 +102,35 @@ export function createRemoteWorktree(target, repoPath, worktreeName, opts = {})
|
|
|
102
102
|
remoteGit(target, gitRoot, ['worktree', 'add', '-b', branchName, worktreePath, `origin/${base}`], 120000, opts);
|
|
103
103
|
return worktreePath;
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* How many commits the host checkout at `repoPath` is behind `origin/<default>` —
|
|
107
|
+
* the remote analog of the local {@link commitsBehindDefault} staleness probe, and
|
|
108
|
+
* the exact case from the incident this guard exists for (a distributed team
|
|
109
|
+
* pointed at a 71-commit-stale checkout on another box).
|
|
110
|
+
*
|
|
111
|
+
* `ensureRemoteRepo` already fetched `origin` when it provisioned/reused the
|
|
112
|
+
* checkout right before this runs, so the remote-tracking ref is usually fresh and
|
|
113
|
+
* this reads it WITHOUT a second fetch: resolve the default branch, then
|
|
114
|
+
* `rev-list --count HEAD..origin/<default>`. (That reuse fetch is best-effort —
|
|
115
|
+
* an offline host leaves the ref stale, so this under-reports rather than blocks;
|
|
116
|
+
* `createRemoteWorktree` re-fetches at launch so the teammate's base is still
|
|
117
|
+
* fresh regardless.) Returns null on any git/ssh error (unreachable host, non-repo
|
|
118
|
+
* path) — the caller treats null as "can't tell, don't block".
|
|
119
|
+
*/
|
|
120
|
+
export function remoteCommitsBehindDefault(target, repoPath, opts = {}) {
|
|
121
|
+
assertValidSshTarget(target);
|
|
122
|
+
try {
|
|
123
|
+
const base = remoteDefaultBranch(target, repoPath, opts);
|
|
124
|
+
const raw = remoteGit(target, repoPath, ['rev-list', '--count', `HEAD..origin/${base}`], 30000, opts);
|
|
125
|
+
const behind = parseInt(raw, 10);
|
|
126
|
+
if (!Number.isFinite(behind))
|
|
127
|
+
return null;
|
|
128
|
+
return { behind, base };
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
105
134
|
// Team-name → repos-dir slug: same allowlist a worktree name uses, so it lands
|
|
106
135
|
// safely in a path (`~/.agents/repos/<slug>`) with no shell metacharacters.
|
|
107
136
|
const SLUG_RE = /[^A-Za-z0-9_-]/g;
|
|
@@ -30,7 +30,7 @@ export interface PlacementTeam {
|
|
|
30
30
|
* device name to its `agents.max-concurrent` cap (from the device doc — read
|
|
31
31
|
* locally via `readMaxConcurrentCaps`, never probed over SSH). Teams counts
|
|
32
32
|
* the team's OWN roster against the cap (device-global counting would need an
|
|
33
|
-
* SSH probe per candidate — out of the hot path;
|
|
33
|
+
* SSH probe per candidate — out of the hot path; AGI EXT auto-launch is the
|
|
34
34
|
* device-wide counter). Only the least-loaded AUTO-PICK (cascade step 3)
|
|
35
35
|
* honors caps: an explicit pin or a pool of one is the user's own choice and
|
|
36
36
|
* is never second-guessed.
|
|
@@ -132,7 +132,7 @@ export function pickLeastLoaded(devices, roster, maxConcurrent) {
|
|
|
132
132
|
.map((d) => `${d} (${load.get(d) ?? 0}/${maxConcurrent[d]})`)
|
|
133
133
|
.join(', ');
|
|
134
134
|
throw new Error(`Every device in the pool is at its agents.max-concurrent cap: ${detail}. ` +
|
|
135
|
-
`Raise a cap with 'agents devices
|
|
135
|
+
`Raise a cap with 'agents devices config <name> agents.max-concurrent N' or add a device to the pool.`);
|
|
136
136
|
}
|
|
137
137
|
// Iterate the pool in declared order so the first device wins ties.
|
|
138
138
|
let best = eligible[0];
|
|
@@ -27,6 +27,30 @@ export declare function gitDiff(worktreePath: string, maxBytes?: number): Promis
|
|
|
27
27
|
* Falls back to `main` when origin/HEAD isn't set.
|
|
28
28
|
*/
|
|
29
29
|
export declare function localDefaultBranch(gitRoot: string): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* How many commits the checkout at `repoDir` is behind freshly-fetched
|
|
32
|
+
* `origin/<default>` — the staleness the `teams add` guard checks before pointing
|
|
33
|
+
* a team at a repo.
|
|
34
|
+
*
|
|
35
|
+
* Fetches `origin` FIRST, on purpose: the exact failure this guards (a team
|
|
36
|
+
* pointed at a repo "without fetching first" — a 71-commit-stale s1 checkout in
|
|
37
|
+
* the real incident) leaves the remote-tracking ref itself stale, so a naive
|
|
38
|
+
* `HEAD..origin/<default>` reads 0 and hides the drift. After the fetch the count
|
|
39
|
+
* is against the true remote.
|
|
40
|
+
*
|
|
41
|
+
* Measures the passed checkout's OWN root ({@link getGitRoot} / `--show-toplevel`,
|
|
42
|
+
* worktree-correct) — NOT {@link getMainRepoRoot}: for a `--use-worktree` shared
|
|
43
|
+
* worktree (or a caller standing inside a linked worktree), the teammate runs in
|
|
44
|
+
* THAT worktree, whose HEAD differs from the main checkout's, so folding to the
|
|
45
|
+
* main root would report the wrong tree's staleness. `origin/<default>` resolves
|
|
46
|
+
* from the shared object store regardless of which worktree we stand in. Returns
|
|
47
|
+
* null when `repoDir` isn't a git repo, origin is unreachable, or git errors — the
|
|
48
|
+
* caller treats null as "can't tell, don't block".
|
|
49
|
+
*/
|
|
50
|
+
export declare function commitsBehindDefault(repoDir: string): Promise<{
|
|
51
|
+
behind: number;
|
|
52
|
+
base: string;
|
|
53
|
+
} | null>;
|
|
30
54
|
/**
|
|
31
55
|
* Create a new git worktree for a teammate, branched off the freshly-fetched
|
|
32
56
|
* default branch. Fetches `origin` first and bases the branch on
|
|
@@ -100,6 +100,48 @@ export async function localDefaultBranch(gitRoot) {
|
|
|
100
100
|
}
|
|
101
101
|
return 'main';
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* How many commits the checkout at `repoDir` is behind freshly-fetched
|
|
105
|
+
* `origin/<default>` — the staleness the `teams add` guard checks before pointing
|
|
106
|
+
* a team at a repo.
|
|
107
|
+
*
|
|
108
|
+
* Fetches `origin` FIRST, on purpose: the exact failure this guards (a team
|
|
109
|
+
* pointed at a repo "without fetching first" — a 71-commit-stale s1 checkout in
|
|
110
|
+
* the real incident) leaves the remote-tracking ref itself stale, so a naive
|
|
111
|
+
* `HEAD..origin/<default>` reads 0 and hides the drift. After the fetch the count
|
|
112
|
+
* is against the true remote.
|
|
113
|
+
*
|
|
114
|
+
* Measures the passed checkout's OWN root ({@link getGitRoot} / `--show-toplevel`,
|
|
115
|
+
* worktree-correct) — NOT {@link getMainRepoRoot}: for a `--use-worktree` shared
|
|
116
|
+
* worktree (or a caller standing inside a linked worktree), the teammate runs in
|
|
117
|
+
* THAT worktree, whose HEAD differs from the main checkout's, so folding to the
|
|
118
|
+
* main root would report the wrong tree's staleness. `origin/<default>` resolves
|
|
119
|
+
* from the shared object store regardless of which worktree we stand in. Returns
|
|
120
|
+
* null when `repoDir` isn't a git repo, origin is unreachable, or git errors — the
|
|
121
|
+
* caller treats null as "can't tell, don't block".
|
|
122
|
+
*/
|
|
123
|
+
export async function commitsBehindDefault(repoDir) {
|
|
124
|
+
const gitRoot = await getGitRoot(repoDir).catch(() => null);
|
|
125
|
+
if (!gitRoot)
|
|
126
|
+
return null;
|
|
127
|
+
try {
|
|
128
|
+
await execFileAsync('git', ['fetch', 'origin'], { cwd: gitRoot });
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return null; // offline / no origin — can't assess staleness, don't block a team.
|
|
132
|
+
}
|
|
133
|
+
const base = await localDefaultBranch(gitRoot);
|
|
134
|
+
try {
|
|
135
|
+
const { stdout } = await execFileAsync('git', ['rev-list', '--count', `HEAD..origin/${base}`], { cwd: gitRoot });
|
|
136
|
+
const behind = parseInt(stdout.trim(), 10);
|
|
137
|
+
if (!Number.isFinite(behind))
|
|
138
|
+
return null;
|
|
139
|
+
return { behind, base };
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return null; // no origin/<default> tracking ref, detached probe, etc.
|
|
143
|
+
}
|
|
144
|
+
}
|
|
103
145
|
/**
|
|
104
146
|
* Create a new git worktree for a teammate, branched off the freshly-fetched
|
|
105
147
|
* default branch. Fetches `origin` first and bases the branch on
|
|
@@ -23,8 +23,17 @@ export declare const EDITOR_VARIANTS: EditorVariant[];
|
|
|
23
23
|
* it, so a `command`/`cwd` containing `&` (or `=`) would be mis-split by a naive
|
|
24
24
|
* multi-param query. base64url is `[A-Za-z0-9_-]` only (no `&`, `=`, `%`, `+`,
|
|
25
25
|
* `/`), so it survives that decode untouched and round-trips exactly.
|
|
26
|
+
*
|
|
27
|
+
* Optional `meta.agent` / `meta.sessionId` / `meta.title` let the extension set
|
|
28
|
+
* the tab chip and status bar without sniffing the local process tree — required
|
|
29
|
+
* when `command` is a remote attach (`ssh … tmux attach`) with no agent binary
|
|
30
|
+
* on this box (#2478).
|
|
26
31
|
*/
|
|
27
|
-
export declare function spawnUri(scheme: string, cwd: string, command: string[], direction?: SplitDirection
|
|
32
|
+
export declare function spawnUri(scheme: string, cwd: string, command: string[], direction?: SplitDirection, meta?: {
|
|
33
|
+
agent?: string;
|
|
34
|
+
sessionId?: string;
|
|
35
|
+
title?: string;
|
|
36
|
+
}): string;
|
|
28
37
|
/** Build a backend bound to one editor variant. */
|
|
29
38
|
export declare function makeVscodiumAgentBackend(variant: EditorVariant): TerminalBackend;
|
|
30
39
|
/** Default backend: VSCodium (`codium` CLI, `vscodium://` scheme). */
|
|
@@ -41,14 +41,25 @@ function appExists(p) {
|
|
|
41
41
|
* it, so a `command`/`cwd` containing `&` (or `=`) would be mis-split by a naive
|
|
42
42
|
* multi-param query. base64url is `[A-Za-z0-9_-]` only (no `&`, `=`, `%`, `+`,
|
|
43
43
|
* `/`), so it survives that decode untouched and round-trips exactly.
|
|
44
|
+
*
|
|
45
|
+
* Optional `meta.agent` / `meta.sessionId` / `meta.title` let the extension set
|
|
46
|
+
* the tab chip and status bar without sniffing the local process tree — required
|
|
47
|
+
* when `command` is a remote attach (`ssh … tmux attach`) with no agent binary
|
|
48
|
+
* on this box (#2478).
|
|
44
49
|
*/
|
|
45
|
-
export function spawnUri(scheme, cwd, command, direction) {
|
|
50
|
+
export function spawnUri(scheme, cwd, command, direction, meta) {
|
|
46
51
|
const payload = {
|
|
47
52
|
command: command.join(' '),
|
|
48
53
|
cwd,
|
|
49
54
|
};
|
|
50
55
|
if (direction)
|
|
51
56
|
payload.split = direction;
|
|
57
|
+
if (meta?.agent)
|
|
58
|
+
payload.agent = meta.agent;
|
|
59
|
+
if (meta?.sessionId)
|
|
60
|
+
payload.sessionId = meta.sessionId;
|
|
61
|
+
if (meta?.title)
|
|
62
|
+
payload.title = meta.title;
|
|
52
63
|
const p = Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url');
|
|
53
64
|
return `${scheme}://${EXTENSION_AUTHORITY}/spawn?p=${p}`;
|
|
54
65
|
}
|
|
@@ -60,11 +71,11 @@ export function makeVscodiumAgentBackend(variant) {
|
|
|
60
71
|
isAvailable(ctx) {
|
|
61
72
|
return ctx.platform === 'darwin' && appExists(variant.app);
|
|
62
73
|
},
|
|
63
|
-
buildTab(cwd, command) {
|
|
64
|
-
return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command)] };
|
|
74
|
+
buildTab(cwd, command, meta) {
|
|
75
|
+
return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command, undefined, meta)] };
|
|
65
76
|
},
|
|
66
|
-
buildSplit(cwd, command, direction) {
|
|
67
|
-
return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command, direction)] };
|
|
77
|
+
buildSplit(cwd, command, direction, meta) {
|
|
78
|
+
return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command, direction, meta)] };
|
|
68
79
|
},
|
|
69
80
|
};
|
|
70
81
|
}
|
|
@@ -21,6 +21,10 @@ export declare function openSurface(req: LaunchRequest, opts?: OpenOptions): Pro
|
|
|
21
21
|
export interface SurfaceItem {
|
|
22
22
|
cwd: string;
|
|
23
23
|
command: string[];
|
|
24
|
+
/** Optional harness identity for editor-backed backends (vscodium-agent). */
|
|
25
|
+
agent?: string;
|
|
26
|
+
sessionId?: string;
|
|
27
|
+
title?: string;
|
|
24
28
|
}
|
|
25
29
|
export interface BuildRequestsOptions {
|
|
26
30
|
backend: Backend;
|
|
@@ -8,9 +8,12 @@ export function specForRequest(req) {
|
|
|
8
8
|
const backend = BACKENDS[req.backend];
|
|
9
9
|
if (!backend)
|
|
10
10
|
throw new Error(`unknown backend: ${req.backend}`);
|
|
11
|
+
const meta = req.agent || req.sessionId || req.title
|
|
12
|
+
? { agent: req.agent, sessionId: req.sessionId, title: req.title }
|
|
13
|
+
: undefined;
|
|
11
14
|
if (req.layout === 'tab')
|
|
12
|
-
return backend.buildTab(req.cwd, req.command);
|
|
13
|
-
return backend.buildSplit(req.cwd, req.command, req.layout === 'split-down' ? 'down' : 'right');
|
|
15
|
+
return backend.buildTab(req.cwd, req.command, meta);
|
|
16
|
+
return backend.buildSplit(req.cwd, req.command, req.layout === 'split-down' ? 'down' : 'right', meta);
|
|
14
17
|
}
|
|
15
18
|
/** Open a single surface for one request. Never throws — failures come back in the result. */
|
|
16
19
|
export async function openSurface(req, opts = {}) {
|
|
@@ -35,6 +38,9 @@ export function buildRequests(items, opts) {
|
|
|
35
38
|
cwd: item.cwd,
|
|
36
39
|
command: item.command,
|
|
37
40
|
host: opts.host,
|
|
41
|
+
agent: item.agent,
|
|
42
|
+
sessionId: item.sessionId,
|
|
43
|
+
title: item.title,
|
|
38
44
|
}));
|
|
39
45
|
}
|
|
40
46
|
/**
|
|
@@ -25,6 +25,21 @@ export interface LaunchSpec {
|
|
|
25
25
|
/** argv to run (e.g. `['osascript','-e',script]` or `['tmux','split-window',…]`). */
|
|
26
26
|
argv: string[];
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Optional identity the caller already knows about the surface. The
|
|
30
|
+
* vscodium-agent backend forwards these into the swarm-ext `/spawn` URI so the
|
|
31
|
+
* extension can set the tab chip/name/session without sniffing the local
|
|
32
|
+
* process tree (required for remote `ssh … tmux attach` resumes — #2478).
|
|
33
|
+
* Other backends ignore them.
|
|
34
|
+
*/
|
|
35
|
+
export interface SurfaceMeta {
|
|
36
|
+
/** Harness id: claude, codex, grok, … */
|
|
37
|
+
agent?: string;
|
|
38
|
+
/** Canonical session id. */
|
|
39
|
+
sessionId?: string;
|
|
40
|
+
/** Optional pre-baked tab title. */
|
|
41
|
+
title?: string;
|
|
42
|
+
}
|
|
28
43
|
/** A single "open this command as this surface" instruction. */
|
|
29
44
|
export interface LaunchRequest {
|
|
30
45
|
backend: Backend;
|
|
@@ -35,6 +50,10 @@ export interface LaunchRequest {
|
|
|
35
50
|
command: string[];
|
|
36
51
|
/** undefined / 'local' = this machine; otherwise a resolvable host alias. */
|
|
37
52
|
host?: string;
|
|
53
|
+
/** Optional agent identity for editor-backed backends. */
|
|
54
|
+
agent?: string;
|
|
55
|
+
sessionId?: string;
|
|
56
|
+
title?: string;
|
|
38
57
|
}
|
|
39
58
|
/** Outcome of opening one surface. Never throws for launch failures — reports them. */
|
|
40
59
|
export interface LaunchResult {
|
|
@@ -53,7 +72,7 @@ export interface TerminalBackend {
|
|
|
53
72
|
/** Can this backend be driven here? (platform + app installed / inside tmux). */
|
|
54
73
|
isAvailable(ctx: EngineContext): boolean;
|
|
55
74
|
/** Command that opens a new tab running `command` in `cwd`. */
|
|
56
|
-
buildTab(cwd: string, command: string[]): LaunchSpec;
|
|
75
|
+
buildTab(cwd: string, command: string[], meta?: SurfaceMeta): LaunchSpec;
|
|
57
76
|
/** Command that splits the current surface, running `command` in `cwd`. */
|
|
58
|
-
buildSplit(cwd: string, command: string[], direction: SplitDirection): LaunchSpec;
|
|
77
|
+
buildSplit(cwd: string, command: string[], direction: SplitDirection, meta?: SurfaceMeta): LaunchSpec;
|
|
59
78
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { setRefreshLockRootForTest, withRefreshLease } from '../refresh-coordinator.js';
|
|
3
|
+
const [lockRoot, resultPath, countPath, key] = process.argv.slice(2);
|
|
4
|
+
setRefreshLockRootForTest(lockRoot);
|
|
5
|
+
await withRefreshLease({
|
|
6
|
+
scope: 'cross-process-test',
|
|
7
|
+
key,
|
|
8
|
+
readCompleted: () => {
|
|
9
|
+
try {
|
|
10
|
+
return Number(fs.readFileSync(resultPath, 'utf-8'));
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
isCompleted: (value) => value === 1,
|
|
17
|
+
refresh: async () => {
|
|
18
|
+
fs.appendFileSync(countPath, 'refresh\n');
|
|
19
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
20
|
+
fs.writeFileSync(resultPath, '1');
|
|
21
|
+
return 1;
|
|
22
|
+
},
|
|
23
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type TicketSource = 'linear' | 'github';
|
|
2
|
+
export interface TicketComment {
|
|
3
|
+
body: string;
|
|
4
|
+
createdAt?: string;
|
|
5
|
+
author?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TicketRow {
|
|
8
|
+
id: string;
|
|
9
|
+
source: TicketSource;
|
|
10
|
+
title: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
status: 'todo' | 'in_progress' | 'done';
|
|
13
|
+
priority?: 'urgent' | 'high' | 'medium' | 'low';
|
|
14
|
+
metadata: {
|
|
15
|
+
identifier?: string;
|
|
16
|
+
url?: string;
|
|
17
|
+
labels?: string[];
|
|
18
|
+
assignee?: string;
|
|
19
|
+
assigneeKind?: 'user' | 'agent';
|
|
20
|
+
state?: string;
|
|
21
|
+
createdAt?: string;
|
|
22
|
+
dueDate?: string;
|
|
23
|
+
project?: string;
|
|
24
|
+
repo?: string;
|
|
25
|
+
comments?: TicketComment[];
|
|
26
|
+
images?: string[];
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface TicketListResult {
|
|
30
|
+
tickets: TicketRow[];
|
|
31
|
+
cycleInfo: {
|
|
32
|
+
name: string;
|
|
33
|
+
startsAt: string;
|
|
34
|
+
endsAt: string;
|
|
35
|
+
} | null;
|
|
36
|
+
sources: {
|
|
37
|
+
linear: {
|
|
38
|
+
available: boolean;
|
|
39
|
+
error?: string;
|
|
40
|
+
};
|
|
41
|
+
github: {
|
|
42
|
+
available: boolean;
|
|
43
|
+
error?: string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export interface TicketListOptions {
|
|
48
|
+
cwd: string;
|
|
49
|
+
linear: boolean;
|
|
50
|
+
github: boolean;
|
|
51
|
+
githubAssignedOnly: boolean;
|
|
52
|
+
}
|
|
53
|
+
export declare function listTickets(options: TicketListOptions): Promise<TicketListResult>;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
const run = promisify(execFile);
|
|
4
|
+
const AGENT_ASSIGNEE = /^(claude|codex|gemini|cursor|opencode|antigravity|grok|kimi|droid)$/i;
|
|
5
|
+
function assigneeKind(name) {
|
|
6
|
+
if (!name)
|
|
7
|
+
return undefined;
|
|
8
|
+
return AGENT_ASSIGNEE.test(name.trim()) ? 'agent' : 'user';
|
|
9
|
+
}
|
|
10
|
+
function imageUrls(...bodies) {
|
|
11
|
+
const urls = new Set();
|
|
12
|
+
const pattern = /!\[[^\]]*\]\(\s*(https?:\/\/[^)\s]+)|<img\b[^>]*?\bsrc\s*=\s*["'](https?:\/\/[^"']+)/gi;
|
|
13
|
+
for (const body of bodies) {
|
|
14
|
+
if (typeof body !== 'string')
|
|
15
|
+
continue;
|
|
16
|
+
let match;
|
|
17
|
+
while ((match = pattern.exec(body)))
|
|
18
|
+
urls.add(match[1] || match[2]);
|
|
19
|
+
}
|
|
20
|
+
return urls.size > 0 ? [...urls] : undefined;
|
|
21
|
+
}
|
|
22
|
+
function errorMessage(error) {
|
|
23
|
+
if (error instanceof Error)
|
|
24
|
+
return error.message;
|
|
25
|
+
return String(error);
|
|
26
|
+
}
|
|
27
|
+
async function readLinear(cwd) {
|
|
28
|
+
const { stdout } = await run('linear', ['tasks', '--json'], {
|
|
29
|
+
cwd,
|
|
30
|
+
timeout: 15_000,
|
|
31
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
32
|
+
});
|
|
33
|
+
const data = JSON.parse(stdout);
|
|
34
|
+
const cycle = data?.cycle;
|
|
35
|
+
const cycleInfo = cycle?.startsAt && cycle?.endsAt
|
|
36
|
+
? { name: String(cycle.name ?? ''), startsAt: String(cycle.startsAt), endsAt: String(cycle.endsAt) }
|
|
37
|
+
: null;
|
|
38
|
+
const priority = {
|
|
39
|
+
1: 'urgent',
|
|
40
|
+
2: 'high',
|
|
41
|
+
3: 'medium',
|
|
42
|
+
4: 'low',
|
|
43
|
+
};
|
|
44
|
+
const tickets = (Array.isArray(data?.issues) ? data.issues : []).map((issue) => {
|
|
45
|
+
const labels = (issue.labels?.nodes ?? []).map((label) => String(label.name));
|
|
46
|
+
const comments = (issue.comments?.nodes ?? []).map((comment) => ({
|
|
47
|
+
body: String(comment.body ?? ''),
|
|
48
|
+
createdAt: comment.createdAt ? String(comment.createdAt) : undefined,
|
|
49
|
+
author: comment.user?.name ? String(comment.user.name) : undefined,
|
|
50
|
+
}));
|
|
51
|
+
const stateType = String(issue.state?.type ?? '');
|
|
52
|
+
const status = stateType === 'started'
|
|
53
|
+
? 'in_progress'
|
|
54
|
+
: stateType === 'completed' || stateType === 'canceled'
|
|
55
|
+
? 'done'
|
|
56
|
+
: 'todo';
|
|
57
|
+
const identifier = String(issue.identifier ?? issue.id ?? '');
|
|
58
|
+
return {
|
|
59
|
+
id: `linear:${identifier}`,
|
|
60
|
+
source: 'linear',
|
|
61
|
+
title: String(issue.title ?? ''),
|
|
62
|
+
description: issue.description ? String(issue.description) : undefined,
|
|
63
|
+
status,
|
|
64
|
+
priority: priority[Number(issue.priority)],
|
|
65
|
+
metadata: {
|
|
66
|
+
identifier,
|
|
67
|
+
url: issue.url ? String(issue.url) : undefined,
|
|
68
|
+
labels,
|
|
69
|
+
assignee: issue.assignee?.name ? String(issue.assignee.name) : undefined,
|
|
70
|
+
assigneeKind: assigneeKind(issue.assignee?.name),
|
|
71
|
+
state: issue.state?.name ? String(issue.state.name) : undefined,
|
|
72
|
+
createdAt: issue.createdAt ? String(issue.createdAt) : undefined,
|
|
73
|
+
dueDate: issue.dueDate ? String(issue.dueDate) : undefined,
|
|
74
|
+
project: issue.project?.name ? String(issue.project.name) : undefined,
|
|
75
|
+
comments,
|
|
76
|
+
images: imageUrls(issue.description, ...comments.map(comment => comment.body)),
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
return { tickets, cycleInfo };
|
|
81
|
+
}
|
|
82
|
+
async function readGithub(cwd, assignedOnly) {
|
|
83
|
+
const repo = (await run('gh', ['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner'], {
|
|
84
|
+
cwd,
|
|
85
|
+
timeout: 5_000,
|
|
86
|
+
})).stdout.trim();
|
|
87
|
+
if (!repo)
|
|
88
|
+
throw new Error('No GitHub repository resolved for this workspace.');
|
|
89
|
+
const args = [
|
|
90
|
+
'issue', 'list', '--repo', repo, '--state', 'open', '--limit', '50',
|
|
91
|
+
'--json', 'number,title,state,labels,assignees,url,body,createdAt',
|
|
92
|
+
];
|
|
93
|
+
if (assignedOnly)
|
|
94
|
+
args.push('--assignee', '@me');
|
|
95
|
+
const { stdout } = await run('gh', args, { cwd, timeout: 15_000, maxBuffer: 16 * 1024 * 1024 });
|
|
96
|
+
const issues = JSON.parse(stdout);
|
|
97
|
+
return issues.map((issue) => {
|
|
98
|
+
const assignee = issue.assignees?.[0]?.login ? String(issue.assignees[0].login) : undefined;
|
|
99
|
+
const number = Number(issue.number);
|
|
100
|
+
return {
|
|
101
|
+
id: `github:${number}`,
|
|
102
|
+
source: 'github',
|
|
103
|
+
title: String(issue.title ?? ''),
|
|
104
|
+
description: issue.body ? String(issue.body) : undefined,
|
|
105
|
+
status: String(issue.state ?? '').toLowerCase() === 'closed' ? 'done' : 'todo',
|
|
106
|
+
metadata: {
|
|
107
|
+
identifier: `#${number}`,
|
|
108
|
+
url: issue.url ? String(issue.url) : undefined,
|
|
109
|
+
labels: (issue.labels ?? []).map((label) => String(label.name)),
|
|
110
|
+
assignee,
|
|
111
|
+
assigneeKind: assigneeKind(assignee),
|
|
112
|
+
state: String(issue.state ?? '').toLowerCase(),
|
|
113
|
+
createdAt: issue.createdAt ? String(issue.createdAt) : undefined,
|
|
114
|
+
repo,
|
|
115
|
+
images: imageUrls(issue.body),
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
export async function listTickets(options) {
|
|
121
|
+
const result = {
|
|
122
|
+
tickets: [],
|
|
123
|
+
cycleInfo: null,
|
|
124
|
+
sources: {
|
|
125
|
+
linear: { available: false },
|
|
126
|
+
github: { available: false },
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
const [linear, github] = await Promise.all([
|
|
130
|
+
options.linear
|
|
131
|
+
? readLinear(options.cwd).then(value => ({ ok: true, value })).catch(error => ({ ok: false, error }))
|
|
132
|
+
: Promise.resolve(null),
|
|
133
|
+
options.github
|
|
134
|
+
? readGithub(options.cwd, options.githubAssignedOnly).then(value => ({ ok: true, value })).catch(error => ({ ok: false, error }))
|
|
135
|
+
: Promise.resolve(null),
|
|
136
|
+
]);
|
|
137
|
+
if (linear?.ok) {
|
|
138
|
+
result.sources.linear.available = true;
|
|
139
|
+
result.tickets.push(...linear.value.tickets);
|
|
140
|
+
result.cycleInfo = linear.value.cycleInfo;
|
|
141
|
+
}
|
|
142
|
+
else if (linear) {
|
|
143
|
+
result.sources.linear.error = errorMessage(linear.error);
|
|
144
|
+
}
|
|
145
|
+
if (github?.ok) {
|
|
146
|
+
result.sources.github.available = true;
|
|
147
|
+
result.tickets.push(...github.value);
|
|
148
|
+
}
|
|
149
|
+
else if (github) {
|
|
150
|
+
result.sources.github.error = errorMessage(github.error);
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
}
|