@phnx-labs/agents-cli 1.22.35 → 1.22.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +708 -2
- package/README.md +83 -43
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.d.ts +15 -0
- package/dist/bootstrap.js +1212 -0
- package/dist/commands/accounts.d.ts +4 -11
- package/dist/commands/accounts.js +159 -27
- package/dist/commands/artifacts-setup.d.ts +53 -0
- package/dist/commands/artifacts-setup.js +161 -0
- package/dist/commands/artifacts.d.ts +18 -0
- package/dist/commands/artifacts.js +58 -0
- package/dist/commands/attach.js +17 -4
- package/dist/commands/audit.d.ts +8 -8
- package/dist/commands/audit.js +57 -47
- package/dist/commands/browser.js +17 -11
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +0 -11
- package/dist/commands/computer-actions.js +33 -0
- package/dist/commands/computer-sessions-picker.d.ts +21 -0
- package/dist/commands/computer-sessions-picker.js +141 -0
- package/dist/commands/computer.d.ts +16 -0
- package/dist/commands/computer.js +37 -0
- package/dist/commands/config.d.ts +17 -0
- package/dist/commands/config.js +401 -0
- package/dist/commands/cp.d.ts +84 -0
- package/dist/commands/cp.js +231 -0
- package/dist/commands/daemon.js +243 -14
- package/dist/commands/detach-core.d.ts +1 -1
- package/dist/commands/detach-core.js +12 -2
- package/dist/commands/detach.js +1 -1
- package/dist/commands/doctor.js +64 -5
- package/dist/commands/events.d.ts +24 -12
- package/dist/commands/events.js +144 -28
- package/dist/commands/exec.js +86 -42
- package/dist/commands/feed.d.ts +1 -1
- package/dist/commands/feed.js +16 -8
- package/dist/commands/focus.d.ts +33 -1
- package/dist/commands/focus.js +177 -17
- package/dist/commands/funnel.d.ts +1 -1
- package/dist/commands/go.js +9 -8
- package/dist/commands/harness-wizard.d.ts +1 -0
- package/dist/commands/harness-wizard.js +18 -20
- package/dist/commands/harness.d.ts +2 -0
- package/dist/commands/harness.js +59 -26
- package/dist/commands/hooks.js +0 -11
- package/dist/commands/inspect.d.ts +94 -1
- package/dist/commands/inspect.js +866 -40
- package/dist/commands/lease.d.ts +4 -4
- package/dist/commands/lease.js +6 -6
- package/dist/commands/login.js +0 -13
- package/dist/commands/logs.d.ts +2 -2
- package/dist/commands/logs.js +2 -2
- package/dist/commands/mcp.js +7 -2
- package/dist/commands/memory.js +7 -2
- package/dist/commands/message.d.ts +1 -1
- package/dist/commands/message.js +37 -6
- package/dist/commands/models.js +71 -0
- package/dist/commands/monitors.d.ts +0 -1
- package/dist/commands/monitors.js +199 -16
- package/dist/commands/open.d.ts +18 -0
- package/dist/commands/open.js +57 -0
- package/dist/commands/packages.js +2 -107
- package/dist/commands/plugins.js +6 -3
- package/dist/commands/profiles.d.ts +1 -0
- package/dist/commands/profiles.js +16 -160
- package/dist/commands/projects.d.ts +28 -0
- package/dist/commands/projects.js +125 -5
- package/dist/commands/reconnect.js +9 -3
- package/dist/commands/repo.js +42 -1
- package/dist/commands/resource-view.d.ts +17 -0
- package/dist/commands/resource-view.js +36 -14
- package/dist/commands/resume.js +9 -2
- package/dist/commands/routines.d.ts +0 -2
- package/dist/commands/routines.js +473 -289
- package/dist/commands/secrets.js +52 -9
- package/dist/commands/sessions-export.d.ts +47 -0
- package/dist/commands/sessions-export.js +116 -6
- package/dist/commands/sessions-import.d.ts +17 -0
- package/dist/commands/sessions-import.js +114 -6
- package/dist/commands/sessions-migrate.d.ts +27 -0
- package/dist/commands/sessions-migrate.js +50 -9
- package/dist/commands/sessions-picker.js +23 -4
- package/dist/commands/sessions-resume.d.ts +5 -3
- package/dist/commands/sessions-resume.js +30 -8
- package/dist/commands/sessions-watch.d.ts +2 -0
- package/dist/commands/sessions-watch.js +53 -0
- package/dist/commands/sessions.d.ts +66 -3
- package/dist/commands/sessions.js +298 -47
- package/dist/commands/setup-browser.js +2 -2
- package/dist/commands/setup-mine.js +0 -1
- package/dist/commands/setup-preferences.js +1 -1
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.js +31 -5
- package/dist/commands/share.d.ts +87 -7
- package/dist/commands/share.js +320 -58
- package/dist/commands/skills.js +0 -11
- package/dist/commands/snapshot.js +1 -1
- package/dist/commands/ssh.d.ts +18 -0
- package/dist/commands/ssh.js +549 -210
- package/dist/commands/sync.d.ts +5 -0
- package/dist/commands/sync.js +212 -32
- package/dist/commands/teams.d.ts +13 -0
- package/dist/commands/teams.js +187 -30
- package/dist/commands/tickets.d.ts +2 -0
- package/dist/commands/tickets.js +43 -0
- package/dist/commands/update.js +2 -4
- package/dist/commands/usage.js +5 -3
- package/dist/commands/versions.js +11 -5
- package/dist/commands/view.js +15 -7
- package/dist/commands/webhook.d.ts +2 -2
- package/dist/commands/webhook.js +7 -7
- package/dist/index.d.ts +18 -2
- package/dist/index.js +53 -1264
- package/dist/lib/account-catalog.d.ts +18 -0
- package/dist/lib/account-catalog.js +38 -0
- package/dist/lib/account-provider-registry.d.ts +18 -0
- package/dist/lib/account-provider-registry.js +59 -0
- package/dist/lib/account-registry.d.ts +40 -0
- package/dist/lib/account-registry.js +239 -0
- package/dist/lib/account-schema.d.ts +44 -0
- package/dist/lib/account-schema.js +91 -0
- package/dist/lib/account-state-service.d.ts +21 -0
- package/dist/lib/account-state-service.js +60 -0
- package/dist/lib/activity.d.ts +1 -1
- package/dist/lib/activity.js +8 -1
- package/dist/lib/add-dir.d.ts +80 -0
- package/dist/lib/add-dir.js +241 -0
- package/dist/lib/agent-cli-commands.d.ts +11 -0
- package/dist/lib/agent-cli-commands.js +30 -0
- package/dist/lib/agents.js +44 -36
- package/dist/lib/answer-router.js +1 -1
- package/dist/lib/audit/log.d.ts +10 -27
- package/dist/lib/audit/log.js +20 -33
- package/dist/lib/auth-health.d.ts +9 -2
- package/dist/lib/auth-health.js +42 -9
- package/dist/lib/auto-pull-worker.js +7 -3
- package/dist/lib/auto-pull.d.ts +44 -3
- package/dist/lib/auto-pull.js +88 -5
- package/dist/lib/binary-shadow.d.ts +28 -0
- package/dist/lib/binary-shadow.js +121 -0
- package/dist/lib/brand.js +9 -3
- package/dist/lib/browser/hygiene.d.ts +90 -0
- package/dist/lib/browser/hygiene.js +146 -0
- package/dist/lib/browser/ipc.d.ts +30 -0
- package/dist/lib/browser/ipc.js +93 -4
- package/dist/lib/browser/profiles.d.ts +3 -2
- package/dist/lib/browser/profiles.js +65 -22
- package/dist/lib/browser/service.d.ts +79 -1
- package/dist/lib/browser/service.js +231 -14
- package/dist/lib/browser/sessions-list.d.ts +22 -2
- package/dist/lib/browser/sessions-list.js +54 -6
- package/dist/lib/browser/stream.d.ts +2 -0
- package/dist/lib/browser/stream.js +1 -0
- package/dist/lib/browser/types.d.ts +63 -1
- package/dist/lib/byok-usage.d.ts +9 -2
- package/dist/lib/byok-usage.js +133 -31
- package/dist/lib/cli-entry.d.ts +11 -0
- package/dist/lib/cli-entry.js +46 -0
- package/dist/lib/cloud/host.d.ts +1 -1
- package/dist/lib/cloud/host.js +2 -2
- package/dist/lib/cloud/registry.js +1 -1
- package/dist/lib/cloud/types.d.ts +1 -1
- package/dist/lib/commands.d.ts +2 -0
- package/dist/lib/commands.js +2 -0
- package/dist/lib/computer/sessions-list.d.ts +150 -0
- package/dist/lib/computer/sessions-list.js +363 -0
- package/dist/lib/config-keys.d.ts +86 -0
- package/dist/lib/config-keys.js +193 -0
- package/dist/lib/config-machine-keys.d.ts +12 -0
- package/dist/lib/config-machine-keys.js +17 -0
- package/dist/lib/config-transfer.js +3 -4
- package/dist/lib/crabbox/cli.d.ts +2 -2
- package/dist/lib/crabbox/cli.js +3 -3
- package/dist/lib/daemon-health.d.ts +22 -0
- package/dist/lib/daemon-health.js +33 -3
- package/dist/lib/daemon-services.d.ts +50 -0
- package/dist/lib/daemon-services.js +147 -0
- package/dist/lib/daemon-ticks.d.ts +35 -66
- package/dist/lib/daemon-ticks.js +77 -159
- package/dist/lib/daemon.d.ts +72 -4
- package/dist/lib/daemon.js +792 -202
- package/dist/lib/deeplink/register.d.ts +49 -0
- package/dist/lib/deeplink/register.js +253 -0
- package/dist/lib/deeplink/url.d.ts +34 -0
- package/dist/lib/deeplink/url.js +78 -0
- package/dist/lib/device-config.d.ts +124 -29
- package/dist/lib/device-config.js +346 -141
- package/dist/lib/devices/config-migration.d.ts +42 -0
- package/dist/lib/devices/config-migration.js +203 -0
- package/dist/lib/devices/connect.js +14 -7
- package/dist/lib/devices/doctor-findings.d.ts +4 -1
- package/dist/lib/devices/doctor-findings.js +20 -1
- package/dist/lib/devices/harness-inventory.d.ts +11 -2
- package/dist/lib/devices/harness-inventory.js +0 -0
- package/dist/lib/devices/health.d.ts +1 -1
- package/dist/lib/devices/health.js +1 -1
- package/dist/lib/devices/pending.d.ts +22 -1
- package/dist/lib/devices/pending.js +67 -2
- package/dist/lib/devices/registry.d.ts +0 -25
- package/dist/lib/devices/registry.js +2 -83
- package/dist/lib/devices/resolve-profile.d.ts +20 -0
- package/dist/lib/devices/resolve-profile.js +44 -0
- package/dist/lib/devices/rollout-verify.d.ts +101 -0
- package/dist/lib/devices/rollout-verify.js +193 -0
- package/dist/lib/devices/ssh-config.js +10 -6
- package/dist/lib/event-families.d.ts +28 -0
- package/dist/lib/event-families.js +159 -0
- package/dist/lib/event-stream.d.ts +9 -1
- package/dist/lib/event-stream.js +26 -9
- package/dist/lib/events.d.ts +9 -1
- package/dist/lib/events.js +21 -6
- package/dist/lib/exec.d.ts +30 -0
- package/dist/lib/exec.js +219 -121
- package/dist/lib/feed-broadcast.d.ts +25 -0
- package/dist/lib/feed-broadcast.js +33 -0
- package/dist/lib/feed.d.ts +1 -1
- package/dist/lib/feed.js +12 -2
- package/dist/lib/fleet/capture.js +15 -0
- package/dist/lib/fleet/manifest.js +9 -0
- package/dist/lib/fleet/types.d.ts +9 -0
- package/dist/lib/fleet-status.js +10 -8
- package/dist/lib/git.d.ts +21 -7
- package/dist/lib/git.js +122 -18
- package/dist/lib/hosts/dispatch.d.ts +8 -3
- package/dist/lib/hosts/dispatch.js +29 -3
- package/dist/lib/hosts/logs.d.ts +2 -2
- package/dist/lib/hosts/logs.js +2 -2
- package/dist/lib/hosts/option.js +1 -1
- package/dist/lib/hosts/passthrough.d.ts +2 -3
- package/dist/lib/hosts/passthrough.js +10 -24
- package/dist/lib/hosts/progress.js +2 -2
- package/dist/lib/hosts/providers/devices.d.ts +3 -3
- package/dist/lib/hosts/providers/devices.js +18 -12
- package/dist/lib/hosts/ready.d.ts +5 -1
- package/dist/lib/hosts/ready.js +9 -3
- package/dist/lib/hosts/reconcile.d.ts +2 -2
- package/dist/lib/hosts/reconcile.js +2 -2
- package/dist/lib/hosts/registry.js +14 -9
- package/dist/lib/hosts/remote-cmd.js +1 -1
- package/dist/lib/hosts/remote-os.d.ts +9 -6
- package/dist/lib/hosts/remote-os.js +13 -6
- package/dist/lib/hosts/routing-flag.d.ts +23 -0
- package/dist/lib/hosts/routing-flag.js +41 -0
- package/dist/lib/hosts/run-target.js +1 -1
- package/dist/lib/hosts/session-index.js +1 -1
- package/dist/lib/hosts/tasks.d.ts +6 -6
- package/dist/lib/hosts/tasks.js +4 -4
- package/dist/lib/hosts/types.js +1 -2
- package/dist/lib/installations/resolve.js +2 -8
- package/dist/lib/isolation-boundary-report.js +0 -1
- package/dist/lib/linear-cache.d.ts +7 -0
- package/dist/lib/linear-cache.js +31 -4
- package/dist/lib/linear-project-counts.d.ts +1 -1
- package/dist/lib/linear-project-counts.js +2 -3
- package/dist/lib/linear-projects.js +1 -1
- package/dist/lib/loop.d.ts +2 -2
- package/dist/lib/loop.js +1 -1
- package/dist/lib/mailbox-target.d.ts +1 -1
- package/dist/lib/mailbox-target.js +1 -1
- package/dist/lib/manifest.js +7 -4
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/snapshot.d.ts +3 -2
- package/dist/lib/menubar/snapshot.js +6 -2
- package/dist/lib/migrate-fold.d.ts +33 -0
- package/dist/lib/migrate-fold.js +130 -0
- package/dist/lib/migrate.d.ts +34 -34
- package/dist/lib/migrate.js +106 -128
- package/dist/lib/model-tier-overrides.d.ts +1 -1
- package/dist/lib/model-tier-overrides.js +15 -2
- package/dist/lib/monitors/config.d.ts +17 -3
- package/dist/lib/monitors/config.js +52 -18
- package/dist/lib/monitors/engine.d.ts +32 -1
- package/dist/lib/monitors/engine.js +94 -11
- package/dist/lib/monitors/fingerprint.d.ts +46 -0
- package/dist/lib/monitors/fingerprint.js +100 -0
- package/dist/lib/monitors/remote.d.ts +47 -0
- package/dist/lib/monitors/remote.js +81 -0
- package/dist/lib/monitors/state.d.ts +39 -0
- package/dist/lib/monitors/state.js +56 -0
- package/dist/lib/onepassword.d.ts +17 -0
- package/dist/lib/onepassword.js +52 -22
- package/dist/lib/open-url.js +1 -1
- package/dist/lib/picker.d.ts +14 -2
- package/dist/lib/picker.js +35 -13
- package/dist/lib/placement.d.ts +1 -1
- package/dist/lib/placement.js +1 -1
- package/dist/lib/pr-land-detach.d.ts +32 -0
- package/dist/lib/pr-land-detach.js +79 -0
- package/dist/lib/profiles-presets.js +13 -0
- package/dist/lib/profiles.d.ts +2 -0
- package/dist/lib/profiles.js +44 -1
- package/dist/lib/project-focus.d.ts +1 -1
- package/dist/lib/project-focus.js +1 -1
- package/dist/lib/project-probe.d.ts +4 -1
- package/dist/lib/project-probe.js +5 -4
- package/dist/lib/project-resources.js +2 -18
- package/dist/lib/project-root.d.ts +16 -0
- package/dist/lib/project-root.js +20 -2
- package/dist/lib/projects.d.ts +20 -1
- package/dist/lib/projects.js +78 -1
- package/dist/lib/refresh-coordinator.d.ts +24 -0
- package/dist/lib/refresh-coordinator.js +52 -0
- package/dist/lib/registry.d.ts +2 -2
- package/dist/lib/registry.js +1 -1
- package/dist/lib/resource-aliases.d.ts +13 -0
- package/dist/lib/resource-aliases.js +26 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.d.ts +16 -0
- package/dist/lib/resources.js +66 -10
- package/dist/lib/rotate.d.ts +3 -4
- package/dist/lib/rotate.js +4 -5
- package/dist/lib/routine-activation.d.ts +22 -2
- package/dist/lib/routine-activation.js +63 -16
- package/dist/lib/routine-context.d.ts +9 -2
- package/dist/lib/routine-context.js +21 -6
- package/dist/lib/routines-project.d.ts +58 -48
- package/dist/lib/routines-project.js +190 -159
- package/dist/lib/routines.d.ts +44 -7
- package/dist/lib/routines.js +92 -34
- package/dist/lib/run-defaults.d.ts +5 -0
- package/dist/lib/run-defaults.js +11 -1
- package/dist/lib/runner.d.ts +10 -8
- package/dist/lib/runner.js +122 -39
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/agent.d.ts +10 -3
- package/dist/lib/secrets/agent.js +43 -8
- package/dist/lib/secrets/bundles.d.ts +1 -0
- package/dist/lib/secrets/bundles.js +92 -80
- package/dist/lib/secrets/index.js +32 -9
- package/dist/lib/secrets/install-helper.d.ts +4 -4
- package/dist/lib/secrets/install-helper.js +4 -4
- package/dist/lib/secrets/push.d.ts +40 -6
- package/dist/lib/secrets/push.js +58 -11
- package/dist/lib/secrets/read-backoff.d.ts +1 -1
- package/dist/lib/secrets/read-backoff.js +1 -1
- package/dist/lib/secrets/remote.d.ts +24 -0
- package/dist/lib/secrets/remote.js +54 -4
- package/dist/lib/self-update.d.ts +108 -0
- package/dist/lib/self-update.js +276 -1
- package/dist/lib/session/active.d.ts +89 -5
- package/dist/lib/session/active.js +165 -10
- package/dist/lib/session/actor-sidecar.d.ts +1 -1
- package/dist/lib/session/actor-sidecar.js +2 -1
- package/dist/lib/session/db.d.ts +176 -2
- package/dist/lib/session/db.js +484 -17
- package/dist/lib/session/discover.js +27 -4
- package/dist/lib/session/hook-sessions.js +2 -2
- package/dist/lib/session/host-link.d.ts +2 -2
- package/dist/lib/session/host-link.js +2 -2
- package/dist/lib/session/pid-registry.d.ts +21 -0
- package/dist/lib/session/pid-registry.js +57 -0
- package/dist/lib/session/remote-active.js +15 -1
- package/dist/lib/session/remote.js +2 -2
- package/dist/lib/session/session-cache.d.ts +14 -7
- package/dist/lib/session/session-cache.js +51 -9
- package/dist/lib/session/state.d.ts +2 -2
- package/dist/lib/session/state.js +1 -1
- package/dist/lib/session/sync/config.d.ts +10 -10
- package/dist/lib/session/sync/config.js +10 -10
- package/dist/lib/session/sync/r2.d.ts +34 -0
- package/dist/lib/session/sync/r2.js +123 -0
- package/dist/lib/session/throughput.d.ts +1 -1
- package/dist/lib/session/throughput.js +1 -1
- package/dist/lib/session/types.d.ts +23 -1
- package/dist/lib/session/types.js +15 -0
- package/dist/lib/session/viewing-in.d.ts +1 -1
- package/dist/lib/session/viewing-in.js +1 -1
- package/dist/lib/session/watch.d.ts +101 -0
- package/dist/lib/session/watch.js +242 -0
- package/dist/lib/share/analytics.js +1 -1
- package/dist/lib/share/capture.d.ts +1 -1
- package/dist/lib/share/capture.js +3 -3
- package/dist/lib/share/config.d.ts +6 -2
- package/dist/lib/share/config.js +6 -5
- package/dist/lib/share/delete.js +3 -3
- package/dist/lib/share/provision.d.ts +38 -0
- package/dist/lib/share/provision.js +51 -1
- package/dist/lib/share/publish.d.ts +40 -1
- package/dist/lib/share/publish.js +119 -6
- package/dist/lib/share/worker-template.d.ts +12 -1
- package/dist/lib/share/worker-template.js +83 -7
- package/dist/lib/shims.d.ts +17 -3
- package/dist/lib/shims.js +98 -26
- package/dist/lib/signin-badge.js +3 -2
- package/dist/lib/skills.js +2 -0
- package/dist/lib/smart-launch.d.ts +8 -8
- package/dist/lib/smart-launch.js +80 -59
- package/dist/lib/ssh-exec.d.ts +1 -1
- package/dist/lib/ssh-exec.js +1 -1
- package/dist/lib/staleness/prune.d.ts +88 -0
- package/dist/lib/staleness/prune.js +69 -0
- package/dist/lib/staleness/registry.d.ts +1 -1
- package/dist/lib/staleness/writers/commands.js +34 -2
- package/dist/lib/staleness/writers/hooks.js +16 -0
- package/dist/lib/staleness/writers/kinds.d.ts +6 -0
- package/dist/lib/staleness/writers/skills.js +19 -0
- package/dist/lib/staleness/writers/subagents.d.ts +2 -3
- package/dist/lib/staleness/writers/subagents.js +0 -4
- package/dist/lib/staleness/writers/types.d.ts +32 -0
- package/dist/lib/startup/command-registry.d.ts +16 -14
- package/dist/lib/startup/command-registry.js +26 -37
- package/dist/lib/startup/dev-build.d.ts +10 -0
- package/dist/lib/startup/dev-build.js +13 -1
- package/dist/lib/startup/spellcheck.d.ts +18 -0
- package/dist/lib/startup/spellcheck.js +45 -0
- package/dist/lib/state.d.ts +36 -9
- package/dist/lib/state.js +96 -46
- package/dist/lib/subagents-registry.d.ts +0 -7
- package/dist/lib/subagents-registry.js +38 -65
- package/dist/lib/subagents.d.ts +0 -33
- package/dist/lib/subagents.js +0 -75
- package/dist/lib/sync-umbrella.js +1 -1
- package/dist/lib/teams/agents.d.ts +41 -1
- package/dist/lib/teams/agents.js +187 -9
- package/dist/lib/teams/api.d.ts +11 -1
- package/dist/lib/teams/api.js +11 -2
- package/dist/lib/teams/delivery.d.ts +41 -0
- package/dist/lib/teams/delivery.js +60 -0
- package/dist/lib/teams/registry.d.ts +14 -0
- package/dist/lib/teams/registry.js +51 -1
- package/dist/lib/teams/remoteWorktree.d.ts +19 -0
- package/dist/lib/teams/remoteWorktree.js +29 -0
- package/dist/lib/teams/scheduler.d.ts +1 -1
- package/dist/lib/teams/scheduler.js +1 -1
- package/dist/lib/teams/worktree.d.ts +24 -0
- package/dist/lib/teams/worktree.js +42 -0
- package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
- package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
- package/dist/lib/terminal/engine.d.ts +4 -0
- package/dist/lib/terminal/engine.js +8 -2
- package/dist/lib/terminal/types.d.ts +21 -2
- package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
- package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
- package/dist/lib/tickets/list.d.ts +53 -0
- package/dist/lib/tickets/list.js +153 -0
- package/dist/lib/tmux/orphan-reap.d.ts +316 -0
- package/dist/lib/tmux/orphan-reap.js +638 -0
- package/dist/lib/tmux/session.d.ts +68 -3
- package/dist/lib/tmux/session.js +96 -5
- package/dist/lib/triggers/handlers.d.ts +20 -0
- package/dist/lib/triggers/handlers.js +16 -1
- package/dist/lib/triggers/webhook.js +10 -0
- package/dist/lib/types.d.ts +47 -35
- package/dist/lib/usage-fleet.d.ts +32 -0
- package/dist/lib/usage-fleet.js +125 -0
- package/dist/lib/usage-refresh.d.ts +3 -3
- package/dist/lib/usage-refresh.js +19 -16
- package/dist/lib/usage.d.ts +51 -47
- package/dist/lib/usage.js +145 -153
- package/dist/lib/version-duplicates.js +2 -2
- package/dist/lib/versions.d.ts +56 -13
- package/dist/lib/versions.js +195 -45
- package/dist/lib/watchdog/log.d.ts +1 -1
- package/dist/lib/watchdog/log.js +3 -3
- package/dist/lib/watchdog/rotate.d.ts +6 -6
- package/dist/lib/watchdog/rotate.js +6 -6
- package/dist/lib/workflows.d.ts +1 -1
- package/dist/lib/yaml-io.d.ts +47 -0
- package/dist/lib/yaml-io.js +55 -0
- package/package.json +2 -1
- package/scripts/install-helper.js +2 -2
- package/scripts/postinstall.js +23 -20
- package/dist/commands/defaults.d.ts +0 -7
- package/dist/commands/defaults.js +0 -107
- package/dist/commands/export.d.ts +0 -11
- package/dist/commands/export.js +0 -215
- package/dist/commands/helper.d.ts +0 -12
- package/dist/commands/helper.js +0 -87
- package/dist/commands/hosts.d.ts +0 -11
- package/dist/commands/hosts.js +0 -330
- package/dist/commands/lock.d.ts +0 -12
- package/dist/commands/lock.js +0 -70
- package/dist/commands/pull.d.ts +0 -17
- package/dist/commands/pull.js +0 -39
- package/dist/commands/push.d.ts +0 -14
- package/dist/commands/push.js +0 -30
- package/dist/commands/set.d.ts +0 -15
- package/dist/commands/set.js +0 -79
- package/dist/commands/setup-share.d.ts +0 -17
- package/dist/commands/setup-share.js +0 -85
- package/dist/commands/wallet.d.ts +0 -20
- package/dist/commands/wallet.js +0 -216
- package/dist/commands/worktree.d.ts +0 -19
- package/dist/commands/worktree.js +0 -272
- package/dist/lib/account-labels.d.ts +0 -24
- package/dist/lib/account-labels.js +0 -72
- package/dist/lib/auto-dispatch-linear.d.ts +0 -18
- package/dist/lib/auto-dispatch-linear.js +0 -107
- package/dist/lib/auto-dispatch-provider.d.ts +0 -10
- package/dist/lib/auto-dispatch-provider.js +0 -30
- package/dist/lib/auto-dispatch.d.ts +0 -93
- package/dist/lib/auto-dispatch.js +0 -128
- package/dist/lib/export.d.ts +0 -72
- package/dist/lib/export.js +0 -269
- package/dist/lib/lock.d.ts +0 -93
- package/dist/lib/lock.js +0 -207
- package/dist/lib/wallet/index.d.ts +0 -78
- package/dist/lib/wallet/index.js +0 -253
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentId } from './types.js';
|
|
2
|
+
export interface NativeAccountCatalogEntry {
|
|
3
|
+
kind: 'native';
|
|
4
|
+
id: string;
|
|
5
|
+
agent: AgentId;
|
|
6
|
+
display: string;
|
|
7
|
+
email: string | null;
|
|
8
|
+
versions: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function groupNativeAccountRows(rows: Array<{
|
|
11
|
+
agent: AgentId;
|
|
12
|
+
version: string;
|
|
13
|
+
accountKey: string | null;
|
|
14
|
+
email: string | null;
|
|
15
|
+
signedIn: boolean;
|
|
16
|
+
}>): NativeAccountCatalogEntry[];
|
|
17
|
+
/** Discover signed-in harness-native identities without copying their auth files. */
|
|
18
|
+
export declare function discoverNativeAccounts(): Promise<NativeAccountCatalogEntry[]>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ALL_AGENT_IDS, getAccountInfo, supportsAccountInspection } from './agents.js';
|
|
2
|
+
import { getVersionHomePath, listInstalledVersions } from './versions.js';
|
|
3
|
+
export function groupNativeAccountRows(rows) {
|
|
4
|
+
const grouped = new Map();
|
|
5
|
+
for (const row of rows) {
|
|
6
|
+
if (!row.signedIn)
|
|
7
|
+
continue;
|
|
8
|
+
const identity = row.accountKey ?? row.email?.toLowerCase();
|
|
9
|
+
if (!identity)
|
|
10
|
+
continue;
|
|
11
|
+
const key = `${row.agent}:${identity}`;
|
|
12
|
+
const existing = grouped.get(key);
|
|
13
|
+
if (existing)
|
|
14
|
+
existing.versions.push(row.version);
|
|
15
|
+
else
|
|
16
|
+
grouped.set(key, {
|
|
17
|
+
kind: 'native',
|
|
18
|
+
id: identity,
|
|
19
|
+
agent: row.agent,
|
|
20
|
+
display: row.email ?? identity,
|
|
21
|
+
email: row.email,
|
|
22
|
+
versions: [row.version],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return [...grouped.values()].map(entry => ({ ...entry, versions: [...new Set(entry.versions)].sort() }))
|
|
26
|
+
.sort((a, b) => a.agent.localeCompare(b.agent) || a.display.localeCompare(b.display));
|
|
27
|
+
}
|
|
28
|
+
/** Discover signed-in harness-native identities without copying their auth files. */
|
|
29
|
+
export async function discoverNativeAccounts() {
|
|
30
|
+
const rows = [];
|
|
31
|
+
for (const agent of ALL_AGENT_IDS.filter(supportsAccountInspection)) {
|
|
32
|
+
for (const version of listInstalledVersions(agent)) {
|
|
33
|
+
const info = await getAccountInfo(agent, getVersionHomePath(agent, version));
|
|
34
|
+
rows.push({ agent, version, accountKey: info.accountKey, email: info.email, signedIn: info.signedIn });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return groupNativeAccountRows(rows);
|
|
38
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentId } from './types.js';
|
|
2
|
+
export type AccountAuthKind = 'api-key' | 'setup-token' | 'bearer-token';
|
|
3
|
+
export interface AccountProviderAdapter {
|
|
4
|
+
provider: string;
|
|
5
|
+
authKinds: readonly AccountAuthKind[];
|
|
6
|
+
envFor(host: AgentId, kind: AccountAuthKind): string;
|
|
7
|
+
connectionEnvFor(host: AgentId): Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* The env var a per-account BASE_URL override should be written to for this
|
|
10
|
+
* host, or null when the provider has no endpoint env on that host. Derived
|
|
11
|
+
* from the provider's own connection env so the base-url key lives in one
|
|
12
|
+
* place instead of being re-guessed by callers.
|
|
13
|
+
*/
|
|
14
|
+
baseUrlEnvFor(host: AgentId): string | null;
|
|
15
|
+
validate(kind: AccountAuthKind, value: string): void;
|
|
16
|
+
}
|
|
17
|
+
export declare function getAccountProvider(provider: string): AccountProviderAdapter;
|
|
18
|
+
export declare function listAccountProviders(): string[];
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const nonEmpty = (provider, kind, value) => {
|
|
2
|
+
if (!value.trim())
|
|
3
|
+
throw new Error(`${provider} ${kind} cannot be empty.`);
|
|
4
|
+
};
|
|
5
|
+
function fixed(provider, authKinds, envByHost, connectionEnvByHost = {}, baseUrlEnvByHost = {}, validate) {
|
|
6
|
+
return {
|
|
7
|
+
provider,
|
|
8
|
+
authKinds,
|
|
9
|
+
envFor(host, kind) {
|
|
10
|
+
if (!authKinds.includes(kind))
|
|
11
|
+
throw new Error(`Provider '${provider}' does not support ${kind} accounts.`);
|
|
12
|
+
const env = envByHost[host];
|
|
13
|
+
if (!env)
|
|
14
|
+
throw new Error(`Provider '${provider}' cannot authenticate the ${host} harness.`);
|
|
15
|
+
return env;
|
|
16
|
+
},
|
|
17
|
+
connectionEnvFor(host) {
|
|
18
|
+
return connectionEnvByHost[host] ?? {};
|
|
19
|
+
},
|
|
20
|
+
baseUrlEnvFor(host) {
|
|
21
|
+
const connection = connectionEnvByHost[host] ?? {};
|
|
22
|
+
return baseUrlEnvByHost[host] ?? Object.keys(connection).find(key => key.endsWith('_BASE_URL')) ?? null;
|
|
23
|
+
},
|
|
24
|
+
validate(kind, value) {
|
|
25
|
+
nonEmpty(provider, kind, value);
|
|
26
|
+
validate?.(kind, value);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const ADAPTERS = new Map([
|
|
31
|
+
['anthropic', fixed('anthropic', ['api-key', 'setup-token'], { claude: 'ANTHROPIC_API_KEY' }, {}, {}, (kind, value) => {
|
|
32
|
+
if (kind === 'setup-token' && !value.startsWith('sk-ant-oat01-')) {
|
|
33
|
+
throw new Error('Anthropic setup tokens must start with sk-ant-oat01-.');
|
|
34
|
+
}
|
|
35
|
+
})],
|
|
36
|
+
['cursor', fixed('cursor', ['api-key'], { cursor: 'CURSOR_API_KEY' })],
|
|
37
|
+
['openrouter', fixed('openrouter', ['api-key'], { claude: 'ANTHROPIC_AUTH_TOKEN', codex: 'OPENAI_API_KEY', opencode: 'OPENROUTER_API_KEY' }, { claude: { ANTHROPIC_BASE_URL: 'https://openrouter.ai/api' }, codex: { OPENAI_BASE_URL: 'https://openrouter.ai/api/v1' } })],
|
|
38
|
+
['deepinfra', fixed('deepinfra', ['api-key'], { codex: 'OPENAI_API_KEY' }, { codex: { OPENAI_BASE_URL: 'https://api.deepinfra.com/v1/openai' } })],
|
|
39
|
+
['openai', fixed('openai', ['api-key'], { codex: 'OPENAI_API_KEY', opencode: 'OPENAI_API_KEY' }, {}, { codex: 'OPENAI_BASE_URL', opencode: 'OPENAI_BASE_URL' })],
|
|
40
|
+
['xai', fixed('xai', ['api-key'], { grok: 'XAI_API_KEY', claude: 'ANTHROPIC_AUTH_TOKEN' })],
|
|
41
|
+
['google', fixed('google', ['api-key'], { gemini: 'GEMINI_API_KEY', antigravity: 'ANTIGRAVITY_API_KEY' })],
|
|
42
|
+
['opencode', fixed('opencode', ['api-key'], { opencode: 'OPENCODE_API_KEY' })],
|
|
43
|
+
['proxy', fixed('proxy', ['api-key', 'bearer-token'], { claude: 'ANTHROPIC_AUTH_TOKEN', codex: 'OPENAI_API_KEY' }, {}, { claude: 'ANTHROPIC_BASE_URL', codex: 'OPENAI_BASE_URL' })],
|
|
44
|
+
['truefoundry', fixed('truefoundry', ['api-key', 'bearer-token'], { claude: 'ANTHROPIC_AUTH_TOKEN' }, {}, { claude: 'ANTHROPIC_BASE_URL' })],
|
|
45
|
+
['bedrock', fixed('bedrock', ['bearer-token'], { claude: 'AWS_BEARER_TOKEN_BEDROCK' })],
|
|
46
|
+
['foundry', fixed('foundry', ['api-key'], { claude: 'ANTHROPIC_FOUNDRY_API_KEY' })],
|
|
47
|
+
['litellm', fixed('litellm', ['api-key', 'bearer-token'], { claude: 'ANTHROPIC_AUTH_TOKEN', codex: 'OPENAI_API_KEY' }, {}, { claude: 'ANTHROPIC_BASE_URL', codex: 'OPENAI_BASE_URL' })],
|
|
48
|
+
['vllm', fixed('vllm', ['api-key', 'bearer-token'], { claude: 'ANTHROPIC_AUTH_TOKEN', codex: 'OPENAI_API_KEY' }, {}, { claude: 'ANTHROPIC_BASE_URL', codex: 'OPENAI_BASE_URL' })],
|
|
49
|
+
['ollama', fixed('ollama', ['api-key'], { codex: 'OPENAI_API_KEY' }, {}, { codex: 'OPENAI_BASE_URL' })],
|
|
50
|
+
]);
|
|
51
|
+
export function getAccountProvider(provider) {
|
|
52
|
+
const adapter = ADAPTERS.get(provider.toLowerCase());
|
|
53
|
+
if (!adapter)
|
|
54
|
+
throw new Error(`Unknown account provider '${provider}'. Supported: ${listAccountProviders().join(', ')}.`);
|
|
55
|
+
return adapter;
|
|
56
|
+
}
|
|
57
|
+
export function listAccountProviders() {
|
|
58
|
+
return [...ADAPTERS.keys()].sort();
|
|
59
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AgentId, Meta } from './types.js';
|
|
2
|
+
import { type AccountAuthKind } from './account-provider-registry.js';
|
|
3
|
+
export interface CredentialAccount {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
provider: string;
|
|
7
|
+
auth: AccountAuthKind;
|
|
8
|
+
secretRef: string;
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AccountRegistryDocument {
|
|
12
|
+
version: 2;
|
|
13
|
+
accounts: Record<string, CredentialAccount>;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolvedCredentialAccount {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
provider: string;
|
|
19
|
+
auth: AccountAuthKind;
|
|
20
|
+
env: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
export declare function accountRegistryPath(base?: string): string;
|
|
23
|
+
export declare function readAccountRegistry(base?: string): AccountRegistryDocument;
|
|
24
|
+
export declare function findAccount(name: string, doc?: AccountRegistryDocument): CredentialAccount | null;
|
|
25
|
+
/** Explicit selection wins over a configured per-harness default. */
|
|
26
|
+
export declare function resolveAccountSelection(explicit: string | undefined, agent: AgentId, meta: Pick<Meta, 'accounts'>, opts?: {
|
|
27
|
+
useDefault?: boolean;
|
|
28
|
+
}): string | undefined;
|
|
29
|
+
export interface AddAccountOptions {
|
|
30
|
+
baseUrl?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function addAccount(name: string, provider: string, auth: AccountAuthKind, secret: string, base?: string, opts?: AddAccountOptions): CredentialAccount;
|
|
33
|
+
export declare function setAccountSecret(name: string, secret: string, base?: string): void;
|
|
34
|
+
export declare function renameAccount(oldName: string, newName: string, base?: string): void;
|
|
35
|
+
export declare function removeAccount(name: string, base?: string): void;
|
|
36
|
+
export declare function inspectAccount(name: string, base?: string): CredentialAccount & {
|
|
37
|
+
secretPresent: boolean;
|
|
38
|
+
policy: 'never';
|
|
39
|
+
};
|
|
40
|
+
export declare function resolveCredentialAccount(name: string, host: AgentId, expectedProvider?: string, base?: string): ResolvedCredentialAccount;
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential accounts, stored as canonical `agents secrets` bundles (RUSH-2470).
|
|
3
|
+
*
|
|
4
|
+
* One account IS one bundle: the bundle label is the account name, its vars
|
|
5
|
+
* carry the identity (ACCOUNT_ID / PROVIDER / AUTH_TYPE / optional BASE_URL)
|
|
6
|
+
* and the secret (API_KEY or TOKEN), and it uses the `never` prompt policy so
|
|
7
|
+
* it reads headlessly and syncs across the fleet with no Touch ID. The bundle
|
|
8
|
+
* shape lives in [[account-schema]]; this module owns the CRUD, resolution,
|
|
9
|
+
* and the one-time migration off the legacy `accounts.yaml`.
|
|
10
|
+
*
|
|
11
|
+
* `readAccountRegistry()` still returns the historical
|
|
12
|
+
* `{ version: 2, accounts }` view so existing consumers (harness, profiles,
|
|
13
|
+
* exec) keep working — it is now a projection over the account bundles, not a
|
|
14
|
+
* file read. Native OAuth logins are NOT accounts here; they stay native and
|
|
15
|
+
* surface through unified discovery in [[account-catalog]].
|
|
16
|
+
*/
|
|
17
|
+
import * as fs from 'node:fs';
|
|
18
|
+
import * as path from 'node:path';
|
|
19
|
+
import * as crypto from 'node:crypto';
|
|
20
|
+
import * as yaml from 'yaml';
|
|
21
|
+
import { atomicWriteFileSync } from './fs-atomic.js';
|
|
22
|
+
import { getUserAgentsDir } from './state.js';
|
|
23
|
+
import { deleteKeychainToken, getKeychainToken, hasKeychainToken } from './secrets/index.js';
|
|
24
|
+
import { bundleExists, deleteBundle, listBundles, readBundle, renameBundle, writeBundleWithItems } from './secrets/bundles.js';
|
|
25
|
+
import { getAccountProvider } from './account-provider-registry.js';
|
|
26
|
+
import { accountSecretItem, buildAccountBundle, parseAccountBundle } from './account-schema.js';
|
|
27
|
+
const NAME = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
28
|
+
const AUTH_KINDS = ['api-key', 'setup-token', 'bearer-token'];
|
|
29
|
+
export function accountRegistryPath(base = getUserAgentsDir()) { return path.join(base, 'accounts.yaml'); }
|
|
30
|
+
function assertName(name) {
|
|
31
|
+
if (!NAME.test(name))
|
|
32
|
+
throw new Error('Account name must start with a letter or number and contain only letters, numbers, dot, underscore, or dash.');
|
|
33
|
+
}
|
|
34
|
+
function isAccountAuthKind(value) {
|
|
35
|
+
return typeof value === 'string' && AUTH_KINDS.includes(value);
|
|
36
|
+
}
|
|
37
|
+
function toCredentialAccount(record) {
|
|
38
|
+
return {
|
|
39
|
+
id: record.id,
|
|
40
|
+
name: record.name,
|
|
41
|
+
provider: record.provider,
|
|
42
|
+
auth: record.auth,
|
|
43
|
+
secretRef: accountSecretItem(record.name, record.auth),
|
|
44
|
+
baseUrl: record.baseUrl,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Every account bundle currently on this device, keyed by stable id. */
|
|
48
|
+
function readAccountBundles() {
|
|
49
|
+
const out = [];
|
|
50
|
+
for (const bundle of listBundles()) {
|
|
51
|
+
const record = parseAccountBundle(bundle);
|
|
52
|
+
if (record)
|
|
53
|
+
out.push(toCredentialAccount(record));
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Fold a legacy `accounts.yaml` into account bundles, then archive it.
|
|
59
|
+
* Transactional: every bundle is written first, and the file is archived (and
|
|
60
|
+
* the old per-account keychain items dropped) ONLY after all writes succeed —
|
|
61
|
+
* so an interrupted migration leaves the file in place and the next read
|
|
62
|
+
* retries, skipping accounts that already landed as a bundle.
|
|
63
|
+
*/
|
|
64
|
+
function migrateLegacyRegistryFile(base) {
|
|
65
|
+
const file = accountRegistryPath(base);
|
|
66
|
+
if (!fs.existsSync(file))
|
|
67
|
+
return;
|
|
68
|
+
const raw = yaml.parse(fs.readFileSync(file, 'utf8'));
|
|
69
|
+
if (!raw || Array.isArray(raw))
|
|
70
|
+
throw new Error(`Account registry corrupted at ${file}: expected a YAML map.`);
|
|
71
|
+
// Legacy version-bound labels (pre-credential-accounts) are not credentials —
|
|
72
|
+
// archive them so they are never resurrected as fake accounts.
|
|
73
|
+
if (raw.version === undefined && raw.labels !== undefined) {
|
|
74
|
+
archiveLegacyFile(file, 'accounts.legacy-labels.yaml');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (raw.version !== 2)
|
|
78
|
+
throw new Error(`Unsupported account registry version '${String(raw.version)}' at ${file}.`);
|
|
79
|
+
const legacyAccounts = (raw.accounts && typeof raw.accounts === 'object' && !Array.isArray(raw.accounts))
|
|
80
|
+
? raw.accounts
|
|
81
|
+
: {};
|
|
82
|
+
const retiredSecretItems = [];
|
|
83
|
+
for (const [key, value] of Object.entries(legacyAccounts)) {
|
|
84
|
+
const item = value ?? {};
|
|
85
|
+
const auth = item.auth;
|
|
86
|
+
if (!isAccountAuthKind(auth))
|
|
87
|
+
throw new Error(`Account '${key}' has unsupported auth kind '${String(auth)}'.`);
|
|
88
|
+
const id = String(item.id ?? key);
|
|
89
|
+
const name = String(item.name ?? '');
|
|
90
|
+
assertName(name);
|
|
91
|
+
const provider = String(item.provider ?? '');
|
|
92
|
+
const legacySecretRef = String(item.secretRef ?? `agents-cli.accounts.${id}.credential`);
|
|
93
|
+
retiredSecretItems.push(legacySecretRef);
|
|
94
|
+
if (bundleExists(name)) {
|
|
95
|
+
const existing = parseAccountBundle(readBundle(name));
|
|
96
|
+
if (!existing || existing.id !== id) {
|
|
97
|
+
throw new Error(`Cannot migrate account '${name}': a different secrets bundle already uses that name.`);
|
|
98
|
+
}
|
|
99
|
+
continue; // already migrated on an earlier, interrupted run
|
|
100
|
+
}
|
|
101
|
+
const baseUrl = item.baseUrl ? String(item.baseUrl) : undefined;
|
|
102
|
+
const record = { id, name, provider, auth, baseUrl };
|
|
103
|
+
const secret = hasKeychainToken(legacySecretRef) ? getKeychainToken(legacySecretRef) : '';
|
|
104
|
+
const { bundle, items } = buildAccountBundle(record, secret || 'x');
|
|
105
|
+
if (!secret)
|
|
106
|
+
items.clear(); // no device-local secret: write metadata only
|
|
107
|
+
writeBundleWithItems(bundle, items);
|
|
108
|
+
}
|
|
109
|
+
// Success: the file's accounts all exist as bundles now. Archive it and drop
|
|
110
|
+
// the superseded per-account keychain items.
|
|
111
|
+
archiveLegacyFile(file, 'accounts.migrated.yaml');
|
|
112
|
+
for (const legacyItem of retiredSecretItems)
|
|
113
|
+
deleteKeychainToken(legacyItem);
|
|
114
|
+
}
|
|
115
|
+
function archiveLegacyFile(file, archiveName) {
|
|
116
|
+
const archived = path.join(path.dirname(file), archiveName);
|
|
117
|
+
if (fs.existsSync(archived))
|
|
118
|
+
fs.rmSync(archived, { force: true });
|
|
119
|
+
fs.renameSync(file, archived);
|
|
120
|
+
}
|
|
121
|
+
export function readAccountRegistry(base = getUserAgentsDir()) {
|
|
122
|
+
migrateLegacyRegistryFile(base);
|
|
123
|
+
const accounts = {};
|
|
124
|
+
for (const account of readAccountBundles())
|
|
125
|
+
accounts[account.id] = account;
|
|
126
|
+
return { version: 2, accounts };
|
|
127
|
+
}
|
|
128
|
+
export function findAccount(name, doc = readAccountRegistry()) {
|
|
129
|
+
return doc.accounts[name] ?? Object.values(doc.accounts).find(account => account.name === name) ?? null;
|
|
130
|
+
}
|
|
131
|
+
/** Explicit selection wins over a configured per-harness default. */
|
|
132
|
+
export function resolveAccountSelection(explicit, agent, meta, opts = {}) {
|
|
133
|
+
if (explicit)
|
|
134
|
+
return explicit;
|
|
135
|
+
return opts.useDefault === false ? undefined : meta.accounts?.defaults?.[agent];
|
|
136
|
+
}
|
|
137
|
+
function profileConsumers(name, base) {
|
|
138
|
+
const dir = path.join(base, 'profiles');
|
|
139
|
+
if (!fs.existsSync(dir))
|
|
140
|
+
return [];
|
|
141
|
+
const consumers = [];
|
|
142
|
+
for (const file of fs.readdirSync(dir).filter(value => /\.ya?ml$/.test(value))) {
|
|
143
|
+
const raw = yaml.parse(fs.readFileSync(path.join(dir, file), 'utf8'));
|
|
144
|
+
if (raw?.account === name)
|
|
145
|
+
consumers.push(file.replace(/\.ya?ml$/, ''));
|
|
146
|
+
}
|
|
147
|
+
return consumers.sort();
|
|
148
|
+
}
|
|
149
|
+
function renameProfileConsumers(oldName, newName, base) {
|
|
150
|
+
const dir = path.join(base, 'profiles');
|
|
151
|
+
for (const profile of profileConsumers(oldName, base)) {
|
|
152
|
+
const file = path.join(dir, `${profile}.yml`);
|
|
153
|
+
const yamlFile = fs.existsSync(file) ? file : path.join(dir, `${profile}.yaml`);
|
|
154
|
+
const raw = yaml.parse(fs.readFileSync(yamlFile, 'utf8'));
|
|
155
|
+
raw.account = newName;
|
|
156
|
+
atomicWriteFileSync(yamlFile, yaml.stringify(raw));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export function addAccount(name, provider, auth, secret, base = getUserAgentsDir(), opts = {}) {
|
|
160
|
+
assertName(name);
|
|
161
|
+
const adapter = getAccountProvider(provider);
|
|
162
|
+
adapter.validate(auth, secret);
|
|
163
|
+
if (bundleExists(name))
|
|
164
|
+
throw new Error(`Secrets bundle '${name}' already exists. Choose a different account name.`);
|
|
165
|
+
if (findAccount(name, readAccountRegistry(base)))
|
|
166
|
+
throw new Error(`Account '${name}' already exists.`);
|
|
167
|
+
const record = { id: crypto.randomUUID(), name, provider: adapter.provider, auth, baseUrl: opts.baseUrl };
|
|
168
|
+
const { bundle, items } = buildAccountBundle(record, secret);
|
|
169
|
+
writeBundleWithItems(bundle, items);
|
|
170
|
+
return toCredentialAccount(record);
|
|
171
|
+
}
|
|
172
|
+
export function setAccountSecret(name, secret, base = getUserAgentsDir()) {
|
|
173
|
+
const account = findAccount(name, readAccountRegistry(base));
|
|
174
|
+
if (!account)
|
|
175
|
+
throw new Error(`Unknown account '${name}'.`);
|
|
176
|
+
getAccountProvider(account.provider).validate(account.auth, secret);
|
|
177
|
+
const record = { id: account.id, name: account.name, provider: account.provider, auth: account.auth, baseUrl: account.baseUrl };
|
|
178
|
+
const { bundle, items } = buildAccountBundle(record, secret);
|
|
179
|
+
bundle.created_at = readBundle(account.name).created_at; // rotate the secret, keep the bundle's birth time
|
|
180
|
+
writeBundleWithItems(bundle, items);
|
|
181
|
+
}
|
|
182
|
+
export function renameAccount(oldName, newName, base = getUserAgentsDir()) {
|
|
183
|
+
assertName(newName);
|
|
184
|
+
const doc = readAccountRegistry(base);
|
|
185
|
+
const account = findAccount(oldName, doc);
|
|
186
|
+
if (!account)
|
|
187
|
+
throw new Error(`Unknown account '${oldName}'.`);
|
|
188
|
+
if (findAccount(newName, doc))
|
|
189
|
+
throw new Error(`Account '${newName}' already exists.`);
|
|
190
|
+
renameBundle(account.name, newName); // moves metadata + secret, preserves ACCOUNT_ID
|
|
191
|
+
renameProfileConsumers(account.name, newName, base);
|
|
192
|
+
}
|
|
193
|
+
export function removeAccount(name, base = getUserAgentsDir()) {
|
|
194
|
+
const account = findAccount(name, readAccountRegistry(base));
|
|
195
|
+
if (!account)
|
|
196
|
+
throw new Error(`Unknown account '${name}'.`);
|
|
197
|
+
const consumers = [...new Set([...profileConsumers(account.name, base), ...profileConsumers(account.id, base)])].sort();
|
|
198
|
+
if (consumers.length)
|
|
199
|
+
throw new Error(`Account '${account.name}' is used by harness${consumers.length === 1 ? '' : 'es'}: ${consumers.join(', ')}. Reassign them before removing it.`);
|
|
200
|
+
deleteKeychainToken(account.secretRef);
|
|
201
|
+
deleteBundle(account.name);
|
|
202
|
+
}
|
|
203
|
+
export function inspectAccount(name, base = getUserAgentsDir()) {
|
|
204
|
+
const account = findAccount(name, readAccountRegistry(base));
|
|
205
|
+
if (!account)
|
|
206
|
+
throw new Error(`Unknown account '${name}'.`);
|
|
207
|
+
const bundle = readBundle(account.name);
|
|
208
|
+
if (bundle.policy !== 'never')
|
|
209
|
+
throw new Error(`Account bundle '${account.name}' must use secrets policy 'never'.`);
|
|
210
|
+
return { ...account, secretPresent: hasKeychainToken(account.secretRef), policy: bundle.policy };
|
|
211
|
+
}
|
|
212
|
+
export function resolveCredentialAccount(name, host, expectedProvider, base = getUserAgentsDir()) {
|
|
213
|
+
const account = findAccount(name, readAccountRegistry(base));
|
|
214
|
+
if (!account)
|
|
215
|
+
throw new Error(`Unknown account '${name}'.`);
|
|
216
|
+
if (expectedProvider && account.provider !== expectedProvider)
|
|
217
|
+
throw new Error(`Account '${account.name}' uses provider '${account.provider}', but this harness requires '${expectedProvider}'.`);
|
|
218
|
+
const adapter = getAccountProvider(account.provider);
|
|
219
|
+
if (account.auth === 'setup-token' && (account.provider !== 'anthropic' || host !== 'claude')) {
|
|
220
|
+
throw new Error(`Provider '${account.provider}' cannot use a setup-token with the ${host} harness.`);
|
|
221
|
+
}
|
|
222
|
+
const envVar = account.auth === 'setup-token' ? 'CLAUDE_CODE_OAUTH_TOKEN' : adapter.envFor(host, account.auth);
|
|
223
|
+
if (!hasKeychainToken(account.secretRef))
|
|
224
|
+
throw new Error(`Credential for account '${account.name}' is missing on this device. Add it with 'agents accounts set-key ${account.name}'.`);
|
|
225
|
+
const connectionEnv = { ...adapter.connectionEnvFor(host) };
|
|
226
|
+
if (account.baseUrl) {
|
|
227
|
+
const baseUrlEnv = adapter.baseUrlEnvFor(host);
|
|
228
|
+
if (!baseUrlEnv)
|
|
229
|
+
throw new Error(`Account '${account.name}' has a base URL override, but provider '${account.provider}' cannot apply it to the ${host} harness.`);
|
|
230
|
+
connectionEnv[baseUrlEnv] = account.baseUrl;
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
id: account.id,
|
|
234
|
+
name: account.name,
|
|
235
|
+
provider: account.provider,
|
|
236
|
+
auth: account.auth,
|
|
237
|
+
env: { ...connectionEnv, [envVar]: getKeychainToken(account.secretRef) },
|
|
238
|
+
};
|
|
239
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { SecretsBundle } from './secrets/bundles.js';
|
|
2
|
+
import type { AccountAuthKind } from './account-provider-registry.js';
|
|
3
|
+
/** Canonical bundle variable names for a provider-account bundle. */
|
|
4
|
+
export declare const ACCOUNT_VARS: {
|
|
5
|
+
readonly id: "ACCOUNT_ID";
|
|
6
|
+
readonly provider: "PROVIDER";
|
|
7
|
+
readonly authType: "AUTH_TYPE";
|
|
8
|
+
readonly baseUrl: "BASE_URL";
|
|
9
|
+
readonly apiKey: "API_KEY";
|
|
10
|
+
readonly token: "TOKEN";
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Account bundles are stored with the `never` prompt policy: no biometry ACL,
|
|
14
|
+
* so reads are silent and the bundle syncs across the fleet without Touch ID.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ACCOUNT_POLICY: "never";
|
|
17
|
+
/** The parsed identity of an account, independent of where its bytes live. */
|
|
18
|
+
export interface AccountSchemaRecord {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
provider: string;
|
|
22
|
+
auth: AccountAuthKind;
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
/** The single secret var name that carries the credential for an auth kind. */
|
|
26
|
+
export declare function secretVarFor(auth: AccountAuthKind): 'API_KEY' | 'TOKEN';
|
|
27
|
+
/** The keychain item that stores an account bundle's secret value. */
|
|
28
|
+
export declare function accountSecretItem(name: string, auth: AccountAuthKind): string;
|
|
29
|
+
/**
|
|
30
|
+
* Build the canonical account bundle plus the keychain item map holding its
|
|
31
|
+
* secret. The identity vars are literals; the secret var is a `keychain:` ref
|
|
32
|
+
* whose value lives in the returned item map, ready for `writeBundleWithItems`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function buildAccountBundle(record: AccountSchemaRecord, secret: string): {
|
|
35
|
+
bundle: SecretsBundle;
|
|
36
|
+
items: Map<string, string>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Parse an account record from a bundle, or null when the bundle is not an
|
|
40
|
+
* account bundle (missing ACCOUNT_ID / PROVIDER / a known AUTH_TYPE). The
|
|
41
|
+
* catalog uses the null return to keep ordinary secrets bundles out of the
|
|
42
|
+
* account list.
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseAccountBundle(bundle: SecretsBundle): AccountSchemaRecord | null;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical on-disk shape of a provider credential account.
|
|
3
|
+
*
|
|
4
|
+
* RUSH-2470 makes a `agents secrets` bundle the single source of truth for a
|
|
5
|
+
* credential account: one account IS one bundle. The bundle's label is the
|
|
6
|
+
* account name; its variables carry the account's identity plus its secret:
|
|
7
|
+
*
|
|
8
|
+
* ACCOUNT_ID the stable UUID (a literal, survives rename)
|
|
9
|
+
* PROVIDER the provider id (a literal, e.g. 'openrouter')
|
|
10
|
+
* AUTH_TYPE 'api-key' | 'setup-token' | 'bearer-token' (a literal)
|
|
11
|
+
* BASE_URL optional endpoint override (a literal)
|
|
12
|
+
* API_KEY the secret, for AUTH_TYPE 'api-key' (a keychain ref)
|
|
13
|
+
* TOKEN the secret, for setup-token/bearer-token (a keychain ref)
|
|
14
|
+
*
|
|
15
|
+
* The identity vars are non-secret literals stored inline in the bundle
|
|
16
|
+
* metadata; only API_KEY / TOKEN reference a keychain-backed value. Account
|
|
17
|
+
* bundles use the `never` prompt policy so their values carry no biometry ACL
|
|
18
|
+
* and sync (and read headlessly) with no Touch ID — the whole point of the
|
|
19
|
+
* change. This module is pure: it builds a bundle from a record and parses a
|
|
20
|
+
* record back out, with no I/O. The registry ([[account-registry]]) owns
|
|
21
|
+
* reads and writes; the catalog ([[account-catalog]]) owns discovery.
|
|
22
|
+
*/
|
|
23
|
+
import { parseBundleValue, secretsKeychainItem } from './secrets/index.js';
|
|
24
|
+
/** Canonical bundle variable names for a provider-account bundle. */
|
|
25
|
+
export const ACCOUNT_VARS = {
|
|
26
|
+
id: 'ACCOUNT_ID',
|
|
27
|
+
provider: 'PROVIDER',
|
|
28
|
+
authType: 'AUTH_TYPE',
|
|
29
|
+
baseUrl: 'BASE_URL',
|
|
30
|
+
apiKey: 'API_KEY',
|
|
31
|
+
token: 'TOKEN',
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Account bundles are stored with the `never` prompt policy: no biometry ACL,
|
|
35
|
+
* so reads are silent and the bundle syncs across the fleet without Touch ID.
|
|
36
|
+
*/
|
|
37
|
+
export const ACCOUNT_POLICY = 'never';
|
|
38
|
+
/** The single secret var name that carries the credential for an auth kind. */
|
|
39
|
+
export function secretVarFor(auth) {
|
|
40
|
+
return auth === 'api-key' ? ACCOUNT_VARS.apiKey : ACCOUNT_VARS.token;
|
|
41
|
+
}
|
|
42
|
+
/** The keychain item that stores an account bundle's secret value. */
|
|
43
|
+
export function accountSecretItem(name, auth) {
|
|
44
|
+
return secretsKeychainItem(name, secretVarFor(auth));
|
|
45
|
+
}
|
|
46
|
+
/** Read a bundle var as a literal string, or undefined if it is a secret ref. */
|
|
47
|
+
function literalOf(raw) {
|
|
48
|
+
if (raw === undefined)
|
|
49
|
+
return undefined;
|
|
50
|
+
const parsed = parseBundleValue(raw);
|
|
51
|
+
return 'literal' in parsed ? parsed.literal : undefined;
|
|
52
|
+
}
|
|
53
|
+
function isAccountAuthKind(value) {
|
|
54
|
+
return value === 'api-key' || value === 'setup-token' || value === 'bearer-token';
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build the canonical account bundle plus the keychain item map holding its
|
|
58
|
+
* secret. The identity vars are literals; the secret var is a `keychain:` ref
|
|
59
|
+
* whose value lives in the returned item map, ready for `writeBundleWithItems`.
|
|
60
|
+
*/
|
|
61
|
+
export function buildAccountBundle(record, secret) {
|
|
62
|
+
const secretVar = secretVarFor(record.auth);
|
|
63
|
+
const vars = {
|
|
64
|
+
[ACCOUNT_VARS.id]: record.id,
|
|
65
|
+
[ACCOUNT_VARS.provider]: record.provider,
|
|
66
|
+
[ACCOUNT_VARS.authType]: record.auth,
|
|
67
|
+
[secretVar]: `keychain:${secretVar}`,
|
|
68
|
+
};
|
|
69
|
+
// Wrap BASE_URL as an escaped literal so a URL that happens to start with a
|
|
70
|
+
// ref prefix (e.g. 'env://…') is never misread as a secret reference.
|
|
71
|
+
if (record.baseUrl)
|
|
72
|
+
vars[ACCOUNT_VARS.baseUrl] = { value: record.baseUrl };
|
|
73
|
+
const bundle = { name: record.name, policy: ACCOUNT_POLICY, vars };
|
|
74
|
+
const items = new Map([[secretsKeychainItem(record.name, secretVar), secret]]);
|
|
75
|
+
return { bundle, items };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Parse an account record from a bundle, or null when the bundle is not an
|
|
79
|
+
* account bundle (missing ACCOUNT_ID / PROVIDER / a known AUTH_TYPE). The
|
|
80
|
+
* catalog uses the null return to keep ordinary secrets bundles out of the
|
|
81
|
+
* account list.
|
|
82
|
+
*/
|
|
83
|
+
export function parseAccountBundle(bundle) {
|
|
84
|
+
const id = literalOf(bundle.vars[ACCOUNT_VARS.id]);
|
|
85
|
+
const provider = literalOf(bundle.vars[ACCOUNT_VARS.provider]);
|
|
86
|
+
const auth = literalOf(bundle.vars[ACCOUNT_VARS.authType]);
|
|
87
|
+
if (!id || !provider || !isAccountAuthKind(auth))
|
|
88
|
+
return null;
|
|
89
|
+
const baseUrl = literalOf(bundle.vars[ACCOUNT_VARS.baseUrl]);
|
|
90
|
+
return { id, name: bundle.name, provider, auth, baseUrl };
|
|
91
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Device-local owner for usage snapshots and authentication health. */
|
|
2
|
+
export declare const USAGE_STATE_TICK_MS = 60000;
|
|
3
|
+
export declare const AUTH_STATE_TICK_MS: number;
|
|
4
|
+
export interface AccountStateService {
|
|
5
|
+
stop(): void;
|
|
6
|
+
}
|
|
7
|
+
export interface AccountStateServiceDeps {
|
|
8
|
+
refreshUsage: () => Promise<void>;
|
|
9
|
+
refreshAuth: () => Promise<void>;
|
|
10
|
+
onError?: (area: 'usage' | 'auth', error: unknown) => void;
|
|
11
|
+
setInterval?: typeof globalThis.setInterval;
|
|
12
|
+
clearInterval?: typeof globalThis.clearInterval;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Start the daemon-owned account-state loops.
|
|
16
|
+
*
|
|
17
|
+
* Each loop is overlap-safe within the daemon. Provider-level work is also
|
|
18
|
+
* guarded by the cross-process refresh lease, so an explicit CLI refresh and
|
|
19
|
+
* an older routine process converge on the same published result.
|
|
20
|
+
*/
|
|
21
|
+
export declare function startAccountStateService(deps: AccountStateServiceDeps): AccountStateService;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Device-local owner for usage snapshots and authentication health. */
|
|
2
|
+
export const USAGE_STATE_TICK_MS = 60_000;
|
|
3
|
+
export const AUTH_STATE_TICK_MS = 3 * 60_000;
|
|
4
|
+
/**
|
|
5
|
+
* Start the daemon-owned account-state loops.
|
|
6
|
+
*
|
|
7
|
+
* Each loop is overlap-safe within the daemon. Provider-level work is also
|
|
8
|
+
* guarded by the cross-process refresh lease, so an explicit CLI refresh and
|
|
9
|
+
* an older routine process converge on the same published result.
|
|
10
|
+
*/
|
|
11
|
+
export function startAccountStateService(deps) {
|
|
12
|
+
const setTimer = deps.setInterval ?? globalThis.setInterval;
|
|
13
|
+
const clearTimer = deps.clearInterval ?? globalThis.clearInterval;
|
|
14
|
+
let usageRunning = false;
|
|
15
|
+
let authRunning = false;
|
|
16
|
+
let stopped = false;
|
|
17
|
+
const runUsage = async () => {
|
|
18
|
+
if (stopped || usageRunning)
|
|
19
|
+
return;
|
|
20
|
+
usageRunning = true;
|
|
21
|
+
try {
|
|
22
|
+
await deps.refreshUsage();
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
deps.onError?.('usage', error);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
usageRunning = false;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const runAuth = async () => {
|
|
32
|
+
if (stopped || authRunning)
|
|
33
|
+
return;
|
|
34
|
+
authRunning = true;
|
|
35
|
+
try {
|
|
36
|
+
await deps.refreshAuth();
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
deps.onError?.('auth', error);
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
authRunning = false;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const usageTimer = setTimer(() => { void runUsage(); }, USAGE_STATE_TICK_MS);
|
|
46
|
+
const authTimer = setTimer(() => { void runAuth(); }, AUTH_STATE_TICK_MS);
|
|
47
|
+
usageTimer.unref?.();
|
|
48
|
+
authTimer.unref?.();
|
|
49
|
+
void runUsage();
|
|
50
|
+
void runAuth();
|
|
51
|
+
return {
|
|
52
|
+
stop() {
|
|
53
|
+
if (stopped)
|
|
54
|
+
return;
|
|
55
|
+
stopped = true;
|
|
56
|
+
clearTimer(usageTimer);
|
|
57
|
+
clearTimer(authTimer);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
package/dist/lib/activity.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type MilestoneEvent = 'plan.created' | 'pr.opened' | 'pr.merged' | 'workt
|
|
|
7
7
|
/** Deliberate agent-authored progress post (`agents feed post`). */
|
|
8
8
|
| 'status.posted'
|
|
9
9
|
/**
|
|
10
|
-
* An agent terminal spawned from the
|
|
10
|
+
* An agent terminal spawned from AGI EXT, the VS Code extension. A milestone
|
|
11
11
|
* because it is the BIRTH of a session — it carries the sessionId and the
|
|
12
12
|
* terminalId that every later event on that session joins through, the same
|
|
13
13
|
* way `subagent.spawned` roots a sub-agent. Written out of process by
|