@phnx-labs/agents-cli 1.22.34 → 1.22.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +672 -2
- package/README.md +82 -35
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.d.ts +15 -0
- package/dist/bootstrap.js +1211 -0
- package/dist/commands/accounts.d.ts +4 -11
- package/dist/commands/accounts.js +159 -27
- package/dist/commands/attach.js +17 -4
- package/dist/commands/audit.d.ts +8 -8
- package/dist/commands/audit.js +57 -47
- package/dist/commands/browser.js +15 -11
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +0 -11
- package/dist/commands/computer-actions.js +33 -0
- package/dist/commands/computer-sessions-picker.d.ts +21 -0
- package/dist/commands/computer-sessions-picker.js +141 -0
- package/dist/commands/computer.d.ts +16 -0
- package/dist/commands/computer.js +37 -0
- package/dist/commands/config.d.ts +17 -0
- package/dist/commands/config.js +401 -0
- package/dist/commands/cp.d.ts +84 -0
- package/dist/commands/cp.js +231 -0
- package/dist/commands/daemon.js +243 -14
- package/dist/commands/detach-core.d.ts +1 -1
- package/dist/commands/detach-core.js +12 -2
- package/dist/commands/detach.js +1 -1
- package/dist/commands/doctor.js +64 -5
- package/dist/commands/events.d.ts +24 -12
- package/dist/commands/events.js +144 -28
- package/dist/commands/exec.js +85 -41
- package/dist/commands/feed.d.ts +1 -1
- package/dist/commands/feed.js +16 -8
- package/dist/commands/focus.d.ts +33 -1
- package/dist/commands/focus.js +177 -17
- package/dist/commands/funnel.d.ts +1 -1
- package/dist/commands/go.js +9 -8
- package/dist/commands/harness-wizard.d.ts +1 -0
- package/dist/commands/harness-wizard.js +18 -20
- package/dist/commands/harness.d.ts +2 -0
- package/dist/commands/harness.js +59 -26
- package/dist/commands/hooks.js +0 -11
- package/dist/commands/inspect.d.ts +94 -1
- package/dist/commands/inspect.js +866 -40
- package/dist/commands/lease.d.ts +4 -4
- package/dist/commands/lease.js +6 -6
- package/dist/commands/login.js +0 -13
- package/dist/commands/logs.d.ts +2 -2
- package/dist/commands/logs.js +2 -2
- package/dist/commands/mcp.js +7 -2
- package/dist/commands/memory.js +7 -2
- package/dist/commands/message.d.ts +1 -1
- package/dist/commands/message.js +37 -6
- package/dist/commands/models.js +4 -0
- package/dist/commands/monitors.d.ts +0 -1
- package/dist/commands/monitors.js +199 -16
- package/dist/commands/open.d.ts +18 -0
- package/dist/commands/open.js +57 -0
- package/dist/commands/packages.js +2 -107
- package/dist/commands/plugins.js +6 -3
- package/dist/commands/profiles.d.ts +1 -0
- package/dist/commands/profiles.js +16 -160
- package/dist/commands/projects.d.ts +28 -0
- package/dist/commands/projects.js +125 -5
- package/dist/commands/reconnect.js +9 -3
- package/dist/commands/repo.js +42 -1
- package/dist/commands/resource-view.d.ts +17 -0
- package/dist/commands/resource-view.js +36 -14
- package/dist/commands/resume.js +9 -2
- package/dist/commands/routines.d.ts +0 -2
- package/dist/commands/routines.js +473 -289
- package/dist/commands/secrets.js +52 -9
- package/dist/commands/sessions-export.d.ts +47 -0
- package/dist/commands/sessions-export.js +116 -6
- package/dist/commands/sessions-import.d.ts +17 -0
- package/dist/commands/sessions-import.js +114 -6
- package/dist/commands/sessions-migrate.d.ts +27 -0
- package/dist/commands/sessions-migrate.js +50 -9
- package/dist/commands/sessions-picker.js +23 -4
- package/dist/commands/sessions-resume.d.ts +5 -3
- package/dist/commands/sessions-resume.js +30 -8
- package/dist/commands/sessions-watch.d.ts +2 -0
- package/dist/commands/sessions-watch.js +53 -0
- package/dist/commands/sessions.d.ts +66 -3
- package/dist/commands/sessions.js +298 -47
- package/dist/commands/set.d.ts +1 -1
- package/dist/commands/set.js +2 -2
- package/dist/commands/setup-browser.js +2 -2
- package/dist/commands/setup-mine.js +0 -1
- package/dist/commands/setup-preferences.js +1 -1
- package/dist/commands/setup-share.js +34 -4
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.js +26 -0
- package/dist/commands/share.d.ts +85 -0
- package/dist/commands/share.js +379 -8
- package/dist/commands/skills.js +0 -11
- package/dist/commands/snapshot.js +1 -1
- package/dist/commands/ssh.d.ts +18 -0
- package/dist/commands/ssh.js +549 -210
- package/dist/commands/sync.d.ts +5 -0
- package/dist/commands/sync.js +212 -32
- package/dist/commands/teams.d.ts +13 -0
- package/dist/commands/teams.js +187 -30
- package/dist/commands/tickets.d.ts +2 -0
- package/dist/commands/tickets.js +43 -0
- package/dist/commands/update.js +2 -4
- package/dist/commands/usage.js +5 -3
- package/dist/commands/versions.js +11 -5
- package/dist/commands/view.js +15 -7
- package/dist/commands/webhook.d.ts +2 -2
- package/dist/commands/webhook.js +7 -7
- package/dist/index.d.ts +18 -2
- package/dist/index.js +53 -1264
- package/dist/lib/account-catalog.d.ts +18 -0
- package/dist/lib/account-catalog.js +38 -0
- package/dist/lib/account-provider-registry.d.ts +18 -0
- package/dist/lib/account-provider-registry.js +59 -0
- package/dist/lib/account-registry.d.ts +40 -0
- package/dist/lib/account-registry.js +239 -0
- package/dist/lib/account-schema.d.ts +44 -0
- package/dist/lib/account-schema.js +91 -0
- package/dist/lib/account-state-service.d.ts +21 -0
- package/dist/lib/account-state-service.js +60 -0
- package/dist/lib/activity.d.ts +1 -1
- package/dist/lib/activity.js +8 -1
- package/dist/lib/add-dir.d.ts +80 -0
- package/dist/lib/add-dir.js +241 -0
- package/dist/lib/agent-cli-commands.d.ts +11 -0
- package/dist/lib/agent-cli-commands.js +30 -0
- package/dist/lib/agents.js +44 -36
- package/dist/lib/answer-router.js +1 -1
- package/dist/lib/audit/log.d.ts +10 -27
- package/dist/lib/audit/log.js +20 -33
- package/dist/lib/auth-health.d.ts +9 -2
- package/dist/lib/auth-health.js +42 -9
- package/dist/lib/auto-pull-worker.js +7 -3
- package/dist/lib/auto-pull.d.ts +44 -3
- package/dist/lib/auto-pull.js +88 -5
- package/dist/lib/binary-shadow.d.ts +28 -0
- package/dist/lib/binary-shadow.js +121 -0
- package/dist/lib/brand.js +9 -3
- package/dist/lib/browser/ipc.d.ts +30 -0
- package/dist/lib/browser/ipc.js +81 -4
- package/dist/lib/browser/profiles.d.ts +3 -2
- package/dist/lib/browser/profiles.js +65 -22
- package/dist/lib/browser/service.d.ts +4 -0
- package/dist/lib/browser/service.js +30 -3
- package/dist/lib/browser/sessions-list.d.ts +22 -2
- package/dist/lib/browser/sessions-list.js +54 -6
- package/dist/lib/browser/stream.d.ts +2 -0
- package/dist/lib/browser/stream.js +1 -0
- package/dist/lib/browser/types.d.ts +19 -0
- package/dist/lib/byok-usage.d.ts +9 -2
- package/dist/lib/byok-usage.js +133 -31
- package/dist/lib/cli-entry.d.ts +11 -0
- package/dist/lib/cli-entry.js +46 -0
- package/dist/lib/cloud/host.d.ts +1 -1
- package/dist/lib/cloud/host.js +2 -2
- package/dist/lib/cloud/registry.js +1 -1
- package/dist/lib/cloud/types.d.ts +1 -1
- package/dist/lib/codex-policy.d.ts +9 -1
- package/dist/lib/codex-policy.js +17 -2
- package/dist/lib/commands.d.ts +2 -0
- package/dist/lib/commands.js +2 -0
- package/dist/lib/computer/sessions-list.d.ts +150 -0
- package/dist/lib/computer/sessions-list.js +363 -0
- package/dist/lib/config-keys.d.ts +86 -0
- package/dist/lib/config-keys.js +193 -0
- package/dist/lib/config-machine-keys.d.ts +12 -0
- package/dist/lib/config-machine-keys.js +17 -0
- package/dist/lib/config-transfer.js +3 -4
- package/dist/lib/crabbox/cli.d.ts +2 -2
- package/dist/lib/crabbox/cli.js +3 -3
- package/dist/lib/daemon-health.d.ts +22 -0
- package/dist/lib/daemon-health.js +33 -3
- package/dist/lib/daemon-services.d.ts +50 -0
- package/dist/lib/daemon-services.js +147 -0
- package/dist/lib/daemon-ticks.d.ts +35 -66
- package/dist/lib/daemon-ticks.js +77 -159
- package/dist/lib/daemon.d.ts +72 -4
- package/dist/lib/daemon.js +792 -202
- package/dist/lib/deeplink/register.d.ts +49 -0
- package/dist/lib/deeplink/register.js +253 -0
- package/dist/lib/deeplink/url.d.ts +34 -0
- package/dist/lib/deeplink/url.js +78 -0
- package/dist/lib/device-config.d.ts +124 -29
- package/dist/lib/device-config.js +346 -141
- package/dist/lib/devices/config-migration.d.ts +42 -0
- package/dist/lib/devices/config-migration.js +203 -0
- package/dist/lib/devices/connect.js +14 -7
- package/dist/lib/devices/doctor-findings.d.ts +4 -1
- package/dist/lib/devices/doctor-findings.js +20 -1
- package/dist/lib/devices/harness-inventory.d.ts +11 -2
- package/dist/lib/devices/harness-inventory.js +0 -0
- package/dist/lib/devices/health.d.ts +1 -1
- package/dist/lib/devices/health.js +1 -1
- package/dist/lib/devices/pending.d.ts +22 -1
- package/dist/lib/devices/pending.js +67 -2
- package/dist/lib/devices/registry.d.ts +0 -25
- package/dist/lib/devices/registry.js +2 -83
- package/dist/lib/devices/resolve-profile.d.ts +20 -0
- package/dist/lib/devices/resolve-profile.js +44 -0
- package/dist/lib/devices/rollout-verify.d.ts +101 -0
- package/dist/lib/devices/rollout-verify.js +193 -0
- package/dist/lib/devices/ssh-config.js +10 -6
- package/dist/lib/event-families.d.ts +28 -0
- package/dist/lib/event-families.js +159 -0
- package/dist/lib/event-stream.d.ts +9 -1
- package/dist/lib/event-stream.js +26 -9
- package/dist/lib/events.d.ts +9 -1
- package/dist/lib/events.js +21 -6
- package/dist/lib/exec.d.ts +30 -0
- package/dist/lib/exec.js +220 -122
- package/dist/lib/feed-broadcast.d.ts +25 -0
- package/dist/lib/feed-broadcast.js +33 -0
- package/dist/lib/feed.d.ts +1 -1
- package/dist/lib/feed.js +12 -2
- package/dist/lib/fleet/capture.js +15 -0
- package/dist/lib/fleet/manifest.js +9 -0
- package/dist/lib/fleet/types.d.ts +9 -0
- package/dist/lib/fleet-status.js +10 -8
- package/dist/lib/git.d.ts +20 -6
- package/dist/lib/git.js +121 -17
- package/dist/lib/hosts/dispatch.d.ts +8 -3
- package/dist/lib/hosts/dispatch.js +29 -3
- package/dist/lib/hosts/logs.d.ts +2 -2
- package/dist/lib/hosts/logs.js +2 -2
- package/dist/lib/hosts/option.js +1 -1
- package/dist/lib/hosts/passthrough.d.ts +2 -3
- package/dist/lib/hosts/passthrough.js +10 -24
- package/dist/lib/hosts/progress.js +2 -2
- package/dist/lib/hosts/providers/devices.d.ts +3 -3
- package/dist/lib/hosts/providers/devices.js +18 -12
- package/dist/lib/hosts/ready.d.ts +5 -1
- package/dist/lib/hosts/ready.js +9 -3
- package/dist/lib/hosts/reconcile.d.ts +2 -2
- package/dist/lib/hosts/reconcile.js +2 -2
- package/dist/lib/hosts/registry.js +14 -9
- package/dist/lib/hosts/remote-cmd.js +1 -1
- package/dist/lib/hosts/remote-os.d.ts +9 -6
- package/dist/lib/hosts/remote-os.js +13 -6
- package/dist/lib/hosts/routing-flag.d.ts +23 -0
- package/dist/lib/hosts/routing-flag.js +41 -0
- package/dist/lib/hosts/run-target.js +1 -1
- package/dist/lib/hosts/session-index.js +1 -1
- package/dist/lib/hosts/tasks.d.ts +6 -6
- package/dist/lib/hosts/tasks.js +4 -4
- package/dist/lib/hosts/types.js +1 -2
- package/dist/lib/installations/resolve.js +2 -8
- package/dist/lib/isolation-boundary-report.js +0 -1
- package/dist/lib/linear-cache.d.ts +7 -0
- package/dist/lib/linear-cache.js +31 -4
- package/dist/lib/linear-project-counts.d.ts +1 -1
- package/dist/lib/linear-project-counts.js +2 -3
- package/dist/lib/linear-projects.js +1 -1
- package/dist/lib/loop.d.ts +2 -2
- package/dist/lib/loop.js +1 -1
- package/dist/lib/mailbox-target.d.ts +1 -1
- package/dist/lib/mailbox-target.js +1 -1
- package/dist/lib/manifest.js +7 -4
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/snapshot.d.ts +3 -2
- package/dist/lib/menubar/snapshot.js +6 -2
- package/dist/lib/migrate-fold.d.ts +33 -0
- package/dist/lib/migrate-fold.js +130 -0
- package/dist/lib/migrate.d.ts +34 -34
- package/dist/lib/migrate.js +106 -128
- package/dist/lib/model-tier-overrides.d.ts +1 -1
- package/dist/lib/model-tier-overrides.js +15 -2
- package/dist/lib/monitors/config.d.ts +17 -3
- package/dist/lib/monitors/config.js +52 -18
- package/dist/lib/monitors/engine.d.ts +32 -1
- package/dist/lib/monitors/engine.js +94 -11
- package/dist/lib/monitors/fingerprint.d.ts +46 -0
- package/dist/lib/monitors/fingerprint.js +100 -0
- package/dist/lib/monitors/remote.d.ts +47 -0
- package/dist/lib/monitors/remote.js +81 -0
- package/dist/lib/monitors/state.d.ts +39 -0
- package/dist/lib/monitors/state.js +56 -0
- package/dist/lib/onepassword.d.ts +17 -0
- package/dist/lib/onepassword.js +52 -22
- package/dist/lib/open-url.js +1 -1
- package/dist/lib/picker.d.ts +14 -2
- package/dist/lib/picker.js +35 -13
- package/dist/lib/placement.d.ts +1 -1
- package/dist/lib/placement.js +1 -1
- package/dist/lib/pr-land-detach.d.ts +32 -0
- package/dist/lib/pr-land-detach.js +79 -0
- package/dist/lib/profiles-presets.js +13 -0
- package/dist/lib/profiles.d.ts +2 -0
- package/dist/lib/profiles.js +44 -1
- package/dist/lib/project-focus.d.ts +1 -1
- package/dist/lib/project-focus.js +1 -1
- package/dist/lib/project-key.d.ts +17 -0
- package/dist/lib/project-key.js +26 -0
- package/dist/lib/project-probe.d.ts +4 -1
- package/dist/lib/project-probe.js +5 -4
- package/dist/lib/project-resources.js +2 -18
- package/dist/lib/project-root.d.ts +16 -0
- package/dist/lib/project-root.js +20 -2
- package/dist/lib/projects.d.ts +20 -1
- package/dist/lib/projects.js +78 -1
- package/dist/lib/refresh-coordinator.d.ts +24 -0
- package/dist/lib/refresh-coordinator.js +52 -0
- package/dist/lib/registry.d.ts +2 -2
- package/dist/lib/registry.js +1 -1
- package/dist/lib/resource-aliases.d.ts +13 -0
- package/dist/lib/resource-aliases.js +26 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.d.ts +16 -0
- package/dist/lib/resources.js +66 -10
- package/dist/lib/rotate.d.ts +3 -4
- package/dist/lib/rotate.js +4 -5
- package/dist/lib/routine-activation.d.ts +22 -2
- package/dist/lib/routine-activation.js +63 -16
- package/dist/lib/routine-context.d.ts +9 -2
- package/dist/lib/routine-context.js +21 -6
- package/dist/lib/routines-project.d.ts +58 -48
- package/dist/lib/routines-project.js +190 -159
- package/dist/lib/routines.d.ts +41 -6
- package/dist/lib/routines.js +92 -34
- package/dist/lib/run-defaults.d.ts +5 -0
- package/dist/lib/run-defaults.js +11 -1
- package/dist/lib/runner.d.ts +10 -8
- package/dist/lib/runner.js +122 -39
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/agent.d.ts +10 -3
- package/dist/lib/secrets/agent.js +43 -8
- package/dist/lib/secrets/bundles.d.ts +1 -0
- package/dist/lib/secrets/bundles.js +92 -80
- package/dist/lib/secrets/index.js +32 -9
- package/dist/lib/secrets/install-helper.d.ts +4 -4
- package/dist/lib/secrets/install-helper.js +4 -4
- package/dist/lib/secrets/push.d.ts +40 -6
- package/dist/lib/secrets/push.js +58 -11
- package/dist/lib/secrets/read-backoff.d.ts +1 -1
- package/dist/lib/secrets/read-backoff.js +1 -1
- package/dist/lib/secrets/remote.d.ts +24 -0
- package/dist/lib/secrets/remote.js +54 -4
- package/dist/lib/self-update.d.ts +108 -0
- package/dist/lib/self-update.js +276 -1
- package/dist/lib/session/active.d.ts +89 -5
- package/dist/lib/session/active.js +165 -10
- package/dist/lib/session/actor-sidecar.d.ts +1 -1
- package/dist/lib/session/actor-sidecar.js +2 -1
- package/dist/lib/session/db.d.ts +176 -2
- package/dist/lib/session/db.js +484 -17
- package/dist/lib/session/discover.js +27 -4
- package/dist/lib/session/hook-sessions.js +2 -2
- package/dist/lib/session/host-link.d.ts +2 -2
- package/dist/lib/session/host-link.js +2 -2
- package/dist/lib/session/pid-registry.d.ts +21 -0
- package/dist/lib/session/pid-registry.js +57 -0
- package/dist/lib/session/remote-active.js +15 -1
- package/dist/lib/session/remote.js +2 -2
- package/dist/lib/session/session-cache.d.ts +14 -7
- package/dist/lib/session/session-cache.js +51 -9
- package/dist/lib/session/state.d.ts +2 -2
- package/dist/lib/session/state.js +1 -1
- package/dist/lib/session/sync/config.d.ts +10 -10
- package/dist/lib/session/sync/config.js +10 -10
- package/dist/lib/session/sync/r2.d.ts +34 -0
- package/dist/lib/session/sync/r2.js +123 -0
- package/dist/lib/session/throughput.d.ts +1 -1
- package/dist/lib/session/throughput.js +1 -1
- package/dist/lib/session/types.d.ts +23 -1
- package/dist/lib/session/types.js +15 -0
- package/dist/lib/session/viewing-in.d.ts +1 -1
- package/dist/lib/session/viewing-in.js +1 -1
- package/dist/lib/session/watch.d.ts +101 -0
- package/dist/lib/session/watch.js +242 -0
- package/dist/lib/share/config.d.ts +4 -0
- package/dist/lib/share/config.js +1 -0
- package/dist/lib/share/delete.d.ts +93 -0
- package/dist/lib/share/delete.js +127 -0
- package/dist/lib/share/provision.d.ts +38 -0
- package/dist/lib/share/provision.js +50 -0
- package/dist/lib/share/publish.d.ts +40 -1
- package/dist/lib/share/publish.js +116 -3
- package/dist/lib/share/worker-template.js +71 -6
- package/dist/lib/shims.d.ts +17 -3
- package/dist/lib/shims.js +136 -27
- package/dist/lib/signin-badge.js +3 -2
- package/dist/lib/skills.js +2 -0
- package/dist/lib/smart-launch.d.ts +8 -8
- package/dist/lib/smart-launch.js +80 -59
- package/dist/lib/ssh-exec.d.ts +1 -1
- package/dist/lib/ssh-exec.js +1 -1
- package/dist/lib/staleness/prune.d.ts +88 -0
- package/dist/lib/staleness/prune.js +69 -0
- package/dist/lib/staleness/registry.d.ts +1 -1
- package/dist/lib/staleness/writers/commands.js +34 -2
- package/dist/lib/staleness/writers/hooks.js +16 -0
- package/dist/lib/staleness/writers/kinds.d.ts +6 -0
- package/dist/lib/staleness/writers/skills.js +19 -0
- package/dist/lib/staleness/writers/subagents.d.ts +2 -3
- package/dist/lib/staleness/writers/subagents.js +0 -4
- package/dist/lib/staleness/writers/types.d.ts +32 -0
- package/dist/lib/startup/command-registry.d.ts +6 -12
- package/dist/lib/startup/command-registry.js +14 -31
- package/dist/lib/startup/dev-build.d.ts +10 -0
- package/dist/lib/startup/dev-build.js +13 -1
- package/dist/lib/startup/spellcheck.d.ts +18 -0
- package/dist/lib/startup/spellcheck.js +45 -0
- package/dist/lib/state.d.ts +36 -9
- package/dist/lib/state.js +96 -46
- package/dist/lib/subagents-registry.d.ts +0 -7
- package/dist/lib/subagents-registry.js +38 -65
- package/dist/lib/subagents.d.ts +0 -33
- package/dist/lib/subagents.js +0 -75
- package/dist/lib/sync-umbrella.js +1 -1
- package/dist/lib/teams/agents.d.ts +41 -1
- package/dist/lib/teams/agents.js +187 -9
- package/dist/lib/teams/api.d.ts +11 -1
- package/dist/lib/teams/api.js +11 -2
- package/dist/lib/teams/delivery.d.ts +41 -0
- package/dist/lib/teams/delivery.js +60 -0
- package/dist/lib/teams/registry.d.ts +14 -0
- package/dist/lib/teams/registry.js +51 -1
- package/dist/lib/teams/remoteWorktree.d.ts +19 -0
- package/dist/lib/teams/remoteWorktree.js +29 -0
- package/dist/lib/teams/scheduler.d.ts +1 -1
- package/dist/lib/teams/scheduler.js +1 -1
- package/dist/lib/teams/worktree.d.ts +24 -0
- package/dist/lib/teams/worktree.js +42 -0
- package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
- package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
- package/dist/lib/terminal/engine.d.ts +4 -0
- package/dist/lib/terminal/engine.js +8 -2
- package/dist/lib/terminal/types.d.ts +21 -2
- package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
- package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
- package/dist/lib/tickets/list.d.ts +53 -0
- package/dist/lib/tickets/list.js +153 -0
- package/dist/lib/tmux/orphan-reap.d.ts +320 -0
- package/dist/lib/tmux/orphan-reap.js +644 -0
- package/dist/lib/tmux/session.d.ts +68 -3
- package/dist/lib/tmux/session.js +95 -5
- package/dist/lib/triggers/handlers.d.ts +20 -0
- package/dist/lib/triggers/handlers.js +6 -1
- package/dist/lib/types.d.ts +46 -34
- package/dist/lib/usage-fleet.d.ts +32 -0
- package/dist/lib/usage-fleet.js +125 -0
- package/dist/lib/usage-refresh.d.ts +3 -3
- package/dist/lib/usage-refresh.js +19 -16
- package/dist/lib/usage.d.ts +51 -47
- package/dist/lib/usage.js +145 -153
- package/dist/lib/version-duplicates.js +2 -2
- package/dist/lib/versions.d.ts +56 -13
- package/dist/lib/versions.js +195 -45
- package/dist/lib/watchdog/log.d.ts +1 -1
- package/dist/lib/watchdog/log.js +3 -3
- package/dist/lib/watchdog/rotate.d.ts +6 -6
- package/dist/lib/watchdog/rotate.js +6 -6
- package/dist/lib/workflows.d.ts +1 -1
- package/dist/lib/yaml-io.d.ts +47 -0
- package/dist/lib/yaml-io.js +55 -0
- package/package.json +2 -1
- package/scripts/install-helper.js +2 -2
- package/scripts/postinstall.js +23 -20
- package/dist/commands/defaults.d.ts +0 -7
- package/dist/commands/defaults.js +0 -107
- package/dist/commands/export.d.ts +0 -11
- package/dist/commands/export.js +0 -215
- package/dist/commands/helper.d.ts +0 -12
- package/dist/commands/helper.js +0 -87
- package/dist/commands/hosts.d.ts +0 -11
- package/dist/commands/hosts.js +0 -330
- package/dist/commands/lock.d.ts +0 -12
- package/dist/commands/lock.js +0 -70
- package/dist/commands/pull.d.ts +0 -17
- package/dist/commands/pull.js +0 -39
- package/dist/commands/push.d.ts +0 -14
- package/dist/commands/push.js +0 -30
- package/dist/commands/wallet.d.ts +0 -20
- package/dist/commands/wallet.js +0 -216
- package/dist/commands/worktree.d.ts +0 -19
- package/dist/commands/worktree.js +0 -272
- package/dist/lib/account-labels.d.ts +0 -24
- package/dist/lib/account-labels.js +0 -72
- package/dist/lib/auto-dispatch-linear.d.ts +0 -18
- package/dist/lib/auto-dispatch-linear.js +0 -107
- package/dist/lib/auto-dispatch-provider.d.ts +0 -10
- package/dist/lib/auto-dispatch-provider.js +0 -30
- package/dist/lib/auto-dispatch.d.ts +0 -93
- package/dist/lib/auto-dispatch.js +0 -128
- package/dist/lib/export.d.ts +0 -72
- package/dist/lib/export.js +0 -269
- package/dist/lib/lock.d.ts +0 -93
- package/dist/lib/lock.js +0 -207
- package/dist/lib/wallet/index.d.ts +0 -78
- package/dist/lib/wallet/index.js +0 -253
package/dist/lib/browser/ipc.js
CHANGED
|
@@ -6,6 +6,23 @@ import { getHelpersDir } from '../state.js';
|
|
|
6
6
|
import { startDaemon, stopDaemon } from '../daemon.js';
|
|
7
7
|
import { getCliVersion } from '../version.js';
|
|
8
8
|
const SOCKET_NAME = 'browser.sock';
|
|
9
|
+
/**
|
|
10
|
+
* Backstop for {@link BrowserIPCServer.stop} — how long to wait for the socket
|
|
11
|
+
* to be released before unlinking it anyway (RUSH-2421).
|
|
12
|
+
*
|
|
13
|
+
* This MUST stay well under the daemon's SIGTERM grace window
|
|
14
|
+
* (`STOP_GRACE_MS`, daemon.ts). `handleShutdown` awaits `stop()`, so a close
|
|
15
|
+
* that takes as long as the grace window means `stopDaemon` gives up waiting
|
|
16
|
+
* and escalates to `killTree` — turning every graceful stop into a kill. The
|
|
17
|
+
* first version of this constant was set to exactly 5000, the same value as
|
|
18
|
+
* `STOP_GRACE_MS`, and did precisely that whenever a browser client held its
|
|
19
|
+
* (deliberately) long-lived connection open.
|
|
20
|
+
*
|
|
21
|
+
* With connections now ended explicitly in `closeServer`, reaching this
|
|
22
|
+
* timeout at all means a socket refused to die; 1.5s bounds that without
|
|
23
|
+
* coming near the grace window.
|
|
24
|
+
*/
|
|
25
|
+
const IPC_CLOSE_TIMEOUT_MS = 1_500;
|
|
9
26
|
export class BrowserDaemonNotRunningError extends Error {
|
|
10
27
|
constructor() {
|
|
11
28
|
super(formatBrowserDaemonNotRunningError());
|
|
@@ -153,6 +170,10 @@ export class BrowserIPCConnection {
|
|
|
153
170
|
export class BrowserIPCServer {
|
|
154
171
|
server = null;
|
|
155
172
|
service;
|
|
173
|
+
/** Live client connections, so {@link stop} can end them rather than wait. */
|
|
174
|
+
connections = new Set();
|
|
175
|
+
/** In-flight stop, so a second SIGTERM awaits the same close, never skips it. */
|
|
176
|
+
stopping = null;
|
|
156
177
|
constructor(service) {
|
|
157
178
|
this.service = service;
|
|
158
179
|
}
|
|
@@ -170,6 +191,12 @@ export class BrowserIPCServer {
|
|
|
170
191
|
}
|
|
171
192
|
}
|
|
172
193
|
this.server = net.createServer((socket) => {
|
|
194
|
+
// `net.Server.close()` stops accepting but does not complete until every
|
|
195
|
+
// EXISTING connection ends, and clients here hold one open on purpose
|
|
196
|
+
// ("the process and socket stay warm between actions"). Tracking them is
|
|
197
|
+
// what lets stop() end them deliberately instead of waiting out a timeout.
|
|
198
|
+
this.connections.add(socket);
|
|
199
|
+
socket.on('close', () => this.connections.delete(socket));
|
|
173
200
|
let buffer = '';
|
|
174
201
|
socket.on('data', async (data) => {
|
|
175
202
|
buffer += data.toString();
|
|
@@ -229,11 +256,38 @@ export class BrowserIPCServer {
|
|
|
229
256
|
});
|
|
230
257
|
});
|
|
231
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Stop accepting, release the binding, and only then resolve.
|
|
261
|
+
*
|
|
262
|
+
* RUSH-2421: this used to call `server.close()` and move on. `close()` is
|
|
263
|
+
* asynchronous — it stops accepting immediately but the binding is not
|
|
264
|
+
* actually released until the `'close'` event fires — so `stop()` resolved
|
|
265
|
+
* while the socket (or named pipe) was still held. The daemon's
|
|
266
|
+
* `handleShutdown` awaits this before it exits, and a successor's
|
|
267
|
+
* `claimDaemonInstance` waits for that exit as its proof the predecessor's
|
|
268
|
+
* resources are free (SING-11). Resolving early made that proof false: the
|
|
269
|
+
* newcomer could bind before the incumbent's binding was gone, which is the
|
|
270
|
+
* two-servers-on-one-socket orphan the eviction protocol exists to prevent.
|
|
271
|
+
*
|
|
272
|
+
* The first version of this waited out a timeout instead, and that made every
|
|
273
|
+
* graceful daemon stop escalate to `killTree`: `close()` does not complete
|
|
274
|
+
* while a connection is open, browser clients hold one open on purpose, and
|
|
275
|
+
* the timeout was set equal to the daemon's own SIGTERM grace window
|
|
276
|
+
* (`STOP_GRACE_MS`) — so `handleShutdown` was still inside `stop()` when
|
|
277
|
+
* `stopDaemon` gave up waiting and killed it. So we END the connections
|
|
278
|
+
* rather than wait for them: `close()` stops accepting, destroying the
|
|
279
|
+
* tracked sockets lets it complete, and the timeout is only a backstop for a
|
|
280
|
+
* socket that will not die, deliberately far below `STOP_GRACE_MS`.
|
|
281
|
+
*/
|
|
232
282
|
async stop() {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
283
|
+
// A second SIGTERM must await the SAME stop, not skip past it because
|
|
284
|
+
// `this.server` was already nulled by the first.
|
|
285
|
+
if (!this.stopping)
|
|
286
|
+
this.stopping = this.doStop();
|
|
287
|
+
return this.stopping;
|
|
288
|
+
}
|
|
289
|
+
async doStop() {
|
|
290
|
+
await this.closeServer();
|
|
237
291
|
if (!IS_WINDOWS) {
|
|
238
292
|
const socketPath = getSocketPath();
|
|
239
293
|
if (fs.existsSync(socketPath)) {
|
|
@@ -242,6 +296,28 @@ export class BrowserIPCServer {
|
|
|
242
296
|
}
|
|
243
297
|
await this.service.shutdown();
|
|
244
298
|
}
|
|
299
|
+
/** Release the listening binding, resolving only once it is genuinely gone. */
|
|
300
|
+
closeServer() {
|
|
301
|
+
const server = this.server;
|
|
302
|
+
this.server = null;
|
|
303
|
+
if (!server)
|
|
304
|
+
return Promise.resolve();
|
|
305
|
+
return new Promise((resolve) => {
|
|
306
|
+
const done = () => { clearTimeout(timer); resolve(); };
|
|
307
|
+
// Backstop only, for a socket that refuses to die. Far below the daemon's
|
|
308
|
+
// SIGTERM grace window so a slow close can never be what gets the daemon
|
|
309
|
+
// killed — the whole point is that the graceful path stays graceful.
|
|
310
|
+
const timer = setTimeout(done, IPC_CLOSE_TIMEOUT_MS);
|
|
311
|
+
// `close()` reports an error when the server was never listening —
|
|
312
|
+
// nothing to release, so that is a completed close, not a failure.
|
|
313
|
+
server.close(() => done());
|
|
314
|
+
// `close()` waits for existing connections; ending them is what lets it
|
|
315
|
+
// finish now instead of at the timeout.
|
|
316
|
+
for (const socket of this.connections)
|
|
317
|
+
socket.destroy();
|
|
318
|
+
this.connections.clear();
|
|
319
|
+
});
|
|
320
|
+
}
|
|
245
321
|
async handleRequest(request) {
|
|
246
322
|
if (request.action === 'upload-stage') {
|
|
247
323
|
const source = request.source;
|
|
@@ -266,6 +342,7 @@ export class BrowserIPCServer {
|
|
|
266
342
|
skipDomainSkill: request.skipDomainSkill,
|
|
267
343
|
actor: request.actor,
|
|
268
344
|
launchId: request.launchId,
|
|
345
|
+
sessionId: request.sessionId,
|
|
269
346
|
});
|
|
270
347
|
return {
|
|
271
348
|
ok: true,
|
|
@@ -5,8 +5,9 @@ export declare const DEFAULT_BROWSER_PROFILE_NAME = "default";
|
|
|
5
5
|
* The device-local configured default profile name (set via
|
|
6
6
|
* `agents browser profiles set-default`), or undefined when unset. When set, it
|
|
7
7
|
* is the profile `agents browser start` resolves to for BOTH the no-`--profile`
|
|
8
|
-
* path and an explicit `--profile default`. Stored
|
|
9
|
-
* `
|
|
8
|
+
* path and an explicit `--profile default`. Stored as this machine's
|
|
9
|
+
* `browser.profile` device-config key (central `fleet.devices.<name>.config`
|
|
10
|
+
* block — see lib/device-config.ts).
|
|
10
11
|
*/
|
|
11
12
|
export declare function getConfiguredDefaultProfileName(): string | undefined;
|
|
12
13
|
export declare function getBrowserRuntimeDir(): string;
|
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
-
import { getBrowserRuntimeDir as getBrowserRuntimeDirRoot, readMeta,
|
|
2
|
+
import { getBrowserRuntimeDir as getBrowserRuntimeDirRoot, readMeta, updateMeta, } from '../state.js';
|
|
3
|
+
import { getConfigValue } from '../device-config.js';
|
|
3
4
|
import { findBrowserPath, findFirstInstalledBrowser, isPortInUse } from './chrome.js';
|
|
4
5
|
import { DEFAULT_VIEWPORT } from './devices.js';
|
|
5
6
|
export const DEFAULT_BROWSER_PROFILE_NAME = 'default';
|
|
7
|
+
/**
|
|
8
|
+
* True for a profile whose contents only make sense on THIS machine, so it must
|
|
9
|
+
* live in the per-machine doc rather than the fleet-synced agents.yaml.
|
|
10
|
+
*
|
|
11
|
+
* Only the auto-detected `default` qualifies: it is generated by probing local
|
|
12
|
+
* browser installs and a free local port, so its `binary:` is an absolute path
|
|
13
|
+
* for one OS. Shared fleet-wide it caused a permanent rewrite loop — a macOS box
|
|
14
|
+
* wrote `/Applications/...`, a Linux box rewrote `/usr/bin/chromium-browser`,
|
|
15
|
+
* each on every `agents browser start`. Named profiles a user created are real
|
|
16
|
+
* fleet config and keep syncing.
|
|
17
|
+
*/
|
|
18
|
+
function isMachineLocalProfile(name) {
|
|
19
|
+
return name === DEFAULT_BROWSER_PROFILE_NAME;
|
|
20
|
+
}
|
|
6
21
|
/**
|
|
7
22
|
* The device-local configured default profile name (set via
|
|
8
23
|
* `agents browser profiles set-default`), or undefined when unset. When set, it
|
|
9
24
|
* is the profile `agents browser start` resolves to for BOTH the no-`--profile`
|
|
10
|
-
* path and an explicit `--profile default`. Stored
|
|
11
|
-
* `
|
|
25
|
+
* path and an explicit `--profile default`. Stored as this machine's
|
|
26
|
+
* `browser.profile` device-config key (central `fleet.devices.<name>.config`
|
|
27
|
+
* block — see lib/device-config.ts).
|
|
12
28
|
*/
|
|
13
29
|
export function getConfiguredDefaultProfileName() {
|
|
14
|
-
return
|
|
30
|
+
return getConfigValue('browser.profile').value || undefined;
|
|
15
31
|
}
|
|
16
32
|
export function getBrowserRuntimeDir() {
|
|
17
33
|
return getBrowserRuntimeDirRoot();
|
|
@@ -82,15 +98,22 @@ function profileToConfig(profile) {
|
|
|
82
98
|
config.logHost = profile.logHost;
|
|
83
99
|
return config;
|
|
84
100
|
}
|
|
85
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Every profile visible on this machine: the fleet-shared ones plus this
|
|
103
|
+
* machine's own. A machine-local entry WINS on a name collision — it was written
|
|
104
|
+
* by this box for this box, whereas the shared copy may carry another OS's
|
|
105
|
+
* binary path (that mismatch is exactly why `default` moved local).
|
|
106
|
+
*/
|
|
107
|
+
function allProfileConfigs() {
|
|
86
108
|
const meta = readMeta();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
109
|
+
return { ...meta.browser, ...meta.deviceBrowser };
|
|
110
|
+
}
|
|
111
|
+
export async function listProfiles() {
|
|
112
|
+
const configs = allProfileConfigs();
|
|
113
|
+
return Object.entries(configs).map(([name, config]) => configToProfile(name, config));
|
|
90
114
|
}
|
|
91
115
|
export async function getProfile(name) {
|
|
92
|
-
const
|
|
93
|
-
const config = meta.browser?.[name];
|
|
116
|
+
const config = allProfileConfigs()[name];
|
|
94
117
|
if (!config)
|
|
95
118
|
return null;
|
|
96
119
|
return configToProfile(name, config);
|
|
@@ -271,7 +294,8 @@ function hasSshEndpoint(endpoints) {
|
|
|
271
294
|
}
|
|
272
295
|
export async function createProfile(profile) {
|
|
273
296
|
const meta = readMeta();
|
|
274
|
-
|
|
297
|
+
const existingConfigs = allProfileConfigs();
|
|
298
|
+
if (existingConfigs[profile.name]) {
|
|
275
299
|
throw new Error(`Profile "${profile.name}" already exists`);
|
|
276
300
|
}
|
|
277
301
|
// Collision check. Every CDP/SSH profile ends up listening on (or
|
|
@@ -280,8 +304,8 @@ export async function createProfile(profile) {
|
|
|
280
304
|
// longer need to scope by host. Two profiles that would need the same
|
|
281
305
|
// local port can't both run at the same time.
|
|
282
306
|
const newLocal = effectiveLocalPort(profile);
|
|
283
|
-
if (newLocal !== undefined
|
|
284
|
-
for (const [existingName, existingConfig] of Object.entries(
|
|
307
|
+
if (newLocal !== undefined) {
|
|
308
|
+
for (const [existingName, existingConfig] of Object.entries(existingConfigs)) {
|
|
285
309
|
const existingProfile = configToProfile(existingName, existingConfig);
|
|
286
310
|
const existingLocal = effectiveLocalPort(existingProfile);
|
|
287
311
|
if (existingLocal === newLocal) {
|
|
@@ -302,25 +326,44 @@ export async function createProfile(profile) {
|
|
|
302
326
|
if (!hasSshEndpoint(profile.endpoints)) {
|
|
303
327
|
findBrowserPath(profile.browser, profile.binary);
|
|
304
328
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
329
|
+
const config = profileToConfig(profile);
|
|
330
|
+
if (isMachineLocalProfile(profile.name)) {
|
|
331
|
+
updateMeta((m) => ({ ...m, deviceBrowser: { ...m.deviceBrowser, [profile.name]: config } }));
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
updateMeta((m) => ({ ...m, browser: { ...m.browser, [profile.name]: config } }));
|
|
308
335
|
}
|
|
309
336
|
export async function updateProfile(profile) {
|
|
310
337
|
const meta = readMeta();
|
|
311
|
-
|
|
338
|
+
const local = meta.deviceBrowser?.[profile.name];
|
|
339
|
+
if (!local && !meta.browser?.[profile.name]) {
|
|
312
340
|
throw new Error(`Profile "${profile.name}" does not exist`);
|
|
313
341
|
}
|
|
314
|
-
|
|
315
|
-
|
|
342
|
+
const config = profileToConfig(profile);
|
|
343
|
+
// A profile that already lives machine-locally stays there; so does the auto
|
|
344
|
+
// `default`, whose binary path and port are specific to this machine.
|
|
345
|
+
if (local || isMachineLocalProfile(profile.name)) {
|
|
346
|
+
updateMeta((m) => ({ ...m, deviceBrowser: { ...m.deviceBrowser, [profile.name]: config } }));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
updateMeta((m) => ({ ...m, browser: { ...m.browser, [profile.name]: config } }));
|
|
316
350
|
}
|
|
317
351
|
export async function deleteProfile(name) {
|
|
318
352
|
const meta = readMeta();
|
|
319
|
-
|
|
353
|
+
const isLocal = !!meta.deviceBrowser?.[name];
|
|
354
|
+
if (!isLocal && !meta.browser?.[name]) {
|
|
320
355
|
throw new Error(`Profile "${name}" does not exist`);
|
|
321
356
|
}
|
|
322
|
-
|
|
323
|
-
|
|
357
|
+
updateMeta((m) => {
|
|
358
|
+
if (isLocal) {
|
|
359
|
+
const next = { ...m.deviceBrowser };
|
|
360
|
+
delete next[name];
|
|
361
|
+
return { ...m, deviceBrowser: Object.keys(next).length > 0 ? next : undefined };
|
|
362
|
+
}
|
|
363
|
+
const next = { ...m.browser };
|
|
364
|
+
delete next[name];
|
|
365
|
+
return { ...m, browser: Object.keys(next).length > 0 ? next : undefined };
|
|
366
|
+
});
|
|
324
367
|
}
|
|
325
368
|
/**
|
|
326
369
|
* Resolve a profile's endpoint presets into a normalized map regardless of
|
|
@@ -62,9 +62,11 @@ export interface HealInfo {
|
|
|
62
62
|
export declare function resolveTaskIdentity(forwarded: {
|
|
63
63
|
actor?: string;
|
|
64
64
|
launchId?: string;
|
|
65
|
+
sessionId?: string;
|
|
65
66
|
}, resolveLocalActor: () => string): {
|
|
66
67
|
owner: string;
|
|
67
68
|
launchId?: string;
|
|
69
|
+
sessionId?: string;
|
|
68
70
|
};
|
|
69
71
|
export declare class BrowserService {
|
|
70
72
|
private static readonly SOURCE_PREFIX;
|
|
@@ -83,6 +85,8 @@ export declare class BrowserService {
|
|
|
83
85
|
/** Caller identity, forwarded from the CLI (see IPCRequest.actor/launchId). */
|
|
84
86
|
actor?: string;
|
|
85
87
|
launchId?: string;
|
|
88
|
+
/** Calling agent session, forwarded from the CLI (see IPCRequest.sessionId). */
|
|
89
|
+
sessionId?: string;
|
|
86
90
|
}): Promise<{
|
|
87
91
|
task: string;
|
|
88
92
|
name: string;
|
|
@@ -15,6 +15,7 @@ import { typeEditorText } from './editor.js';
|
|
|
15
15
|
import { detectUploadPattern, stageUploadFile, uploadToDropTarget, uploadToFileInput, uploadViaFileChooser, } from './upload.js';
|
|
16
16
|
import { emit } from '../events.js';
|
|
17
17
|
import { resolveActor } from '../actor.js';
|
|
18
|
+
import { recordBrowserSession } from '../session/db.js';
|
|
18
19
|
import { sshExecAsync } from '../ssh-exec.js';
|
|
19
20
|
function isPathInside(candidate, dir) {
|
|
20
21
|
const rel = path.relative(dir, candidate);
|
|
@@ -235,6 +236,7 @@ export function resolveTaskIdentity(forwarded, resolveLocalActor) {
|
|
|
235
236
|
return {
|
|
236
237
|
owner: forwarded.actor ?? resolveLocalActor(),
|
|
237
238
|
launchId: forwarded.launchId,
|
|
239
|
+
sessionId: forwarded.sessionId,
|
|
238
240
|
};
|
|
239
241
|
}
|
|
240
242
|
export class BrowserService {
|
|
@@ -348,9 +350,10 @@ export class BrowserService {
|
|
|
348
350
|
createdAt: Date.now(),
|
|
349
351
|
pid: conn.pid,
|
|
350
352
|
// Identity is forwarded from the caller (see resolveTaskIdentity): WHO
|
|
351
|
-
// (owner)
|
|
352
|
-
// every task to the shared daemon's
|
|
353
|
-
|
|
353
|
+
// (owner), WHICH run (launchId), and WHICH agent session (sessionId).
|
|
354
|
+
// Resolving daemon-side would attribute every task to the shared daemon's
|
|
355
|
+
// actor (the RUSH-2020 bug).
|
|
356
|
+
...resolveTaskIdentity({ actor: opts.actor, launchId: opts.launchId, sessionId: opts.sessionId }, () => resolveActor().id),
|
|
354
357
|
};
|
|
355
358
|
// For Electron, get the existing window as the tab
|
|
356
359
|
if (conn.electron) {
|
|
@@ -363,6 +366,30 @@ export class BrowserService {
|
|
|
363
366
|
}
|
|
364
367
|
conn.tasks.set(taskName, task);
|
|
365
368
|
await this.saveTaskState(effectiveProfileName, conn.tasks);
|
|
369
|
+
// Durable identity, written ONCE at start and never deleted (RUSH-2549).
|
|
370
|
+
// tasks.json above stays live state: `stop` drops the task from that map, so
|
|
371
|
+
// anything recorded only there is gone the moment the task ends -- which is
|
|
372
|
+
// why every finished task used to list as "unlinked". This row outlives the
|
|
373
|
+
// task, the daemon, and a reboot. Metadata only: the capture bytes stay on
|
|
374
|
+
// disk under capture_dir.
|
|
375
|
+
// Guarded like `emit` below ("logging should never break the CLI",
|
|
376
|
+
// events.ts): the browser task is already started and registered. An
|
|
377
|
+
// unwritable session DB must not turn a working `agents browser start` into
|
|
378
|
+
// a failure -- the cost of a miss is one unlinked row, not a dead browser.
|
|
379
|
+
try {
|
|
380
|
+
recordBrowserSession({
|
|
381
|
+
task: taskName,
|
|
382
|
+
profile: effectiveProfileName,
|
|
383
|
+
sessionId: task.sessionId,
|
|
384
|
+
launchId: task.launchId,
|
|
385
|
+
actor: task.owner,
|
|
386
|
+
startedAt: task.createdAt,
|
|
387
|
+
captureDir: getProfileSessionsDir(effectiveProfileName, taskName),
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
catch {
|
|
391
|
+
// Recording is best-effort; the task itself is live either way.
|
|
392
|
+
}
|
|
366
393
|
emit('browser.launch', { profile: effectiveProfileName, task: taskName, pid: conn.pid });
|
|
367
394
|
void import('../analytics/usage-db.js').then(({ recordUsage }) => {
|
|
368
395
|
recordUsage({
|
|
@@ -33,10 +33,17 @@ export declare function renderBrowserSessions(groups: ProfileArtifacts[]): strin
|
|
|
33
33
|
export declare function resolveArtifact(groups: ProfileArtifacts[], selector: string): string | null;
|
|
34
34
|
/** Open a file in the OS default app. Returns true on success. */
|
|
35
35
|
export declare function openArtifact(filePath: string): boolean;
|
|
36
|
-
/** The identity fields this module cares about
|
|
36
|
+
/** The identity fields this module cares about for one task. */
|
|
37
37
|
export interface TaskIdentity {
|
|
38
38
|
owner?: string;
|
|
39
39
|
launchId?: string;
|
|
40
|
+
/**
|
|
41
|
+
* The agent session that drove the task. Primary identity: it is carried by
|
|
42
|
+
* every agent process, whereas a launch id is present on a minority of them.
|
|
43
|
+
* Sourced from the durable `browser_sessions` row, which survives task stop —
|
|
44
|
+
* `tasks.json` never records it beyond the task's own lifetime (RUSH-2549).
|
|
45
|
+
*/
|
|
46
|
+
sessionId?: string;
|
|
40
47
|
}
|
|
41
48
|
/**
|
|
42
49
|
* Read a profile's `tasks.json` for the identity of its CURRENTLY LIVE tasks,
|
|
@@ -48,6 +55,17 @@ export interface TaskIdentity {
|
|
|
48
55
|
* browser daemon is running.
|
|
49
56
|
*/
|
|
50
57
|
export declare function loadTaskIdentities(profile: string): Map<string, TaskIdentity>;
|
|
58
|
+
/**
|
|
59
|
+
* Identity for one profile's tasks, durable copy first.
|
|
60
|
+
*
|
|
61
|
+
* `browser_sessions` is the source of truth: it is written at task start and
|
|
62
|
+
* never deleted, so it answers for tasks that have already stopped — the case
|
|
63
|
+
* `tasks.json` structurally cannot, since `saveTaskState` rewrites that file
|
|
64
|
+
* from the LIVE task map. The live file is still merged on top for a task that
|
|
65
|
+
* is running right now, so a task started by an older CLI (no DB row yet) keeps
|
|
66
|
+
* whatever identity it does have rather than regressing to nothing.
|
|
67
|
+
*/
|
|
68
|
+
export declare function loadDurableTaskIdentities(profile: string): Map<string, TaskIdentity>;
|
|
51
69
|
/** launchId -> indexed session id, built once from every source that records
|
|
52
70
|
* this join, so a task-heavy profile resolves without re-scanning per task. */
|
|
53
71
|
export interface LaunchSessionIndex {
|
|
@@ -85,6 +103,8 @@ export interface BrowserSessionRow {
|
|
|
85
103
|
task?: string;
|
|
86
104
|
owner?: string;
|
|
87
105
|
launchId?: string;
|
|
106
|
+
/** The agent session that drove the task, when one was recorded. */
|
|
107
|
+
sessionId?: string;
|
|
88
108
|
linkStatus: BrowserSessionLinkStatus;
|
|
89
109
|
linkedSession?: SessionMeta;
|
|
90
110
|
/** Newest first. */
|
|
@@ -99,7 +119,7 @@ export interface BrowserSessionRow {
|
|
|
99
119
|
* or session-index dependency and is unit-testable with synthetic data (see
|
|
100
120
|
* {@link buildBrowserSessionRows} for the impure disk/index-reading caller).
|
|
101
121
|
*/
|
|
102
|
-
export declare function groupIntoRows(groups: ProfileArtifacts[], taskIdentities: Map<string, Map<string, TaskIdentity>>, resolveLaunch?: (launchId: string) => SessionMeta | null): BrowserSessionRow[];
|
|
122
|
+
export declare function groupIntoRows(groups: ProfileArtifacts[], taskIdentities: Map<string, Map<string, TaskIdentity>>, resolveLaunch?: (launchId: string) => SessionMeta | null, resolveSession?: (sessionId: string) => SessionMeta | null): BrowserSessionRow[];
|
|
103
123
|
/** Build task-first rows for one profile (or every profile with captures),
|
|
104
124
|
* reading `tasks.json` and resolving launchIds against the live indexes.
|
|
105
125
|
* The interactive picker's data source. */
|
|
@@ -19,7 +19,7 @@ import * as path from 'path';
|
|
|
19
19
|
import { spawnSync } from 'child_process';
|
|
20
20
|
import { getBrowserRuntimeDir, getProfileRuntimeDir } from './profiles.js';
|
|
21
21
|
import { formatRelativeTime } from '../session/relative-time.js';
|
|
22
|
-
import { getSessionById } from '../session/db.js';
|
|
22
|
+
import { getSessionById, listBrowserSessionRecords, pruneToolSessions } from '../session/db.js';
|
|
23
23
|
import { listPidSessionEntries } from '../session/pid-registry.js';
|
|
24
24
|
import { loadHookSessionIndex } from '../session/hook-sessions.js';
|
|
25
25
|
import { readRecentActivity } from '../activity.js';
|
|
@@ -214,10 +214,40 @@ export function loadTaskIdentities(profile) {
|
|
|
214
214
|
out.set(name, {
|
|
215
215
|
owner: typeof t.owner === 'string' ? t.owner : undefined,
|
|
216
216
|
launchId: typeof t.launchId === 'string' ? t.launchId : undefined,
|
|
217
|
+
sessionId: typeof t.sessionId === 'string' ? t.sessionId : undefined,
|
|
217
218
|
});
|
|
218
219
|
}
|
|
219
220
|
return out;
|
|
220
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Identity for one profile's tasks, durable copy first.
|
|
224
|
+
*
|
|
225
|
+
* `browser_sessions` is the source of truth: it is written at task start and
|
|
226
|
+
* never deleted, so it answers for tasks that have already stopped — the case
|
|
227
|
+
* `tasks.json` structurally cannot, since `saveTaskState` rewrites that file
|
|
228
|
+
* from the LIVE task map. The live file is still merged on top for a task that
|
|
229
|
+
* is running right now, so a task started by an older CLI (no DB row yet) keeps
|
|
230
|
+
* whatever identity it does have rather than regressing to nothing.
|
|
231
|
+
*/
|
|
232
|
+
export function loadDurableTaskIdentities(profile) {
|
|
233
|
+
const merged = new Map();
|
|
234
|
+
for (const record of listBrowserSessionRecords(profile)) {
|
|
235
|
+
merged.set(record.task, {
|
|
236
|
+
owner: record.actor,
|
|
237
|
+
launchId: record.launchId,
|
|
238
|
+
sessionId: record.sessionId,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
for (const [task, live] of loadTaskIdentities(profile)) {
|
|
242
|
+
const durable = merged.get(task);
|
|
243
|
+
merged.set(task, {
|
|
244
|
+
owner: live.owner ?? durable?.owner,
|
|
245
|
+
launchId: live.launchId ?? durable?.launchId,
|
|
246
|
+
sessionId: live.sessionId ?? durable?.sessionId,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
return merged;
|
|
250
|
+
}
|
|
221
251
|
/**
|
|
222
252
|
* Build the launchId -> sessionId index from the same three sources
|
|
223
253
|
* `feed-post.ts` `resolvePostIdentity` already uses for this exact problem —
|
|
@@ -260,7 +290,7 @@ export function resolveLaunchSession(index, launchId) {
|
|
|
260
290
|
* or session-index dependency and is unit-testable with synthetic data (see
|
|
261
291
|
* {@link buildBrowserSessionRows} for the impure disk/index-reading caller).
|
|
262
292
|
*/
|
|
263
|
-
export function groupIntoRows(groups, taskIdentities, resolveLaunch) {
|
|
293
|
+
export function groupIntoRows(groups, taskIdentities, resolveLaunch, resolveSession) {
|
|
264
294
|
const rows = [];
|
|
265
295
|
for (const g of groups) {
|
|
266
296
|
const identities = taskIdentities.get(g.profile) ?? new Map();
|
|
@@ -278,14 +308,24 @@ export function groupIntoRows(groups, taskIdentities, resolveLaunch) {
|
|
|
278
308
|
for (const [task, artifacts] of byTask) {
|
|
279
309
|
artifacts.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
280
310
|
const identity = identities.get(task);
|
|
281
|
-
|
|
311
|
+
// Session id first: it is the direct answer and the one agents actually
|
|
312
|
+
// carry. The launchId join stays as the fallback for a task that recorded
|
|
313
|
+
// only that (an older CLI, or a run whose session id was unset).
|
|
314
|
+
let linkedSession = null;
|
|
315
|
+
if (identity?.sessionId && resolveSession)
|
|
316
|
+
linkedSession = resolveSession(identity.sessionId);
|
|
317
|
+
if (!linkedSession && identity?.launchId && resolveLaunch) {
|
|
318
|
+
linkedSession = resolveLaunch(identity.launchId);
|
|
319
|
+
}
|
|
320
|
+
const hasIdentityKey = !!(identity?.sessionId || identity?.launchId);
|
|
282
321
|
rows.push({
|
|
283
322
|
kind: 'task',
|
|
284
323
|
profile: g.profile,
|
|
285
324
|
task,
|
|
286
325
|
owner: identity?.owner,
|
|
287
326
|
launchId: identity?.launchId,
|
|
288
|
-
|
|
327
|
+
sessionId: identity?.sessionId,
|
|
328
|
+
linkStatus: linkedSession ? 'linked' : hasIdentityKey ? 'unresolved' : 'unlinked',
|
|
289
329
|
linkedSession: linkedSession ?? undefined,
|
|
290
330
|
artifacts,
|
|
291
331
|
counts: countByKind(artifacts),
|
|
@@ -311,10 +351,18 @@ export function groupIntoRows(groups, taskIdentities, resolveLaunch) {
|
|
|
311
351
|
* reading `tasks.json` and resolving launchIds against the live indexes.
|
|
312
352
|
* The interactive picker's data source. */
|
|
313
353
|
export function buildBrowserSessionRows(profile) {
|
|
354
|
+
// Retention runs from BOTH listing paths, not just the computer one: a box
|
|
355
|
+
// that uses `agents browser` and never runs `agents sessions --computer`
|
|
356
|
+
// would otherwise never sweep either table. Best-effort — a read-only DB
|
|
357
|
+
// must not break a listing.
|
|
358
|
+
try {
|
|
359
|
+
pruneToolSessions();
|
|
360
|
+
}
|
|
361
|
+
catch { /* listing must not fail on retention */ }
|
|
314
362
|
const groups = listBrowserSessions(profile);
|
|
315
|
-
const taskIdentities = new Map(groups.map((g) => [g.profile,
|
|
363
|
+
const taskIdentities = new Map(groups.map((g) => [g.profile, loadDurableTaskIdentities(g.profile)]));
|
|
316
364
|
const index = buildLaunchSessionIndex();
|
|
317
|
-
return groupIntoRows(groups, taskIdentities, (launchId) => resolveLaunchSession(index, launchId));
|
|
365
|
+
return groupIntoRows(groups, taskIdentities, (launchId) => resolveLaunchSession(index, launchId), (sessionId) => getSessionById(sessionId));
|
|
318
366
|
}
|
|
319
367
|
/**
|
|
320
368
|
* Search predicate for the interactive picker: task name, profile, the linked
|
|
@@ -53,6 +53,7 @@ export async function runBrowserIPCStream(options) {
|
|
|
53
53
|
taskName: request.taskName ?? defaultTask,
|
|
54
54
|
actor: request.actor ?? options.actor,
|
|
55
55
|
launchId: request.launchId ?? options.launchId,
|
|
56
|
+
sessionId: request.sessionId ?? options.sessionId,
|
|
56
57
|
};
|
|
57
58
|
}
|
|
58
59
|
else if (!request.task && defaultTask) {
|
|
@@ -93,6 +93,13 @@ export interface Task {
|
|
|
93
93
|
* from the caller over IPC. Optional: tasks from before this shipped carry none.
|
|
94
94
|
*/
|
|
95
95
|
launchId?: string;
|
|
96
|
+
/**
|
|
97
|
+
* The agent session that started this task (`$AGENT_SESSION_ID`), forwarded
|
|
98
|
+
* from the caller at `start`. The durable copy lives in the `browser_sessions`
|
|
99
|
+
* table, which survives `stop`; this in-memory/tasks.json copy is the live one
|
|
100
|
+
* (RUSH-2549).
|
|
101
|
+
*/
|
|
102
|
+
sessionId?: string;
|
|
96
103
|
/**
|
|
97
104
|
* Per-tab snapshot of the last ref listing captured for that tab
|
|
98
105
|
* (shortId -> {descriptors, opts}). Persisted to tasks.json so a later
|
|
@@ -196,6 +203,18 @@ export interface IPCRequest {
|
|
|
196
203
|
skipDomainSkill?: boolean;
|
|
197
204
|
actor?: string;
|
|
198
205
|
launchId?: string;
|
|
206
|
+
/**
|
|
207
|
+
* The calling agent session (`$AGENT_SESSION_ID` / `$AGENTS_SESSION_ID`) —
|
|
208
|
+
* the id that answers "which agent drove this task" and the one persisted to
|
|
209
|
+
* `browser_sessions` (RUSH-2549).
|
|
210
|
+
*
|
|
211
|
+
* This is the primary identity, not a spare: `launchId` alone was the join
|
|
212
|
+
* key, and a fleet measurement found it present on only 2 of 5 live agent
|
|
213
|
+
* processes while a session id was on 5 of 5 — every agent reaching the
|
|
214
|
+
* browser carries one. It is the same env `stampProvenance()` already reads
|
|
215
|
+
* for `computer.action` events, so both tool surfaces key on one signal.
|
|
216
|
+
*/
|
|
217
|
+
sessionId?: string;
|
|
199
218
|
}
|
|
200
219
|
/** Subset of IPCResponse describing a recording start result. */
|
|
201
220
|
export interface RecordStartFields {
|
package/dist/lib/byok-usage.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface ByokUsageResult {
|
|
|
20
20
|
error: string | null;
|
|
21
21
|
}
|
|
22
22
|
export declare function setByokFetchForTest(fn: typeof globalThis.fetch): void;
|
|
23
|
+
export declare const BYOK_REFRESH_INTERVAL_MS: number;
|
|
24
|
+
export declare function setByokCachePathForTest(value: string | null): string | null;
|
|
23
25
|
export declare function resetByokCacheForTest(): void;
|
|
24
26
|
export declare function hasByokProvider(provider: string): boolean;
|
|
25
27
|
export declare function renderByokBar(result: ByokUsageResult): string;
|
|
@@ -30,9 +32,14 @@ export declare function renderByokBar(result: ByokUsageResult): string;
|
|
|
30
32
|
* Returns a `ByokUsageResult` with `budget: null` when the token is absent
|
|
31
33
|
* from the keychain (so the caller can skip rendering a bar without error).
|
|
32
34
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
+
* Ordinary reads are cache-only. Explicit refreshes are serialized per provider
|
|
36
|
+
* credential across every agents-cli process on the device.
|
|
35
37
|
*/
|
|
36
38
|
export declare function getByokUsageForHarness(profile: Profile, opts?: {
|
|
37
39
|
forceRefresh?: boolean;
|
|
38
40
|
}): Promise<ByokUsageResult | null>;
|
|
41
|
+
/** Refresh each configured BYOK credential when its daemon-owned snapshot is due. */
|
|
42
|
+
export declare function refreshDueByokUsage(profiles: Profile[], now?: number): Promise<{
|
|
43
|
+
refreshed: number;
|
|
44
|
+
skipped: number;
|
|
45
|
+
}>;
|