@phnx-labs/agents-cli 1.22.112 → 1.22.114
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 +37 -0
- package/README.md +10 -11
- package/dist/cli/command-registry.d.ts +0 -60
- package/dist/cli/command-registry.js +59 -61
- package/dist/commands/apply.d.ts +0 -4
- package/dist/commands/apply.js +3 -3
- package/dist/commands/browser-picker.d.ts +3 -6
- package/dist/commands/browser-picker.js +2 -2
- package/dist/commands/browser-sessions-picker.d.ts +2 -1
- package/dist/commands/computer-sessions-picker.d.ts +2 -1
- package/dist/commands/computer.d.ts +14 -19
- package/dist/commands/computer.js +65 -10
- package/dist/commands/config.js +46 -2
- package/dist/commands/daemon.d.ts +0 -23
- package/dist/commands/daemon.js +1 -1
- package/dist/commands/detach-core.d.ts +2 -1
- package/dist/commands/detach.d.ts +0 -3
- package/dist/commands/detach.js +3 -3
- package/dist/commands/feed.d.ts +3 -3
- package/dist/commands/feed.js +1 -1
- package/dist/commands/focus.d.ts +4 -4
- package/dist/commands/harness-hooks.d.ts +0 -7
- package/dist/commands/harness-hooks.js +1 -1
- package/dist/commands/harness-wizard.d.ts +2 -2
- package/dist/commands/harness.d.ts +3 -8
- package/dist/commands/harness.js +1 -1
- package/dist/commands/inspect.d.ts +2 -3
- package/dist/commands/inspect.js +1 -1
- package/dist/commands/message.d.ts +1 -1
- package/dist/commands/message.js +3 -3
- package/dist/commands/projects.d.ts +2 -18
- package/dist/commands/projects.js +89 -3
- package/dist/commands/resource-view.d.ts +3 -2
- package/dist/commands/resume.d.ts +0 -1
- package/dist/commands/resume.js +1 -1
- package/dist/commands/routines.d.ts +1 -3
- package/dist/commands/routines.js +1 -1
- package/dist/commands/run-account-picker.d.ts +2 -1
- package/dist/commands/run-broadcast.d.ts +2 -1
- package/dist/commands/run-device-picker.d.ts +2 -1
- package/dist/commands/secrets-passthrough.d.ts +14 -0
- package/dist/commands/secrets-passthrough.js +21 -2
- package/dist/commands/sessions-backfill.d.ts +2 -35
- package/dist/commands/sessions-backfill.js +1 -1
- package/dist/commands/sessions-bookmark.d.ts +0 -10
- package/dist/commands/sessions-bookmark.js +1 -1
- package/dist/commands/sessions-inject.d.ts +2 -3
- package/dist/commands/sessions-inject.js +8 -17
- package/dist/commands/sessions-picker-factory.d.ts +4 -14
- package/dist/commands/sessions-picker-factory.js +2 -2
- package/dist/commands/sessions-picker.d.ts +3 -9
- package/dist/commands/sessions-picker.js +2 -2
- package/dist/commands/sessions-resume.d.ts +2 -4
- package/dist/commands/sessions-resume.js +0 -5
- package/dist/commands/sessions-stats.d.ts +2 -1
- package/dist/commands/sessions-stop.d.ts +0 -3
- package/dist/commands/sessions-stop.js +1 -1
- package/dist/commands/sessions-tail.d.ts +2 -1
- package/dist/commands/sessions-trace.d.ts +4 -6
- package/dist/commands/sessions-trace.js +1 -1
- package/dist/commands/sessions.d.ts +14 -104
- package/dist/commands/sessions.js +22 -10
- package/dist/commands/setup-mine.d.ts +0 -6
- package/dist/commands/setup-mine.js +1 -1
- package/dist/commands/setup.d.ts +3 -4
- package/dist/commands/setup.js +1 -1
- package/dist/commands/share.d.ts +8 -8
- package/dist/commands/teams-picker.d.ts +2 -5
- package/dist/commands/teams-picker.js +2 -2
- package/dist/commands/teams.d.ts +1 -7
- package/dist/commands/teams.js +1 -1
- package/dist/commands/tmux.d.ts +1 -1
- package/dist/commands/tmux.js +1 -1
- package/dist/commands/upgrade.d.ts +2 -1
- package/dist/commands/utils.d.ts +1 -1
- package/dist/commands/utils.js +1 -1
- package/dist/lib/account-capabilities.d.ts +2 -1
- package/dist/lib/account-catalog.d.ts +4 -13
- package/dist/lib/account-catalog.js +1 -1
- package/dist/lib/account-registry.d.ts +3 -4
- package/dist/lib/account-registry.js +1 -1
- package/dist/lib/accounting/account-launch.d.ts +4 -3
- package/dist/lib/accounting/account-pool.d.ts +2 -1
- package/dist/lib/accounting/rotate.d.ts +3 -9
- package/dist/lib/accounting/rotate.js +2 -14
- package/dist/lib/accounting/usage-sync.d.ts +5 -4
- package/dist/lib/accounting/usage.d.ts +7 -31
- package/dist/lib/accounting/usage.js +4 -4
- package/dist/lib/accounts/migrate.d.ts +8 -8
- package/dist/lib/accounts/migrate.js +1 -1
- package/dist/lib/acp/client.d.ts +3 -2
- package/dist/lib/acp/harnesses.d.ts +2 -2
- package/dist/lib/acp/harnesses.js +1 -1
- package/dist/lib/acp/run.d.ts +2 -1
- package/dist/lib/actor.d.ts +3 -2
- package/dist/lib/add-dir.d.ts +2 -17
- package/dist/lib/add-dir.js +2 -6
- package/dist/lib/address.d.ts +56 -0
- package/dist/lib/address.js +143 -0
- package/dist/lib/agent-spec/agents.d.ts +12 -28
- package/dist/lib/agent-spec/agents.js +2 -6
- package/dist/lib/agent-spec/primitives.d.ts +0 -7
- package/dist/lib/agent-spec/primitives.js +0 -6
- package/dist/lib/agent-spec/types.d.ts +2 -1
- package/dist/lib/analytics/dashboard.d.ts +1 -5
- package/dist/lib/analytics/dashboard.js +0 -2
- package/dist/lib/analytics/mix-commands.d.ts +0 -7
- package/dist/lib/analytics/mix-commands.js +3 -3
- package/dist/lib/analytics/recipes.d.ts +0 -12
- package/dist/lib/analytics/recipes.js +7 -31
- package/dist/lib/analytics/usage-db.d.ts +5 -32
- package/dist/lib/analytics/usage-db.js +1 -70
- package/dist/lib/answer-router.d.ts +7 -6
- package/dist/lib/answer-router.js +5 -11
- package/dist/lib/artifact-actions.d.ts +0 -4
- package/dist/lib/ask-classifier.d.ts +3 -4
- package/dist/lib/ask-classifier.js +0 -7
- package/dist/lib/auth-health.d.ts +3 -46
- package/dist/lib/auth-health.js +3 -3
- package/dist/lib/auth-mint.d.ts +6 -6
- package/dist/lib/auth-mint.js +5 -5
- package/dist/lib/bench/runner.d.ts +2 -2
- package/dist/lib/bench/runner.js +1 -1
- package/dist/lib/bench/storage.d.ts +0 -1
- package/dist/lib/bench/storage.js +1 -1
- package/dist/lib/boot-profile.d.ts +0 -2
- package/dist/lib/boot-profile.js +0 -4
- package/dist/lib/brand.d.ts +0 -6
- package/dist/lib/brand.js +1 -1
- package/dist/lib/browser/arc-discovery.d.ts +4 -12
- package/dist/lib/browser/arc-discovery.js +1 -1
- package/dist/lib/browser/cdp.d.ts +1 -1
- package/dist/lib/browser/chrome.d.ts +2 -2
- package/dist/lib/browser/chrome.js +0 -4
- package/dist/lib/browser/chromium-discovery.d.ts +3 -2
- package/dist/lib/browser/drivers/arc.d.ts +3 -20
- package/dist/lib/browser/drivers/arc.js +2 -7
- package/dist/lib/browser/drivers/firefox.d.ts +2 -6
- package/dist/lib/browser/drivers/firefox.js +1 -1
- package/dist/lib/browser/drivers/local.d.ts +2 -1
- package/dist/lib/browser/drivers/ssh.d.ts +2 -3
- package/dist/lib/browser/drivers/ssh.js +0 -7
- package/dist/lib/browser/firefox-discovery.d.ts +4 -3
- package/dist/lib/browser/har.d.ts +8 -7
- package/dist/lib/browser/hygiene.d.ts +2 -3
- package/dist/lib/browser/hygiene.js +1 -1
- package/dist/lib/browser/ipc.d.ts +4 -3
- package/dist/lib/browser/ipc.js +1 -1
- package/dist/lib/browser/login-detection.d.ts +1 -8
- package/dist/lib/browser/registry.d.ts +2 -1
- package/dist/lib/browser/remote-control.d.ts +0 -7
- package/dist/lib/browser/remote-control.js +2 -2
- package/dist/lib/browser/resolve-target.d.ts +2 -6
- package/dist/lib/browser/resolve-target.js +3 -3
- package/dist/lib/browser/runtime-state.d.ts +4 -4
- package/dist/lib/browser/service.d.ts +4 -4
- package/dist/lib/browser/sessions-list.d.ts +0 -10
- package/dist/lib/browser/sessions-list.js +3 -3
- package/dist/lib/browser/stream.d.ts +2 -1
- package/dist/lib/browser/task-index.d.ts +4 -4
- package/dist/lib/browser/task-index.js +1 -1
- package/dist/lib/browser/types.d.ts +0 -20
- package/dist/lib/browser/types.js +1 -34
- package/dist/lib/browser/upload.d.ts +0 -27
- package/dist/lib/budget/ledger.d.ts +0 -2
- package/dist/lib/budget/ledger.js +1 -1
- package/dist/lib/budget/live-cloud.d.ts +2 -1
- package/dist/lib/budget/preflight.d.ts +3 -5
- package/dist/lib/budget/preflight.js +1 -1
- package/dist/lib/catchup.d.ts +2 -1
- package/dist/lib/channels/owner-forward.d.ts +5 -4
- package/dist/lib/channels/owner-sink.js +2 -2
- package/dist/lib/channels/providers/desktop.js +1 -1
- package/dist/lib/channels/providers/rush.d.ts +2 -1
- package/dist/lib/channels/registry.d.ts +1 -1
- package/dist/lib/channels/registry.js +1 -1
- package/dist/lib/channels/resolve.d.ts +3 -2
- package/dist/lib/channels/send.d.ts +5 -4
- package/dist/lib/cli-resources.d.ts +3 -9
- package/dist/lib/cli-resources.js +1 -1
- package/dist/lib/cloud/cursor.d.ts +1 -2
- package/dist/lib/cloud/cursor.js +1 -1
- package/dist/lib/cloud/dispatch.d.ts +2 -1
- package/dist/lib/cloud/factory.d.ts +0 -2
- package/dist/lib/cloud/factory.js +1 -1
- package/dist/lib/cloud/rush.d.ts +3 -11
- package/dist/lib/cloud/rush.js +1 -1
- package/dist/lib/cloud/session-index.d.ts +2 -1
- package/dist/lib/cloud/types.d.ts +2 -1
- package/dist/lib/codex-policy.d.ts +2 -1
- package/dist/lib/commands.d.ts +7 -7
- package/dist/lib/commands.js +1 -1
- package/dist/lib/comms-render.d.ts +1 -1
- package/dist/lib/computer/context.d.ts +11 -3
- package/dist/lib/computer/context.js +2 -2
- package/dist/lib/computer/policy.d.ts +0 -12
- package/dist/lib/computer/policy.js +1 -1
- package/dist/lib/computer-client.d.ts +3 -3
- package/dist/lib/computer-client.js +0 -1
- package/dist/lib/concurrency.d.ts +2 -1
- package/dist/lib/config-keys.d.ts +16 -3
- package/dist/lib/config-keys.js +47 -2
- package/dist/lib/convert.d.ts +0 -12
- package/dist/lib/convert.js +1 -12
- package/dist/lib/crabbox/cli.d.ts +6 -24
- package/dist/lib/crabbox/cli.js +2 -28
- package/dist/lib/crabbox/lease.d.ts +5 -6
- package/dist/lib/crabbox/lease.js +1 -1
- package/dist/lib/crabbox/progress.d.ts +2 -1
- package/dist/lib/crabbox/setup-copy.d.ts +2 -3
- package/dist/lib/crabbox/setup-copy.js +1 -1
- package/dist/lib/daemon/account-state-daemon-service.d.ts +1 -1
- package/dist/lib/daemon/attention-notify-service.d.ts +2 -1
- package/dist/lib/daemon/catchup-service.d.ts +2 -1
- package/dist/lib/daemon/daemon.d.ts +4 -12
- package/dist/lib/daemon/daemon.js +42 -23
- package/dist/lib/daemon/harness-update-service.d.ts +2 -19
- package/dist/lib/daemon/harness-update-service.js +3 -3
- package/dist/lib/daemon/runner.d.ts +3 -3
- package/dist/lib/daemon/self-update-service.d.ts +1 -16
- package/dist/lib/daemon/self-update-service.js +6 -6
- package/dist/lib/daemon/state-dir-check-service.d.ts +2 -1
- package/dist/lib/daemon/supervisor.d.ts +3 -2
- package/dist/lib/daemon/testdata/process-view-daemon.d.ts +1 -0
- package/dist/lib/daemon/testdata/process-view-daemon.js +14 -0
- package/dist/lib/daemon/testdata/process-view-start.d.ts +1 -0
- package/dist/lib/daemon/testdata/process-view-start.js +43 -0
- package/dist/lib/daemon-services.d.ts +2 -1
- package/dist/lib/daemon-webhooks.d.ts +1 -1
- package/dist/lib/deeplink/register.d.ts +3 -13
- package/dist/lib/deeplink/register.js +3 -3
- package/dist/lib/deeplink/url.d.ts +3 -2
- package/dist/lib/device-config.d.ts +4 -15
- package/dist/lib/device-config.js +164 -8
- package/dist/lib/devices/connect.d.ts +2 -1
- package/dist/lib/devices/discovery-policy.d.ts +3 -2
- package/dist/lib/devices/doctor-findings.js +1 -1
- package/dist/lib/devices/doctor-overview-cache.d.ts +3 -2
- package/dist/lib/devices/fleet-divergence.d.ts +2 -1
- package/dist/lib/devices/fleet.d.ts +3 -4
- package/dist/lib/devices/fleet.js +1 -1
- package/dist/lib/devices/harness-inventory.d.ts +3 -2
- package/dist/lib/devices/health-report.d.ts +3 -2
- package/dist/lib/devices/health.d.ts +1 -8
- package/dist/lib/devices/health.js +1 -1
- package/dist/lib/devices/interactive-host.d.ts +0 -2
- package/dist/lib/devices/interactive-host.js +1 -1
- package/dist/lib/devices/known-hosts.d.ts +2 -20
- package/dist/lib/devices/known-hosts.js +2 -2
- package/dist/lib/devices/pool.d.ts +2 -1
- package/dist/lib/devices/resolve-target.d.ts +2 -2
- package/dist/lib/devices/rollout-verify.d.ts +3 -2
- package/dist/lib/devices/stats-cache.d.ts +3 -2
- package/dist/lib/devices/sync.d.ts +6 -5
- package/dist/lib/devices/worker-pick.d.ts +3 -12
- package/dist/lib/devices/worker-pick.js +1 -1
- package/dist/lib/diff-text.d.ts +2 -1
- package/dist/lib/doctor-diff.d.ts +2 -1
- package/dist/lib/drift-sync.d.ts +3 -2
- package/dist/lib/drift.d.ts +3 -3
- package/dist/lib/drift.js +1 -1
- package/dist/lib/event-families.d.ts +0 -6
- package/dist/lib/event-families.js +3 -3
- package/dist/lib/event-provenance.d.ts +4 -1
- package/dist/lib/event-provenance.js +4 -0
- package/dist/lib/events-ingest.d.ts +4 -3
- package/dist/lib/exec-account-home.d.ts +2 -4
- package/dist/lib/exec-account-home.js +1 -1
- package/dist/lib/exec-bounded.d.ts +3 -4
- package/dist/lib/exec-bounded.js +1 -1
- package/dist/lib/exec.d.ts +6 -18
- package/dist/lib/exec.js +28 -8
- package/dist/lib/factory/snapshot.d.ts +2 -2
- package/dist/lib/factory/snapshot.js +1 -1
- package/dist/lib/feed/activity-stream.d.ts +2 -5
- package/dist/lib/feed/activity-stream.js +11 -2
- package/dist/lib/feed/activity.d.ts +16 -33
- package/dist/lib/feed/activity.js +69 -26
- package/dist/lib/feed/answer.d.ts +3 -2
- package/dist/lib/feed/attention.js +5 -1
- package/dist/lib/feed/events.d.ts +2 -47
- package/dist/lib/feed/events.js +1 -141
- package/dist/lib/feed/feed.d.ts +9 -42
- package/dist/lib/feed/feed.js +1 -60
- package/dist/lib/feed/pr-status.d.ts +0 -2
- package/dist/lib/feed/pr-status.js +1 -5
- package/dist/lib/feed/watch.d.ts +10 -2
- package/dist/lib/feed/watch.js +91 -4
- package/dist/lib/feed-broadcast.d.ts +5 -47
- package/dist/lib/feed-broadcast.js +9 -9
- package/dist/lib/feed-outcome.d.ts +3 -6
- package/dist/lib/feed-outcome.js +2 -2
- package/dist/lib/feed-policy.d.ts +5 -6
- package/dist/lib/feed-policy.js +2 -2
- package/dist/lib/feed-post.d.ts +3 -4
- package/dist/lib/feed-post.js +2 -2
- package/dist/lib/feed-ranking.d.ts +2 -2
- package/dist/lib/feed-ranking.js +1 -1
- package/dist/lib/fleet/apply.d.ts +5 -6
- package/dist/lib/fleet/apply.js +4 -4
- package/dist/lib/fleet/manifest.d.ts +2 -1
- package/dist/lib/fleet/remote-login.d.ts +18 -36
- package/dist/lib/fleet/remote-login.js +20 -19
- package/dist/lib/fleet/types.d.ts +0 -8
- package/dist/lib/fleet-cache.d.ts +1 -18
- package/dist/lib/fleet-cache.js +0 -5
- package/dist/lib/fleet-shared-repo-sync.d.ts +3 -3
- package/dist/lib/fleet-shared-repo-sync.js +1 -1
- package/dist/lib/fleet-shared-state.d.ts +3 -2
- package/dist/lib/format.d.ts +2 -1
- package/dist/lib/friction-heuristics.d.ts +2 -1
- package/dist/lib/fs-walk.d.ts +2 -1
- package/dist/lib/fuzzy.d.ts +2 -1
- package/dist/lib/gemini-settings.d.ts +0 -1
- package/dist/lib/gemini-settings.js +1 -1
- package/dist/lib/git.d.ts +7 -65
- package/dist/lib/git.js +3 -142
- package/dist/lib/github/gh-overload.d.ts +0 -4
- package/dist/lib/github/gh-overload.js +2 -2
- package/dist/lib/github/project-prs.d.ts +118 -0
- package/dist/lib/github/project-prs.js +173 -0
- package/dist/lib/github/rest.d.ts +2 -1
- package/dist/lib/harness/exec-config-version.d.ts +2 -1
- package/dist/lib/harness-auth-capabilities.d.ts +5 -4
- package/dist/lib/harness-connection-test.d.ts +2 -1
- package/dist/lib/heal.d.ts +3 -20
- package/dist/lib/heal.js +2 -39
- package/dist/lib/help.d.ts +3 -2
- package/dist/lib/helper-download.d.ts +0 -12
- package/dist/lib/helper-download.js +2 -2
- package/dist/lib/helper-versions.d.ts +2 -1
- package/dist/lib/helper-versions.js +1 -1
- package/dist/lib/hooks/install.d.ts +8 -49
- package/dist/lib/hooks/install.js +2 -96
- package/dist/lib/hooks/match.d.ts +2 -1
- package/dist/lib/hosts/credential-transport.d.ts +0 -2
- package/dist/lib/hosts/credential-transport.js +1 -1
- package/dist/lib/hosts/dispatch.d.ts +2 -34
- package/dist/lib/hosts/dispatch.js +4 -21
- package/dist/lib/hosts/logs.d.ts +2 -1
- package/dist/lib/hosts/passthrough.d.ts +1 -1
- package/dist/lib/hosts/passthrough.js +0 -1
- package/dist/lib/hosts/progress.d.ts +0 -5
- package/dist/lib/hosts/progress.js +1 -1
- package/dist/lib/hosts/ready.d.ts +3 -4
- package/dist/lib/hosts/ready.js +0 -8
- package/dist/lib/hosts/reconcile.d.ts +2 -8
- package/dist/lib/hosts/reconcile.js +1 -1
- package/dist/lib/hosts/reconnect.d.ts +4 -11
- package/dist/lib/hosts/reconnect.js +2 -2
- package/dist/lib/hosts/registry.d.ts +1 -1
- package/dist/lib/hosts/remote-cmd.d.ts +4 -3
- package/dist/lib/hosts/remote-session-id.d.ts +5 -27
- package/dist/lib/hosts/remote-session-id.js +18 -61
- package/dist/lib/hosts/session-index.d.ts +3 -2
- package/dist/lib/hosts/ssh-config.d.ts +2 -3
- package/dist/lib/hosts/ssh-config.js +0 -10
- package/dist/lib/humans.d.ts +0 -2
- package/dist/lib/humans.js +2 -2
- package/dist/lib/import.d.ts +4 -3
- package/dist/lib/installations/installation-lock.d.ts +0 -2
- package/dist/lib/installations/installation-lock.js +2 -2
- package/dist/lib/installations/launch-gate.d.ts +0 -9
- package/dist/lib/installations/launch-gate.js +1 -1
- package/dist/lib/installations/migrate.d.ts +0 -11
- package/dist/lib/installations/migrate.js +1 -1
- package/dist/lib/installations/shims.d.ts +1 -1
- package/dist/lib/installations/shims.js +2 -2
- package/dist/lib/installations/update-runtime.js +1 -1
- package/dist/lib/launch-identity.d.ts +10 -0
- package/dist/lib/launch-identity.js +31 -0
- package/dist/lib/linear-cache.d.ts +2 -1
- package/dist/lib/linux-userns.d.ts +2 -3
- package/dist/lib/linux-userns.js +0 -4
- package/dist/lib/loop.d.ts +2 -1
- package/dist/lib/mailbox-gc.d.ts +2 -1
- package/dist/lib/mailbox-target.d.ts +2 -1
- package/dist/lib/mailbox.d.ts +0 -6
- package/dist/lib/mailbox.js +1 -1
- package/dist/lib/manifest.d.ts +0 -14
- package/dist/lib/manifest.js +2 -2
- package/dist/lib/mcp-registry.d.ts +2 -1
- package/dist/lib/memory.d.ts +2 -13
- package/dist/lib/memory.js +4 -4
- package/dist/lib/menubar/download-menubar.d.ts +0 -2
- package/dist/lib/menubar/download-menubar.js +1 -5
- package/dist/lib/menubar/install-menubar.d.ts +3 -14
- package/dist/lib/menubar/install-menubar.js +3 -3
- package/dist/lib/menubar/migrate-prefs.d.ts +53 -0
- package/dist/lib/menubar/migrate-prefs.js +168 -0
- package/dist/lib/menubar/resolve-version.d.ts +1 -9
- package/dist/lib/menubar/resolve-version.js +4 -4
- package/dist/lib/menubar/snapshot.d.ts +24 -2
- package/dist/lib/menubar/snapshot.js +26 -0
- package/dist/lib/model-tier-overrides.d.ts +3 -2
- package/dist/lib/monitors/config.d.ts +0 -2
- package/dist/lib/monitors/config.js +0 -4
- package/dist/lib/monitors/engine.d.ts +1 -1
- package/dist/lib/monitors/remote.d.ts +3 -2
- package/dist/lib/monitors/sources/webhook.d.ts +2 -15
- package/dist/lib/monitors/sources/webhook.js +1 -38
- package/dist/lib/monitors/state.d.ts +4 -7
- package/dist/lib/monitors/state.js +2 -2
- package/dist/lib/notify.d.ts +1 -1
- package/dist/lib/notify.js +1 -1
- package/dist/lib/onepassword.d.ts +5 -14
- package/dist/lib/onepassword.js +0 -64
- package/dist/lib/open-url.d.ts +3 -2
- package/dist/lib/openclaw-keychain.d.ts +4 -17
- package/dist/lib/openclaw-keychain.js +3 -33
- package/dist/lib/operator.d.ts +2 -2
- package/dist/lib/operator.js +1 -1
- package/dist/lib/output/git-output.d.ts +4 -14
- package/dist/lib/output/git-output.js +1 -1
- package/dist/lib/owner-message.d.ts +3 -29
- package/dist/lib/owner-message.js +3 -3
- package/dist/lib/packages/output-home.d.ts +2 -4
- package/dist/lib/packages/output-home.js +2 -2
- package/dist/lib/perf/db.d.ts +0 -2
- package/dist/lib/perf/db.js +2 -7
- package/dist/lib/permissions-registry.d.ts +2 -3
- package/dist/lib/permissions-registry.js +0 -4
- package/dist/lib/permissions.d.ts +6 -16
- package/dist/lib/permissions.js +2 -15
- package/dist/lib/picker.d.ts +6 -5
- package/dist/lib/placement.d.ts +3 -6
- package/dist/lib/placement.js +0 -17
- package/dist/lib/platform/posixpath.d.ts +2 -1
- package/dist/lib/platform/winpath.d.ts +2 -1
- package/dist/lib/plugins/plugin-marketplace.d.ts +2 -2
- package/dist/lib/plugins/plugin-marketplace.js +1 -1
- package/dist/lib/pr-land-detach.d.ts +2 -1
- package/dist/lib/profiles-presets.d.ts +2 -1
- package/dist/lib/profiles.d.ts +3 -9
- package/dist/lib/profiles.js +1 -9
- package/dist/lib/project-doctor.d.ts +2 -1
- package/dist/lib/project-launch.d.ts +2 -2
- package/dist/lib/project-probe.d.ts +4 -3
- package/dist/lib/project-pull.d.ts +2 -1
- package/dist/lib/project-resources.d.ts +2 -2
- package/dist/lib/project-resources.js +1 -1
- package/dist/lib/project-root.d.ts +2 -6
- package/dist/lib/project-root.js +1 -1
- package/dist/lib/project-schedule.d.ts +2 -1
- package/dist/lib/project-status.d.ts +2 -16
- package/dist/lib/project-status.js +3 -3
- package/dist/lib/reconcile-and-repair.d.ts +5 -4
- package/dist/lib/redact.d.ts +7 -1
- package/dist/lib/redact.js +94 -3
- package/dist/lib/refresh-coordinator.d.ts +2 -1
- package/dist/lib/refresh.d.ts +3 -2
- package/dist/lib/remote-agents-json.d.ts +3 -2
- package/dist/lib/reserved-stores.d.ts +0 -2
- package/dist/lib/reserved-stores.js +3 -5
- package/dist/lib/resource-content-diff.d.ts +0 -2
- package/dist/lib/resource-content-diff.js +1 -1
- package/dist/lib/resource-patterns.d.ts +2 -1
- package/dist/lib/resource-profiles.d.ts +2 -8
- package/dist/lib/resource-profiles.js +3 -27
- package/dist/lib/resources/workflows.d.ts +1 -1
- package/dist/lib/resources.d.ts +4 -9
- package/dist/lib/resources.js +1 -1
- package/dist/lib/routine-context.d.ts +2 -5
- package/dist/lib/routine-context.js +2 -2
- package/dist/lib/routine-notify-owner.d.ts +8 -7
- package/dist/lib/routine-notify-owner.js +5 -5
- package/dist/lib/routine-process-cleanup.d.ts +2 -1
- package/dist/lib/routine-readiness.d.ts +0 -2
- package/dist/lib/routine-readiness.js +0 -7
- package/dist/lib/routines-project.d.ts +3 -4
- package/dist/lib/routines-project.js +1 -1
- package/dist/lib/rules/compile.d.ts +3 -25
- package/dist/lib/rules/compile.js +1 -1
- package/dist/lib/rules/compose.d.ts +3 -9
- package/dist/lib/rules/rules.d.ts +4 -15
- package/dist/lib/rules/rules.js +1 -64
- package/dist/lib/run-defaults.d.ts +1 -1
- package/dist/lib/run-notify.d.ts +2 -1
- package/dist/lib/run-trace-sync.d.ts +1 -1
- package/dist/lib/run-trace-sync.js +1 -1
- package/dist/lib/scheduler.d.ts +2 -1
- package/dist/lib/scheduling/routines.d.ts +9 -21
- package/dist/lib/scheduling/routines.js +3 -46
- package/dist/lib/secrets-client.d.ts +0 -17
- package/dist/lib/secrets-client.js +4 -26
- package/dist/lib/secrets-policy.d.ts +12 -17
- package/dist/lib/secrets-policy.js +5 -5
- package/dist/lib/secrets-types.d.ts +3 -2
- package/dist/lib/secrets-types.js +2 -1
- package/dist/lib/self-heal/checks/install-staging.js +1 -1
- package/dist/lib/self-heal/registry.d.ts +3 -2
- package/dist/lib/self-heal/types.d.ts +1 -1
- package/dist/lib/self-heal/types.js +1 -1
- package/dist/lib/self-update.d.ts +5 -5
- package/dist/lib/self-update.js +4 -4
- package/dist/lib/session/active.js +9 -3
- package/dist/lib/session/actor-sidecar.d.ts +3 -2
- package/dist/lib/session/artifacts.d.ts +0 -2
- package/dist/lib/session/artifacts.js +1 -1
- package/dist/lib/session/bash-command.d.ts +2 -7
- package/dist/lib/session/bundle.d.ts +4 -6
- package/dist/lib/session/bundle.js +1 -5
- package/dist/lib/session/cloud.d.ts +0 -4
- package/dist/lib/session/cloud.js +2 -15
- package/dist/lib/session/db.d.ts +2 -1
- package/dist/lib/session/db.js +39 -4
- package/dist/lib/session/detached.d.ts +2 -1
- package/dist/lib/session/detached.js +2 -2
- package/dist/lib/session/digest.d.ts +2 -2
- package/dist/lib/session/digest.js +1 -1
- package/dist/lib/session/discover.js +7 -2
- package/dist/lib/session/fork.d.ts +3 -2
- package/dist/lib/session/highlights.d.ts +6 -5
- package/dist/lib/session/hook-sessions.d.ts +12 -1
- package/dist/lib/session/hook-sessions.js +139 -6
- package/dist/lib/session/host-link.d.ts +2 -1
- package/dist/lib/session/inject.d.ts +1 -1
- package/dist/lib/session/inject.js +1 -1
- package/dist/lib/session/insights.d.ts +3 -15
- package/dist/lib/session/insights.js +2 -2
- package/dist/lib/session/local-tmux-attach.d.ts +2 -18
- package/dist/lib/session/local-tmux-attach.js +1 -1
- package/dist/lib/session/migrations.d.ts +0 -1
- package/dist/lib/session/migrations.js +1 -1
- package/dist/lib/session/mirror.d.ts +5 -8
- package/dist/lib/session/mirror.js +2 -2
- package/dist/lib/session/parse.d.ts +1 -32
- package/dist/lib/session/parse.js +4 -4
- package/dist/lib/session/pid-registry.d.ts +18 -5
- package/dist/lib/session/pid-registry.js +164 -17
- package/dist/lib/session/presence.d.ts +2 -1
- package/dist/lib/session/process-view.d.ts +25 -0
- package/dist/lib/session/process-view.js +176 -0
- package/dist/lib/session/projection.d.ts +13 -0
- package/dist/lib/session/projection.js +101 -0
- package/dist/lib/session/prompt.d.ts +3 -2
- package/dist/lib/session/prompt.js +38 -1
- package/dist/lib/session/recovery.d.ts +3 -2
- package/dist/lib/session/remote/peer-stream.d.ts +2 -5
- package/dist/lib/session/remote/peer-stream.js +2 -2
- package/dist/lib/session/remote/remote-bundle.d.ts +2 -1
- package/dist/lib/session/remote/remote-list.d.ts +5 -5
- package/dist/lib/session/remote/remote.d.ts +4 -3
- package/dist/lib/session/remote/watch.d.ts +10 -7
- package/dist/lib/session/remote/watch.js +10 -6
- package/dist/lib/session/remote-active.d.ts +2 -1
- package/dist/lib/session/render.d.ts +2 -2
- package/dist/lib/session/render.js +1 -1
- package/dist/lib/session/resume-owner.d.ts +1 -1
- package/dist/lib/session/resume-owner.js +1 -1
- package/dist/lib/session/run-names.d.ts +2 -1
- package/dist/lib/session/session-cache.d.ts +7 -26
- package/dist/lib/session/session-cache.js +17 -8
- package/dist/lib/session/share-html.d.ts +1 -21
- package/dist/lib/session/share-html.js +1 -1
- package/dist/lib/session/shell-programs.d.ts +2 -1
- package/dist/lib/session/state.d.ts +41 -8
- package/dist/lib/session/state.js +112 -11
- package/dist/lib/session/stream-render.d.ts +2 -1
- package/dist/lib/session/sync/agents.d.ts +0 -4
- package/dist/lib/session/sync/agents.js +0 -0
- package/dist/lib/session/sync/backend.d.ts +5 -5
- package/dist/lib/session/sync/managed-config.d.ts +0 -8
- package/dist/lib/session/sync/managed-key.d.ts +0 -2
- package/dist/lib/session/sync/managed-key.js +1 -1
- package/dist/lib/session/sync/r2.d.ts +4 -1
- package/dist/lib/session/sync/r2.js +4 -7
- package/dist/lib/session/sync/transcript-crypto.d.ts +2 -1
- package/dist/lib/session/tail.d.ts +2 -1
- package/dist/lib/session/team-filter.d.ts +1 -1
- package/dist/lib/session/testdata/pid-registry-namespace.d.ts +1 -0
- package/dist/lib/session/testdata/pid-registry-namespace.js +27 -0
- package/dist/lib/session/testdata/process-view-namespace.d.ts +1 -0
- package/dist/lib/session/testdata/process-view-namespace.js +56 -0
- package/dist/lib/session/testdata/process-view-private.d.ts +1 -0
- package/dist/lib/session/testdata/process-view-private.js +12 -0
- package/dist/lib/session/throughput.d.ts +2 -3
- package/dist/lib/session/throughput.js +1 -1
- package/dist/lib/session/timeline-pass.d.ts +3 -42
- package/dist/lib/session/timeline-pass.js +4 -4
- package/dist/lib/session/timeline.d.ts +3 -13
- package/dist/lib/session/timeline.js +3 -3
- package/dist/lib/session/tool-calls.d.ts +2 -2
- package/dist/lib/session/tool-calls.js +1 -1
- package/dist/lib/session/tool-index.d.ts +0 -8
- package/dist/lib/session/tool-index.js +2 -2
- package/dist/lib/session/tool-store.d.ts +2 -1
- package/dist/lib/session/trajectory-compare.d.ts +2 -1
- package/dist/lib/session/trajectory-lineage.d.ts +2 -1
- package/dist/lib/session/trajectory-text.d.ts +3 -2
- package/dist/lib/session/trajectory.d.ts +2 -1
- package/dist/lib/session/viewing-in.d.ts +2 -1
- package/dist/lib/settings-manifest.d.ts +2 -1
- package/dist/lib/share/delete.d.ts +5 -4
- package/dist/lib/share/html.d.ts +0 -2
- package/dist/lib/share/html.js +9 -9
- package/dist/lib/share/http-error.d.ts +3 -2
- package/dist/lib/share/og.d.ts +2 -1
- package/dist/lib/share/provision.d.ts +2 -2
- package/dist/lib/share/publish.d.ts +4 -13
- package/dist/lib/share/publish.js +2 -2
- package/dist/lib/shim-heal.d.ts +1 -5
- package/dist/lib/shim-heal.js +0 -6
- package/dist/lib/smart-launch.d.ts +4 -5
- package/dist/lib/smart-launch.js +1 -1
- package/dist/lib/snapshot.d.ts +3 -2
- package/dist/lib/ssh-exec.d.ts +5 -4
- package/dist/lib/ssh-tunnel.d.ts +3 -2
- package/dist/lib/staleness/checkers/permissions.d.ts +0 -2
- package/dist/lib/staleness/checkers/permissions.js +1 -1
- package/dist/lib/staleness/fingerprint.d.ts +0 -7
- package/dist/lib/staleness/fingerprint.js +1 -1
- package/dist/lib/staleness/prune.d.ts +3 -2
- package/dist/lib/staleness/registry.d.ts +1 -1
- package/dist/lib/staleness/writers/sources.d.ts +0 -8
- package/dist/lib/staleness/writers/sources.js +1 -1
- package/dist/lib/startup/command-registry.js +1 -1
- package/dist/lib/state.d.ts +1 -3
- package/dist/lib/state.js +1 -4
- package/dist/lib/subagents-registry.d.ts +4 -3
- package/dist/lib/subagents.d.ts +2 -1
- package/dist/lib/subagents.js +3 -2
- package/dist/lib/summarizer/pass.d.ts +3 -6
- package/dist/lib/summarizer/pass.js +2 -2
- package/dist/lib/summarizer/summarize.d.ts +4 -3
- package/dist/lib/sync-passphrase.d.ts +3 -2
- package/dist/lib/sync-status.d.ts +3 -16
- package/dist/lib/sync-status.js +2 -2
- package/dist/lib/sync-umbrella.d.ts +4 -3
- package/dist/lib/system-run-sync.d.ts +2 -1
- package/dist/lib/teams/agents.d.ts +2 -4
- package/dist/lib/teams/agents.js +1 -1
- package/dist/lib/teams/forEach.d.ts +3 -2
- package/dist/lib/teams/pr-watch.d.ts +4 -11
- package/dist/lib/teams/pr-watch.js +4 -4
- package/dist/lib/teams/registry.d.ts +2 -3
- package/dist/lib/teams/registry.js +1 -1
- package/dist/lib/teams/remoteWorktree.d.ts +0 -16
- package/dist/lib/teams/remoteWorktree.js +3 -3
- package/dist/lib/teams/scheduler.d.ts +6 -5
- package/dist/lib/teams/scheduler.js +1 -1
- package/dist/lib/teams/supervisor.d.ts +4 -3
- package/dist/lib/teams/worktree.d.ts +0 -9
- package/dist/lib/teams/worktree.js +0 -32
- package/dist/lib/term-client.d.ts +44 -0
- package/dist/lib/term-client.js +117 -0
- package/dist/lib/terminal/inject.d.ts +3 -16
- package/dist/lib/terminal/inject.js +1 -29
- package/dist/lib/terminal/resolve.d.ts +3 -9
- package/dist/lib/terminal/resolve.js +3 -7
- package/dist/lib/tmux/binary.d.ts +2 -1
- package/dist/lib/tmux/orphan-reap.d.ts +6 -7
- package/dist/lib/tmux/orphan-reap.js +1 -1
- package/dist/lib/tmux/session.d.ts +4 -3
- package/dist/lib/traces/classify.d.ts +3 -2
- package/dist/lib/traces/config.d.ts +0 -8
- package/dist/lib/traces/insights.d.ts +2 -1
- package/dist/lib/traces/phenotype.d.ts +3 -3
- package/dist/lib/traces/provision.d.ts +1 -3
- package/dist/lib/traces/provision.js +1 -1
- package/dist/lib/traces/schema2-build.d.ts +1 -1
- package/dist/lib/traces/schema2-danger.d.ts +2 -1
- package/dist/lib/traces/schema2.d.ts +5 -4
- package/dist/lib/traces/segments.d.ts +4 -20
- package/dist/lib/traces/segments.js +3 -3
- package/dist/lib/traces/sync.d.ts +2 -3
- package/dist/lib/traces/sync.js +1 -1
- package/dist/lib/triggers/handlers.d.ts +4 -13
- package/dist/lib/triggers/handlers.js +1 -1
- package/dist/lib/triggers/webhook.d.ts +5 -27
- package/dist/lib/triggers/webhook.js +4 -4
- package/dist/lib/types.d.ts +3 -3
- package/dist/lib/usage-refresh.d.ts +4 -10
- package/dist/lib/usage-refresh.js +3 -8
- package/dist/lib/verbs.d.ts +2 -1
- package/dist/lib/version-duplicates.d.ts +2 -3
- package/dist/lib/version-duplicates.js +3 -33
- package/dist/lib/version.d.ts +2 -1
- package/dist/lib/warn-unpushed.d.ts +2 -1
- package/dist/lib/watchdog/history.d.ts +3 -2
- package/dist/lib/watchdog/log.d.ts +0 -6
- package/dist/lib/watchdog/log.js +1 -1
- package/dist/lib/watchdog/rotate.d.ts +2 -26
- package/dist/lib/watchdog/rotate.js +4 -12
- package/dist/lib/watchdog/runner.d.ts +0 -7
- package/dist/lib/watchdog/runner.js +4 -4
- package/dist/lib/watchdog/service.d.ts +2 -2
- package/dist/lib/watchdog/service.js +1 -1
- package/dist/lib/watchdog/watchdog-agent.d.ts +2 -1
- package/dist/lib/watchdog/watchdog.d.ts +2 -1
- package/dist/lib/watchdog/watchdogTail.d.ts +2 -1
- package/dist/lib/workflows-registry.d.ts +3 -2
- package/dist/lib/workflows.d.ts +4 -7
- package/dist/lib/workflows.js +1 -1
- package/dist/lib/worktree/held.d.ts +4 -28
- package/dist/lib/worktree/held.js +3 -3
- package/package.json +2 -3
- package/scripts/postinstall.js +5 -4
- package/dist/commands/pty.d.ts +0 -20
- package/dist/commands/pty.js +0 -404
- package/dist/lib/config-machine-keys.d.ts +0 -14
- package/dist/lib/config-machine-keys.js +0 -21
- package/dist/lib/pty-client.d.ts +0 -49
- package/dist/lib/pty-client.js +0 -315
- package/dist/lib/pty-server.d.ts +0 -59
- package/dist/lib/pty-server.js +0 -653
package/dist/lib/pty-server.js
DELETED
|
@@ -1,653 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PTY Sidecar Server
|
|
3
|
-
*
|
|
4
|
-
* Lightweight unix socket server that manages persistent PTY sessions.
|
|
5
|
-
* Started as a detached process by `agents pty` commands. Sessions survive
|
|
6
|
-
* across multiple CLI invocations. Each session holds a real PTY (via node-pty)
|
|
7
|
-
* and a headless terminal emulator (via @xterm/headless) for screen rendering.
|
|
8
|
-
*
|
|
9
|
-
* Protocol: newline-delimited JSON over ~/.agents/.system/pty.sock
|
|
10
|
-
*/
|
|
11
|
-
import * as net from 'net';
|
|
12
|
-
import * as fs from 'fs';
|
|
13
|
-
import * as path from 'path';
|
|
14
|
-
import * as crypto from 'crypto';
|
|
15
|
-
import { fileURLToPath } from 'url';
|
|
16
|
-
import { getPtyDir as getPtyDirRoot } from './state.js';
|
|
17
|
-
import { isAlive, captureProcessStartTime } from './platform/index.js';
|
|
18
|
-
// Re-exported for the existing importers of this module; the implementation is
|
|
19
|
-
// in platform/process.ts, shared with teams/agents.ts so the two cannot drift.
|
|
20
|
-
export { captureProcessStartTime };
|
|
21
|
-
// --- Constants ---
|
|
22
|
-
const IS_WINDOWS = process.platform === 'win32';
|
|
23
|
-
const SENTINEL = '__AGENTS_PTY_DONE__';
|
|
24
|
-
const SOCKET_NAME = 'pty.sock';
|
|
25
|
-
const PID_FILE = 'pty.pid';
|
|
26
|
-
const LOG_FILE = 'logs.jsonl';
|
|
27
|
-
const LOG_MAX_SIZE = 5 * 1024 * 1024; // 5 MB
|
|
28
|
-
const LOG_ROTATE_COUNT = 3;
|
|
29
|
-
const SESSION_IDLE_MS = 30 * 60 * 1000; // 30 min
|
|
30
|
-
const SERVER_IDLE_MS = 60 * 60 * 1000; // 1 hour
|
|
31
|
-
// --- Path helpers ---
|
|
32
|
-
/** Env vars forwarded into PTY sessions. Excludes API tokens, cloud creds, etc. */
|
|
33
|
-
const PTY_ENV_ALLOWLIST = [
|
|
34
|
-
'HOME', 'PATH', 'SHELL', 'USER', 'LOGNAME',
|
|
35
|
-
'TERM', 'TERM_PROGRAM', 'TERM_PROGRAM_VERSION', 'COLORTERM',
|
|
36
|
-
'LANG', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES', 'TZ',
|
|
37
|
-
'TMPDIR',
|
|
38
|
-
'XDG_RUNTIME_DIR', 'XDG_CONFIG_HOME', 'XDG_DATA_HOME', 'XDG_CACHE_HOME',
|
|
39
|
-
'NODE_PATH', 'NVM_DIR', 'BUN_INSTALL',
|
|
40
|
-
'EDITOR', 'VISUAL', 'PAGER', 'LESS',
|
|
41
|
-
'NO_COLOR', 'FORCE_COLOR',
|
|
42
|
-
];
|
|
43
|
-
/**
|
|
44
|
-
* Windows allowlist. cmd.exe / PowerShell refuse to start (or misbehave) without
|
|
45
|
-
* SystemRoot, ComSpec, PATHEXT and the USERPROFILE/APPDATA family, so a Unix-style
|
|
46
|
-
* allowlist would spawn a broken shell. PATH/TERM/color/NODE vars are shared with
|
|
47
|
-
* the Unix list; the rest are Windows-specific.
|
|
48
|
-
*/
|
|
49
|
-
const PTY_ENV_ALLOWLIST_WIN = [
|
|
50
|
-
'SystemRoot', 'SystemDrive', 'windir', 'ComSpec', 'PATH', 'PATHEXT',
|
|
51
|
-
'TEMP', 'TMP', 'USERPROFILE', 'HOMEDRIVE', 'HOMEPATH', 'HOME',
|
|
52
|
-
'APPDATA', 'LOCALAPPDATA', 'PROGRAMFILES', 'PROGRAMDATA',
|
|
53
|
-
'USERNAME', 'USERDOMAIN', 'COMPUTERNAME', 'OS',
|
|
54
|
-
'PROCESSOR_ARCHITECTURE', 'NUMBER_OF_PROCESSORS',
|
|
55
|
-
'TERM', 'COLORTERM', 'NO_COLOR', 'FORCE_COLOR',
|
|
56
|
-
'NODE_PATH', 'BUN_INSTALL',
|
|
57
|
-
];
|
|
58
|
-
function buildPtyEnv() {
|
|
59
|
-
const env = {};
|
|
60
|
-
const allowlist = IS_WINDOWS ? PTY_ENV_ALLOWLIST_WIN : PTY_ENV_ALLOWLIST;
|
|
61
|
-
for (const key of allowlist) {
|
|
62
|
-
const v = process.env[key];
|
|
63
|
-
if (v !== undefined)
|
|
64
|
-
env[key] = v;
|
|
65
|
-
}
|
|
66
|
-
return env;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Wrap a user command so a `__SENTINEL__:<exit>` line is printed after it
|
|
70
|
-
* finishes — that line drives completion detection in the exec/read flow.
|
|
71
|
-
* The separator and exit-code variable are shell-family specific:
|
|
72
|
-
* POSIX sh/zsh/bash : `cmd; echo "S:$?"`
|
|
73
|
-
* PowerShell : `cmd; echo "S:$LASTEXITCODE"`
|
|
74
|
-
* cmd.exe : `cmd & echo S:%errorlevel%` (`&` always runs the echo)
|
|
75
|
-
* Only the completion marker matters; the numeric exit code is informational
|
|
76
|
-
* (the authoritative code comes from node-pty's onExit).
|
|
77
|
-
*/
|
|
78
|
-
export function buildSentinelCommand(shell, command) {
|
|
79
|
-
// Split on both separators: a Windows shell path (`C:\…\cmd.exe`) must be
|
|
80
|
-
// recognized even when this code runs under POSIX path.basename, which does
|
|
81
|
-
// not treat `\` as a separator.
|
|
82
|
-
const name = (shell.split(/[\\/]/).pop() || shell).toLowerCase();
|
|
83
|
-
if (name === 'cmd.exe' || name === 'cmd') {
|
|
84
|
-
return `${command} & echo ${SENTINEL}:%errorlevel%`;
|
|
85
|
-
}
|
|
86
|
-
if (name === 'powershell.exe' || name === 'powershell' || name === 'pwsh.exe' || name === 'pwsh') {
|
|
87
|
-
return `${command}; echo "${SENTINEL}:$LASTEXITCODE"`;
|
|
88
|
-
}
|
|
89
|
-
return `${command}; echo "${SENTINEL}:$?"`;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Turn a native-binding load failure into an actionable, platform-aware message.
|
|
93
|
-
*
|
|
94
|
-
* The binding is `@homebridge/node-pty-prebuilt-multiarch`'s `pty.node`. On Linux
|
|
95
|
-
* it is baked into the npm tarball and always present; on macOS/Windows it is
|
|
96
|
-
* fetched per host + Node ABI at install time by the package's `prebuild-install`
|
|
97
|
-
* postinstall. The common failure is a Node runtime whose ABI has no published
|
|
98
|
-
* prebuild (the PHNX-2740 darwin-arm64 case): `prebuild-install` finds nothing,
|
|
99
|
-
* the build-from-source fallback also fails, and the loader throws a bare
|
|
100
|
-
* `Cannot find module '.../pty.node'` / MODULE_NOT_FOUND with no clue what to do.
|
|
101
|
-
*
|
|
102
|
-
* Pure (returns the lines) so it can be unit-tested without spawning the server.
|
|
103
|
-
*/
|
|
104
|
-
export function describeNativePtyLoadFailure(err) {
|
|
105
|
-
const detail = err instanceof Error ? (err.stack || err.message) : String(err);
|
|
106
|
-
const abi = process.versions.modules;
|
|
107
|
-
const nodeVersion = process.version;
|
|
108
|
-
const platform = `${process.platform}-${process.arch}`;
|
|
109
|
-
const lines = [
|
|
110
|
-
`agents pty could not load its native terminal binding (@homebridge/node-pty-prebuilt-multiarch).`,
|
|
111
|
-
` platform: ${platform} node: ${nodeVersion} (ABI ${abi})`,
|
|
112
|
-
``,
|
|
113
|
-
`The prebuilt binary for this platform + Node ABI is missing. On macOS/Windows`,
|
|
114
|
-
`it is downloaded at install time; a Node version newer than any published`,
|
|
115
|
-
`prebuild, or an install that skipped the postinstall, leaves it absent.`,
|
|
116
|
-
``,
|
|
117
|
-
`Fix it by reinstalling so the native binding is fetched or built:`,
|
|
118
|
-
` npm rebuild @homebridge/node-pty-prebuilt-multiarch # rebuild for this Node`,
|
|
119
|
-
` # or reinstall the CLI: npm i -g @phnx-labs/agents-cli`,
|
|
120
|
-
`If your Node (ABI ${abi}) is newer than the shipped prebuilds, install an LTS`,
|
|
121
|
-
`Node and retry, or ensure a C++ toolchain is present for the source build.`,
|
|
122
|
-
``,
|
|
123
|
-
`Underlying error:`,
|
|
124
|
-
...detail.split('\n').map(l => ` ${l}`),
|
|
125
|
-
];
|
|
126
|
-
return lines;
|
|
127
|
-
}
|
|
128
|
-
/** Get the PTY helper directory, creating it if needed. */
|
|
129
|
-
function getPtyDir() {
|
|
130
|
-
const dir = getPtyDirRoot();
|
|
131
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
132
|
-
return dir;
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Resolve the IPC endpoint for a given platform + PTY scratch dir. Pure so both
|
|
136
|
-
* branches are testable without stubbing process.platform.
|
|
137
|
-
*
|
|
138
|
-
* Unix: an AF_UNIX socket file inside the scratch dir.
|
|
139
|
-
* Windows: a named pipe (`\\.\pipe\…`). Named pipes are NOT filesystem objects,
|
|
140
|
-
* so the name is derived from a hash of the (per-user) scratch dir to keep it
|
|
141
|
-
* stable across invocations and isolated per user — and callers must never probe
|
|
142
|
-
* it with fs.existsSync (it always reports false). Both forms are accepted by
|
|
143
|
-
* net.createServer/createConnection.
|
|
144
|
-
*/
|
|
145
|
-
export function derivePtyEndpoint(platform, ptyDir) {
|
|
146
|
-
if (platform === 'win32') {
|
|
147
|
-
const hash = crypto.createHash('sha1').update(ptyDir).digest('hex').slice(0, 16);
|
|
148
|
-
return `\\\\.\\pipe\\agents-pty-${hash}`;
|
|
149
|
-
}
|
|
150
|
-
return path.join(ptyDir, SOCKET_NAME);
|
|
151
|
-
}
|
|
152
|
-
/** Get the IPC endpoint the PTY server listens on / clients connect to. */
|
|
153
|
-
export function getSocketPath() {
|
|
154
|
-
return derivePtyEndpoint(process.platform, getPtyDir());
|
|
155
|
-
}
|
|
156
|
-
/** Get the path to the PTY server PID file. */
|
|
157
|
-
export function getPtyPidPath() {
|
|
158
|
-
return path.join(getPtyDir(), PID_FILE);
|
|
159
|
-
}
|
|
160
|
-
/** Get the path to the PTY server log file. */
|
|
161
|
-
export function getPtyLogPath() {
|
|
162
|
-
const logDir = getPtyDir();
|
|
163
|
-
return path.join(logDir, LOG_FILE);
|
|
164
|
-
}
|
|
165
|
-
/** Check if the PTY server process is alive by probing the stored PID. */
|
|
166
|
-
export function isPtyServerRunning() {
|
|
167
|
-
const pidPath = getPtyPidPath();
|
|
168
|
-
if (!fs.existsSync(pidPath))
|
|
169
|
-
return false;
|
|
170
|
-
try {
|
|
171
|
-
const pid = parseInt(fs.readFileSync(pidPath, 'utf-8').trim(), 10);
|
|
172
|
-
if (isNaN(pid))
|
|
173
|
-
return false;
|
|
174
|
-
if (isAlive(pid))
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
catch {
|
|
178
|
-
// read failed — fall through and treat the pid file as stale
|
|
179
|
-
}
|
|
180
|
-
try {
|
|
181
|
-
fs.unlinkSync(pidPath);
|
|
182
|
-
}
|
|
183
|
-
catch { }
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
// --- Logging ---
|
|
187
|
-
function rotateLogsIfNeeded(logPath) {
|
|
188
|
-
try {
|
|
189
|
-
const stat = fs.statSync(logPath);
|
|
190
|
-
if (stat.size < LOG_MAX_SIZE)
|
|
191
|
-
return;
|
|
192
|
-
for (let i = LOG_ROTATE_COUNT - 1; i >= 1; i--) {
|
|
193
|
-
const older = `${logPath}.${i}`;
|
|
194
|
-
const newer = i === 1 ? logPath : `${logPath}.${i - 1}`;
|
|
195
|
-
if (fs.existsSync(newer)) {
|
|
196
|
-
fs.renameSync(newer, older);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
if (fs.existsSync(logPath)) {
|
|
200
|
-
fs.renameSync(logPath, `${logPath}.1`);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
catch { }
|
|
204
|
-
}
|
|
205
|
-
function log(level, message) {
|
|
206
|
-
const logPath = getPtyLogPath();
|
|
207
|
-
rotateLogsIfNeeded(logPath);
|
|
208
|
-
const entry = { ts: new Date().toISOString(), level, message };
|
|
209
|
-
try {
|
|
210
|
-
fs.appendFileSync(logPath, JSON.stringify(entry) + '\n', 'utf-8');
|
|
211
|
-
}
|
|
212
|
-
catch { }
|
|
213
|
-
}
|
|
214
|
-
// --- Server ---
|
|
215
|
-
/** Start the PTY sidecar server, listening on the unix socket for JSON requests. */
|
|
216
|
-
export async function runPtyServer() {
|
|
217
|
-
// Dynamic imports for optional native deps
|
|
218
|
-
let nodePty;
|
|
219
|
-
let XtermTerminal;
|
|
220
|
-
try {
|
|
221
|
-
// The Homebridge multiarch fork of node-pty (API-identical to the 1.x N-API
|
|
222
|
-
// upstream). Its npm tarball BAKES IN the Linux prebuilds (glibc + musl, every
|
|
223
|
-
// arch + Node ABI), so Linux never needs a compiler or a network fetch. The
|
|
224
|
-
// darwin-arm64 / win32 binaries are NOT in the tarball — they are downloaded
|
|
225
|
-
// per host+Node-ABI at install time by the package's own `prebuild-install`
|
|
226
|
-
// postinstall (gated by bun's `trustedDependencies`). That fetch fails when the
|
|
227
|
-
// running Node ABI is newer than any published prebuild (e.g. 0.13.1 shipped no
|
|
228
|
-
// darwin-arm64 above Node 24 / ABI 137, so Node 25/26 fell through to a
|
|
229
|
-
// build-from-source that also failed — PHNX-2740), leaving a raw MODULE_NOT_FOUND.
|
|
230
|
-
// Fail loud with the platform/ABI and a concrete remediation instead.
|
|
231
|
-
nodePty = await import('@homebridge/node-pty-prebuilt-multiarch');
|
|
232
|
-
// Handle ESM default export
|
|
233
|
-
if (nodePty.default?.spawn)
|
|
234
|
-
nodePty = nodePty.default;
|
|
235
|
-
// Ensure spawn-helper is executable (bun install doesn't set +x on prebuilds)
|
|
236
|
-
try {
|
|
237
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
238
|
-
const ptyBase = path.resolve(__dirname, '..', '..', 'node_modules', '@homebridge', 'node-pty-prebuilt-multiarch');
|
|
239
|
-
const helpers = [
|
|
240
|
-
path.join(ptyBase, 'prebuilds', `${process.platform}-${process.arch}`, 'spawn-helper'),
|
|
241
|
-
path.join(ptyBase, 'build', 'Release', 'spawn-helper'),
|
|
242
|
-
];
|
|
243
|
-
for (const h of helpers) {
|
|
244
|
-
if (fs.existsSync(h)) {
|
|
245
|
-
fs.chmodSync(h, 0o755);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
catch { }
|
|
250
|
-
}
|
|
251
|
-
catch (err) {
|
|
252
|
-
for (const line of describeNativePtyLoadFailure(err))
|
|
253
|
-
console.error(line);
|
|
254
|
-
process.exit(1);
|
|
255
|
-
}
|
|
256
|
-
try {
|
|
257
|
-
const xterm = await import('@xterm/headless');
|
|
258
|
-
// Handle ESM default export wrapping
|
|
259
|
-
XtermTerminal = xterm.Terminal || xterm.default?.Terminal;
|
|
260
|
-
}
|
|
261
|
-
catch {
|
|
262
|
-
console.error('@xterm/headless is required for PTY support.');
|
|
263
|
-
console.error('Install: cd ' + '~/agents-cli && bun add @xterm/headless');
|
|
264
|
-
process.exit(1);
|
|
265
|
-
}
|
|
266
|
-
const sessions = new Map();
|
|
267
|
-
const socketPath = getSocketPath();
|
|
268
|
-
const pidPath = getPtyPidPath();
|
|
269
|
-
// Race resolution must happen BEFORE touching the socket file. Two clients
|
|
270
|
-
// racing ensureServer() in pty-client.ts can both observe
|
|
271
|
-
// isPtyServerRunning()=false and spawn parallel servers; without the
|
|
272
|
-
// O_EXCL claim below, the second spawn would unlink the first's socket
|
|
273
|
-
// inode and overwrite its PID file, orphaning the first server with its
|
|
274
|
-
// kernel socket binding intact but unreachable via the filesystem.
|
|
275
|
-
if (isPtyServerRunning()) {
|
|
276
|
-
log('INFO', 'PTY server already running; duplicate spawn exits cleanly');
|
|
277
|
-
process.exit(0);
|
|
278
|
-
}
|
|
279
|
-
try {
|
|
280
|
-
fs.writeFileSync(pidPath, String(process.pid), { flag: 'wx', encoding: 'utf-8' });
|
|
281
|
-
}
|
|
282
|
-
catch (err) {
|
|
283
|
-
if (err && err.code === 'EEXIST') {
|
|
284
|
-
log('INFO', 'PID slot claimed by a concurrent server; exiting cleanly');
|
|
285
|
-
process.exit(0);
|
|
286
|
-
}
|
|
287
|
-
throw err;
|
|
288
|
-
}
|
|
289
|
-
// We own the PID slot; ensure it's released on any exit path, not just SIGTERM/SIGINT.
|
|
290
|
-
process.on('exit', () => { try {
|
|
291
|
-
fs.unlinkSync(pidPath);
|
|
292
|
-
}
|
|
293
|
-
catch { } });
|
|
294
|
-
// Remove stale socket from a prior crashed server. Safe now that we hold the PID
|
|
295
|
-
// slot. Windows named pipes are not filesystem inodes — they vanish with their
|
|
296
|
-
// owning process, so there's nothing to unlink (and existsSync always reports false).
|
|
297
|
-
if (!IS_WINDOWS && fs.existsSync(socketPath)) {
|
|
298
|
-
try {
|
|
299
|
-
fs.unlinkSync(socketPath);
|
|
300
|
-
}
|
|
301
|
-
catch { }
|
|
302
|
-
}
|
|
303
|
-
let lastActivityTime = Date.now();
|
|
304
|
-
function generateId() {
|
|
305
|
-
return crypto.randomBytes(4).toString('hex');
|
|
306
|
-
}
|
|
307
|
-
function killSession(session) {
|
|
308
|
-
if (!session.exited) {
|
|
309
|
-
try {
|
|
310
|
-
session.pty.kill();
|
|
311
|
-
}
|
|
312
|
-
catch { }
|
|
313
|
-
session.exited = true;
|
|
314
|
-
}
|
|
315
|
-
if (session.terminal) {
|
|
316
|
-
try {
|
|
317
|
-
session.terminal.dispose();
|
|
318
|
-
}
|
|
319
|
-
catch { }
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
function getScreenLines(session) {
|
|
323
|
-
const lines = [];
|
|
324
|
-
const buf = session.terminal.buffer.active;
|
|
325
|
-
for (let y = 0; y < session.rows; y++) {
|
|
326
|
-
const line = buf.getLine(y);
|
|
327
|
-
const text = line ? line.translateToString(true) : '';
|
|
328
|
-
// Strip lines containing the sentinel pattern
|
|
329
|
-
if (text.includes(SENTINEL))
|
|
330
|
-
continue;
|
|
331
|
-
lines.push(text);
|
|
332
|
-
}
|
|
333
|
-
// Trim trailing empty lines
|
|
334
|
-
while (lines.length > 0 && lines[lines.length - 1] === '') {
|
|
335
|
-
lines.pop();
|
|
336
|
-
}
|
|
337
|
-
return lines;
|
|
338
|
-
}
|
|
339
|
-
// Session idle cleanup + server auto-exit
|
|
340
|
-
const cleanupInterval = setInterval(() => {
|
|
341
|
-
const now = Date.now();
|
|
342
|
-
for (const [id, session] of sessions) {
|
|
343
|
-
if (now - session.lastActivity > SESSION_IDLE_MS) {
|
|
344
|
-
log('INFO', `Cleaning up idle session ${id}`);
|
|
345
|
-
killSession(session);
|
|
346
|
-
sessions.delete(id);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
if (sessions.size === 0 && now - lastActivityTime > SERVER_IDLE_MS) {
|
|
350
|
-
log('INFO', 'No sessions, server idle timeout reached. Shutting down.');
|
|
351
|
-
shutdown();
|
|
352
|
-
}
|
|
353
|
-
}, 60_000);
|
|
354
|
-
// --- Request handlers ---
|
|
355
|
-
async function handleRequest(req) {
|
|
356
|
-
lastActivityTime = Date.now();
|
|
357
|
-
switch (req.action) {
|
|
358
|
-
case 'start': {
|
|
359
|
-
const rows = req.params?.rows || 24;
|
|
360
|
-
const cols = req.params?.cols || 120;
|
|
361
|
-
const shell = req.params?.shell
|
|
362
|
-
|| (IS_WINDOWS ? (process.env.ComSpec || 'powershell.exe') : (process.env.SHELL || 'zsh'));
|
|
363
|
-
const cwd = req.params?.cwd
|
|
364
|
-
|| (IS_WINDOWS ? (process.env.USERPROFILE || process.env.HOME || process.cwd()) : (process.env.HOME || '/'));
|
|
365
|
-
const id = generateId();
|
|
366
|
-
let ptyProcess;
|
|
367
|
-
try {
|
|
368
|
-
ptyProcess = nodePty.spawn(shell, [], {
|
|
369
|
-
name: 'xterm-256color',
|
|
370
|
-
cols,
|
|
371
|
-
rows,
|
|
372
|
-
cwd,
|
|
373
|
-
env: buildPtyEnv(),
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
catch (err) {
|
|
377
|
-
return { ok: false, error: `Failed to spawn PTY: ${err.message}` };
|
|
378
|
-
}
|
|
379
|
-
const terminal = new XtermTerminal({ rows, cols, allowProposedApi: true });
|
|
380
|
-
const session = {
|
|
381
|
-
id,
|
|
382
|
-
pty: ptyProcess,
|
|
383
|
-
terminal,
|
|
384
|
-
rows,
|
|
385
|
-
cols,
|
|
386
|
-
shell,
|
|
387
|
-
cwd,
|
|
388
|
-
pid: ptyProcess.pid,
|
|
389
|
-
startTime: captureProcessStartTime(ptyProcess.pid),
|
|
390
|
-
startedAt: Date.now(),
|
|
391
|
-
lastActivity: Date.now(),
|
|
392
|
-
pendingOutput: '',
|
|
393
|
-
appActive: false,
|
|
394
|
-
activeCommand: '',
|
|
395
|
-
exited: false,
|
|
396
|
-
exitCode: null,
|
|
397
|
-
};
|
|
398
|
-
ptyProcess.onData((data) => {
|
|
399
|
-
session.pendingOutput += data;
|
|
400
|
-
terminal.write(data);
|
|
401
|
-
session.lastActivity = Date.now();
|
|
402
|
-
// Check for sentinel to detect command completion
|
|
403
|
-
if (session.appActive && session.pendingOutput.includes(SENTINEL + ':')) {
|
|
404
|
-
session.appActive = false;
|
|
405
|
-
session.activeCommand = '';
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
ptyProcess.onExit(({ exitCode }) => {
|
|
409
|
-
session.exited = true;
|
|
410
|
-
session.exitCode = exitCode;
|
|
411
|
-
session.appActive = false;
|
|
412
|
-
});
|
|
413
|
-
// Wait for shell to initialize, then clear init output
|
|
414
|
-
await new Promise(r => setTimeout(r, 300));
|
|
415
|
-
session.pendingOutput = '';
|
|
416
|
-
sessions.set(id, session);
|
|
417
|
-
log('INFO', `Session started: ${id} (pid=${ptyProcess.pid}, shell=${shell}, ${cols}x${rows})`);
|
|
418
|
-
return { ok: true, id, pid: ptyProcess.pid, rows, cols, shell };
|
|
419
|
-
}
|
|
420
|
-
case 'exec': {
|
|
421
|
-
const session = sessions.get(req.id);
|
|
422
|
-
if (!session)
|
|
423
|
-
return { ok: false, error: `Session not found: ${req.id}` };
|
|
424
|
-
if (session.exited)
|
|
425
|
-
return { ok: false, error: 'Session has exited' };
|
|
426
|
-
if (session.appActive) {
|
|
427
|
-
return { ok: false, error: `Command already active: ${session.activeCommand}. Use write to interact or signal to interrupt.` };
|
|
428
|
-
}
|
|
429
|
-
const command = req.params?.command;
|
|
430
|
-
if (!command)
|
|
431
|
-
return { ok: false, error: 'command is required' };
|
|
432
|
-
session.appActive = true;
|
|
433
|
-
session.activeCommand = command;
|
|
434
|
-
session.pendingOutput = '';
|
|
435
|
-
// Windows conpty submits on CR; POSIX line discipline expects LF.
|
|
436
|
-
const submit = IS_WINDOWS ? '\r' : '\n';
|
|
437
|
-
session.pty.write(`${buildSentinelCommand(session.shell, command)}${submit}`);
|
|
438
|
-
session.lastActivity = Date.now();
|
|
439
|
-
return { ok: true, submitted: true };
|
|
440
|
-
}
|
|
441
|
-
case 'read': {
|
|
442
|
-
const session = sessions.get(req.id);
|
|
443
|
-
if (!session)
|
|
444
|
-
return { ok: false, error: `Session not found: ${req.id}` };
|
|
445
|
-
const waitMs = Math.min(Math.max(req.params?.ms || 100, 50), 5000);
|
|
446
|
-
// Wait for output to accumulate
|
|
447
|
-
if (session.pendingOutput.length === 0) {
|
|
448
|
-
await new Promise(r => setTimeout(r, waitMs));
|
|
449
|
-
}
|
|
450
|
-
const output = session.pendingOutput;
|
|
451
|
-
session.pendingOutput = '';
|
|
452
|
-
// Strip sentinel lines from output
|
|
453
|
-
const cleaned = output
|
|
454
|
-
.split('\n')
|
|
455
|
-
.filter(line => !line.includes(SENTINEL))
|
|
456
|
-
.join('\n');
|
|
457
|
-
return {
|
|
458
|
-
ok: true,
|
|
459
|
-
output: cleaned,
|
|
460
|
-
bytes: output.length,
|
|
461
|
-
app_active: session.appActive,
|
|
462
|
-
active_command: session.activeCommand || undefined,
|
|
463
|
-
exited: session.exited,
|
|
464
|
-
exit_code: session.exitCode,
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
case 'write': {
|
|
468
|
-
const session = sessions.get(req.id);
|
|
469
|
-
if (!session)
|
|
470
|
-
return { ok: false, error: `Session not found: ${req.id}` };
|
|
471
|
-
if (session.exited)
|
|
472
|
-
return { ok: false, error: 'Session has exited' };
|
|
473
|
-
let input = req.params?.input ?? '';
|
|
474
|
-
if (input === '')
|
|
475
|
-
input = '\n';
|
|
476
|
-
session.pty.write(input);
|
|
477
|
-
session.lastActivity = Date.now();
|
|
478
|
-
return { ok: true };
|
|
479
|
-
}
|
|
480
|
-
case 'screen': {
|
|
481
|
-
const session = sessions.get(req.id);
|
|
482
|
-
if (!session)
|
|
483
|
-
return { ok: false, error: `Session not found: ${req.id}` };
|
|
484
|
-
const lines = getScreenLines(session);
|
|
485
|
-
const buf = session.terminal.buffer.active;
|
|
486
|
-
return {
|
|
487
|
-
ok: true,
|
|
488
|
-
screen: lines.join('\n'),
|
|
489
|
-
rows: session.rows,
|
|
490
|
-
cols: session.cols,
|
|
491
|
-
cursor: { x: buf.cursorX, y: buf.cursorY },
|
|
492
|
-
app_active: session.appActive,
|
|
493
|
-
active_command: session.activeCommand || undefined,
|
|
494
|
-
exited: session.exited,
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
case 'signal': {
|
|
498
|
-
const session = sessions.get(req.id);
|
|
499
|
-
if (!session)
|
|
500
|
-
return { ok: false, error: `Session not found: ${req.id}` };
|
|
501
|
-
if (session.exited)
|
|
502
|
-
return { ok: false, error: 'Session has exited' };
|
|
503
|
-
const sig = (req.params?.signal || 'INT').toUpperCase();
|
|
504
|
-
if (!['INT', 'TERM', 'KILL', 'HUP'].includes(sig)) {
|
|
505
|
-
return { ok: false, error: `Unsupported signal: ${sig}` };
|
|
506
|
-
}
|
|
507
|
-
// Guard against PID reuse: confirm the PID is still owned by the
|
|
508
|
-
// process we spawned. If the start-time we captured at spawn no
|
|
509
|
-
// longer matches /proc or `ps`, treat the session as exited and
|
|
510
|
-
// refuse to signal — otherwise we'd kill an unrelated process that
|
|
511
|
-
// happens to have inherited this PID.
|
|
512
|
-
if (session.startTime !== null) {
|
|
513
|
-
const current = captureProcessStartTime(session.pid);
|
|
514
|
-
if (current === null || current !== session.startTime) {
|
|
515
|
-
session.exited = true;
|
|
516
|
-
return { ok: false, error: 'Session has exited' };
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
try {
|
|
520
|
-
// node-pty kill accepts signal number; use process.kill for named signals
|
|
521
|
-
process.kill(session.pid, `SIG${sig}`);
|
|
522
|
-
}
|
|
523
|
-
catch (err) {
|
|
524
|
-
return { ok: false, error: `Failed to send signal: ${err.message}` };
|
|
525
|
-
}
|
|
526
|
-
return { ok: true };
|
|
527
|
-
}
|
|
528
|
-
case 'resize': {
|
|
529
|
-
const session = sessions.get(req.id);
|
|
530
|
-
if (!session)
|
|
531
|
-
return { ok: false, error: `Session not found: ${req.id}` };
|
|
532
|
-
if (session.exited)
|
|
533
|
-
return { ok: false, error: 'Session has exited' };
|
|
534
|
-
const rows = req.params?.rows || session.rows;
|
|
535
|
-
const cols = req.params?.cols || session.cols;
|
|
536
|
-
session.pty.resize(cols, rows);
|
|
537
|
-
session.terminal.resize(cols, rows);
|
|
538
|
-
session.rows = rows;
|
|
539
|
-
session.cols = cols;
|
|
540
|
-
return { ok: true, rows, cols };
|
|
541
|
-
}
|
|
542
|
-
case 'list': {
|
|
543
|
-
const list = [];
|
|
544
|
-
for (const [, session] of sessions) {
|
|
545
|
-
list.push({
|
|
546
|
-
id: session.id,
|
|
547
|
-
pid: session.pid,
|
|
548
|
-
shell: session.shell,
|
|
549
|
-
cwd: session.cwd,
|
|
550
|
-
rows: session.rows,
|
|
551
|
-
cols: session.cols,
|
|
552
|
-
started_at: session.startedAt,
|
|
553
|
-
last_activity: session.lastActivity,
|
|
554
|
-
app_active: session.appActive,
|
|
555
|
-
active_command: session.activeCommand || undefined,
|
|
556
|
-
exited: session.exited,
|
|
557
|
-
exit_code: session.exitCode,
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
return { ok: true, sessions: list };
|
|
561
|
-
}
|
|
562
|
-
case 'stop': {
|
|
563
|
-
const session = sessions.get(req.id);
|
|
564
|
-
if (!session)
|
|
565
|
-
return { ok: false, error: `Session not found: ${req.id}` };
|
|
566
|
-
killSession(session);
|
|
567
|
-
sessions.delete(req.id);
|
|
568
|
-
log('INFO', `Session stopped: ${req.id}`);
|
|
569
|
-
return { ok: true };
|
|
570
|
-
}
|
|
571
|
-
case 'ping': {
|
|
572
|
-
return { ok: true, sessions: sessions.size, pid: process.pid };
|
|
573
|
-
}
|
|
574
|
-
default:
|
|
575
|
-
return { ok: false, error: `Unknown action: ${req.action}` };
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
// --- Socket server ---
|
|
579
|
-
const server = net.createServer((conn) => {
|
|
580
|
-
let buf = '';
|
|
581
|
-
conn.on('data', async (chunk) => {
|
|
582
|
-
buf += chunk.toString();
|
|
583
|
-
const nlIndex = buf.indexOf('\n');
|
|
584
|
-
if (nlIndex === -1)
|
|
585
|
-
return;
|
|
586
|
-
const line = buf.slice(0, nlIndex);
|
|
587
|
-
buf = '';
|
|
588
|
-
try {
|
|
589
|
-
const req = JSON.parse(line);
|
|
590
|
-
const res = await handleRequest(req);
|
|
591
|
-
conn.write(JSON.stringify(res) + '\n');
|
|
592
|
-
}
|
|
593
|
-
catch (err) {
|
|
594
|
-
conn.write(JSON.stringify({ ok: false, error: err.message || String(err) }) + '\n');
|
|
595
|
-
}
|
|
596
|
-
conn.end();
|
|
597
|
-
});
|
|
598
|
-
conn.on('error', () => { });
|
|
599
|
-
});
|
|
600
|
-
// Lock down the PTY scratch dir before opening the socket — without this,
|
|
601
|
-
// any local user with execute on the parent dir could connect to the socket
|
|
602
|
-
// during the listen()-to-chmod() window. macOS BSD AF_UNIX semantics make
|
|
603
|
-
// socket mode advisory only, so the parent dir is the real boundary.
|
|
604
|
-
//
|
|
605
|
-
// On Windows the transport is a named pipe, not a filesystem inode: chmod/umask
|
|
606
|
-
// are no-ops (and umask throws in some Node builds), and pipe ACLs default to
|
|
607
|
-
// the creating user. So we skip the Unix hardening entirely there.
|
|
608
|
-
const agentsDir = getPtyDirRoot();
|
|
609
|
-
fs.mkdirSync(agentsDir, { recursive: true });
|
|
610
|
-
if (!IS_WINDOWS) {
|
|
611
|
-
fs.chmodSync(agentsDir, 0o700);
|
|
612
|
-
// umask covers any inherited group/other bits while listen() is creating
|
|
613
|
-
// the socket inode — it only matters for the unobservable instant before
|
|
614
|
-
// we can chmod the inode itself.
|
|
615
|
-
process.umask(0o077);
|
|
616
|
-
}
|
|
617
|
-
await new Promise((resolve) => {
|
|
618
|
-
server.listen(socketPath, () => resolve());
|
|
619
|
-
});
|
|
620
|
-
// Surface chmod failures: a 0o600 socket is a load-bearing security
|
|
621
|
-
// assumption, not a nice-to-have. If we can't lock it down, refuse to
|
|
622
|
-
// start so the caller learns immediately. (No-op on Windows named pipes.)
|
|
623
|
-
if (!IS_WINDOWS) {
|
|
624
|
-
fs.chmodSync(socketPath, 0o600);
|
|
625
|
-
}
|
|
626
|
-
log('INFO', `PTY server started (PID: ${process.pid}, socket: ${socketPath})`);
|
|
627
|
-
// Shutdown handler
|
|
628
|
-
function shutdown() {
|
|
629
|
-
log('INFO', 'PTY server shutting down');
|
|
630
|
-
for (const session of sessions.values()) {
|
|
631
|
-
killSession(session);
|
|
632
|
-
}
|
|
633
|
-
sessions.clear();
|
|
634
|
-
clearInterval(cleanupInterval);
|
|
635
|
-
server.close();
|
|
636
|
-
// Named pipes are reclaimed by the OS on close; only Unix sockets leave a file.
|
|
637
|
-
if (!IS_WINDOWS) {
|
|
638
|
-
try {
|
|
639
|
-
fs.unlinkSync(socketPath);
|
|
640
|
-
}
|
|
641
|
-
catch { }
|
|
642
|
-
}
|
|
643
|
-
try {
|
|
644
|
-
fs.unlinkSync(getPtyPidPath());
|
|
645
|
-
}
|
|
646
|
-
catch { }
|
|
647
|
-
process.exit(0);
|
|
648
|
-
}
|
|
649
|
-
process.on('SIGTERM', shutdown);
|
|
650
|
-
process.on('SIGINT', shutdown);
|
|
651
|
-
// Keep alive
|
|
652
|
-
await new Promise(() => { });
|
|
653
|
-
}
|