@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/feed/feed.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export interface BlockQuestion {
|
|
|
7
7
|
header?: string;
|
|
8
8
|
options?: BlockOption[];
|
|
9
9
|
multiSelect?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Preceding report/explanation for a prose question — the context that came
|
|
12
|
+
* BEFORE the trailing ask, Markdown + newlines preserved (PHNX-3999). The
|
|
13
|
+
* operator UI renders it under the question; absent for a structured question.
|
|
14
|
+
*/
|
|
15
|
+
context?: string;
|
|
10
16
|
}
|
|
11
17
|
export interface MessageReceipt {
|
|
12
18
|
/** The message id this receipt describes. */
|
|
@@ -230,8 +236,6 @@ export declare function deriveBlockState(block: OpenBlock): AttentionState;
|
|
|
230
236
|
export declare function recordResolution(resolution: AttentionResolution, root?: string): void;
|
|
231
237
|
/** Read the latest resolution tombstone for a block, if one exists. */
|
|
232
238
|
export declare function readResolution(blockId: string, root?: string): AttentionResolution | undefined;
|
|
233
|
-
/** Read every resolution tombstone. Returns them sorted by stable block filename. */
|
|
234
|
-
export declare function listResolutions(root?: string): AttentionResolution[];
|
|
235
239
|
/**
|
|
236
240
|
* Stable block id for a session. One block per session -- a new question
|
|
237
241
|
* replaces the previous one (the agent can only ask one question at a time).
|
|
@@ -239,7 +243,7 @@ export declare function listResolutions(root?: string): AttentionResolution[];
|
|
|
239
243
|
export declare function blockIdForSession(sessionId: string): string;
|
|
240
244
|
/** Read one block record. Returns undefined when missing or corrupt. */
|
|
241
245
|
export declare function readBlock(blockId: string, root?: string): OpenBlock | undefined;
|
|
242
|
-
|
|
246
|
+
type RecordAnswerResult = {
|
|
243
247
|
ok: true;
|
|
244
248
|
} | {
|
|
245
249
|
ok: false;
|
|
@@ -292,10 +296,6 @@ export declare function recordParked(blockId: string, root?: string): void;
|
|
|
292
296
|
export declare function recordDefaulted(blockId: string, root?: string): void;
|
|
293
297
|
/** Mark that an urgent block was paged to the phone. */
|
|
294
298
|
export declare function recordNotified(blockId: string, root?: string): void;
|
|
295
|
-
/** Convenience: record that a terminal answer closed the block. */
|
|
296
|
-
export declare function recordTerminalAnswer(blockId: string, root?: string): void;
|
|
297
|
-
/** Remove answered marker and receipts for a block (used by block removal/GC). */
|
|
298
|
-
export declare function clearBlockLifecycle(blockId: string, root?: string): void;
|
|
299
299
|
/** Identity of the agent declaring a block — the subset of `PostIdentity` it needs. */
|
|
300
300
|
export interface DeclaringAgent {
|
|
301
301
|
sessionId: string;
|
|
@@ -304,7 +304,7 @@ export interface DeclaringAgent {
|
|
|
304
304
|
runtime: string;
|
|
305
305
|
cwd?: string;
|
|
306
306
|
}
|
|
307
|
-
|
|
307
|
+
interface DeclareBlockInput {
|
|
308
308
|
/** What the agent needs from the user, front-loaded. */
|
|
309
309
|
text: string;
|
|
310
310
|
/** Answerable choices, if the ask is a pick-one. */
|
|
@@ -347,40 +347,6 @@ export declare function removeBlock(blockId: string, root?: string): boolean;
|
|
|
347
347
|
* CLI-writable user hooks dir without a separate file in the npm tarball.
|
|
348
348
|
*/
|
|
349
349
|
export declare const FEED_PUBLISH_HOOK_SCRIPT = "#!/usr/bin/env python3\n\"\"\"Publish and clear open-block records for `agents feed`.\n\nThe manifest invokes this script for top-level AskUserQuestion calls, waiting\nnotifications, question answers, and session lifecycle events. One atomic file\nper session means a new block replaces the previous block. Answer/resume/stop\nevents remove it so `agents feed` only lists decisions that are still open.\n\nSub-agent gate: when the PreToolUse payload carries `agent_type`, this is a\nTask/Agent subagent -- skip. Only the top-level agent publishes. Verified on\nClaude Code 2.1.170 (2026-07).\n\nFail-open: ANY error is swallowed so a feed hiccup never blocks a tool call.\n\"\"\"\nimport os\nimport sys\nimport json\nimport re\nimport socket\nimport tempfile\nfrom datetime import datetime, timezone\n\n# Notification subtypes that mean something is PENDING. Claude's idle_prompt is\n# deliberately absent: it fires a minute after the turn ended with the operator\n# idle, which is a finished turn, not a request -- publishing it put an\n# Approve/Deny banner on a session that had already answered \"pong\" (PHNX-3999).\nWAITING_NOTIFICATION_TYPES = {\n \"permission_prompt\",\n \"elicitation_dialog\",\n}\nCLEAR_EVENTS = {\n \"PostToolUse\",\n \"Stop\",\n \"SessionEnd\",\n}\n# Codex emits a PermissionRequest event (not Claude's Notification) when it\n# blocks on an approval prompt. Claude never fires PermissionRequest, so the\n# same script handles both: PermissionRequest maps to an approval-class block\n# with a high cost-of-delay so 'agents feed --dispatch' pages it as urgent.\n\n\ndef read_json(path):\n try:\n with open(path) as f:\n return json.load(f)\n except Exception:\n return None\n\n\ndef write_json(path, value):\n dir_name = os.path.dirname(path)\n os.makedirs(dir_name, exist_ok=True)\n fd, tmp = tempfile.mkstemp(dir=dir_name, suffix=\".tmp\")\n try:\n with os.fdopen(fd, \"w\") as f:\n json.dump(value, f, indent=2)\n os.replace(tmp, path)\n except Exception:\n try:\n os.unlink(tmp)\n except Exception:\n pass\n\n\ndef project_from_cwd(cwd):\n \"\"\"Basename of cwd, with worktree paths resolved to their repo name.\"\"\"\n if not cwd:\n return None\n norm = cwd.replace(\"\\\\\", \"/\").rstrip(\"/\")\n if not norm:\n return None\n marker = \"/.agents/worktrees/\"\n idx = norm.find(marker)\n if idx > 0:\n repo_path = norm[:idx]\n base = repo_path[repo_path.rfind(\"/\") + 1:]\n if base:\n return base\n base = norm[norm.rfind(\"/\") + 1:]\n return base or None\n\n\ndef main():\n raw = sys.stdin.read()\n try:\n payload = json.loads(raw) if raw.strip() else {}\n except Exception:\n return\n\n # Sub-agent gate.\n if payload.get(\"agent_type\"):\n return\n\n session_id = payload.get(\"session_id\", \"\")\n if not session_id:\n return\n\n safe_session_id = re.sub(r\"[^A-Za-z0-9._-]\", \"-\", session_id)\n block_id = f\"block-{safe_session_id}\"\n home = os.environ.get(\"HOME\") or os.path.expanduser(\"~\")\n feed_dir = os.path.join(home, \".agents\", \".history\", \"feed\")\n answered_dir = os.path.join(feed_dir, \"answered\")\n asks_dir = os.path.join(feed_dir, \"asks\")\n target = os.path.join(feed_dir, f\"{block_id}.json\")\n hook_event = payload.get(\"hook_event_name\", \"PreToolUse\")\n\n if hook_event in CLEAR_EVENTS:\n # A declared block (`agents feed post --blocked`) is the agent explicitly\n # saying it is stuck. Unlike a question/notification/approval block -- which\n # tracks an in-flight harness prompt that a lifecycle event resolves -- a\n # declared block stays open until it is actually ANSWERED. So while it is\n # still UNANSWERED, Stop/SessionEnd/PostToolUse must never silently drop it:\n # otherwise the needs-you record vanishes the moment the agent parks the block\n # and its turn ends -- exactly when the owner still needs to see and answer it.\n # Once it IS answered (an answered marker exists), it clears like any other\n # block by falling through below -- which frees that marker too, so a later\n # `--blocked` in the same session is not falsely locked as already-answered\n # (recordAnswer creates the marker with O_EXCL).\n try:\n with open(target) as existing_file:\n existing = json.load(existing_file)\n answered = os.path.exists(os.path.join(answered_dir, f\"{block_id}.json\"))\n if existing.get(\"kind\") == \"declared\" and not answered:\n return\n except Exception:\n pass\n # A matcher-less PostToolUse clear (registered for Codex so an approved\n # tool clears its approval card) must NOT wipe an open AskUserQuestion\n # while an unrelated tool runs mid-question -- those are cleared only by\n # the AskUserQuestion-matched PostToolUse. So on PostToolUse, keep a\n # 'question' block; approval/notification blocks clear once the tool runs.\n if hook_event == \"PostToolUse\":\n try:\n with open(target) as existing_file:\n existing = json.load(existing_file)\n if existing.get(\"kind\") == \"question\" and payload.get(\"tool_name\") != \"AskUserQuestion\":\n return\n except Exception:\n pass\n try:\n os.unlink(target)\n except FileNotFoundError:\n pass\n except Exception:\n pass\n # Also clear the answered marker so a future question for this session\n # is not permanently locked.\n try:\n os.unlink(os.path.join(answered_dir, f\"{block_id}.json\"))\n except FileNotFoundError:\n pass\n except Exception:\n pass\n return\n\n # Terminal answers (human typed in the TUI) record an answered marker and\n # remove the block file so the feed stops showing it within one poll cycle.\n # The marker stays behind so a concurrent surface cannot double-answer.\n # A resolution tombstone is written BEFORE unlink (matching TS recordAnswer)\n # so a stale lifecycle re-read cannot resurrect this generation.\n if hook_event == \"UserPromptSubmit\":\n os.makedirs(answered_dir, exist_ok=True)\n marker = os.path.join(answered_dir, f\"{block_id}.json\")\n now_iso = datetime.now(timezone.utc).isoformat()\n try:\n fd = os.open(marker, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)\n record = {\n \"answeredAt\": now_iso,\n \"answeredFrom\": \"terminal\",\n }\n with os.fdopen(fd, \"w\") as f:\n json.dump(record, f, indent=2)\n except FileExistsError:\n pass\n except Exception:\n pass\n # Tombstone first, then drop the open-block view. A missing/corrupt\n # block means there is nothing to resolve; fail open.\n existing = read_json(target)\n if isinstance(existing, dict):\n generation = existing.get(\"generation\") or existing.get(\"ts\")\n if generation:\n tombstone = {\n \"blockId\": block_id,\n \"generation\": generation,\n \"resolvedAt\": now_iso,\n \"reason\": \"answered\",\n }\n source_cursor = existing.get(\"sourceCursor\")\n if source_cursor:\n tombstone[\"sourceCursor\"] = source_cursor\n write_json(\n os.path.join(feed_dir, \"resolutions\", f\"{block_id}.json\"),\n tombstone,\n )\n # Remove the visible block so the feed drops the answered question.\n try:\n os.unlink(target)\n except FileNotFoundError:\n pass\n except Exception:\n pass\n return\n\n notification_type = None\n codex_approval = False\n if hook_event == \"Notification\":\n notification_type = payload.get(\"notification_type\", \"\")\n if notification_type not in WAITING_NOTIFICATION_TYPES:\n return\n # Claude emits a generic permission notification after presenting an\n # AskUserQuestion. Keep the structured questions and options already\n # published for this session instead of replacing them with that less\n # useful notification text.\n try:\n with open(target) as existing_file:\n existing = json.load(existing_file)\n if existing.get(\"kind\") == \"question\":\n return\n except Exception:\n pass\n message = payload.get(\"message\", \"\")\n if not message:\n return\n normalized_questions = [{\n \"text\": message,\n \"header\": payload.get(\"title\") or notification_type.replace(\"_\", \" \").title(),\n \"multiSelect\": False,\n }]\n kind = \"notification\"\n elif hook_event == \"PermissionRequest\":\n # Codex approval prompt. The payload mirrors PreToolUse (tool_name,\n # tool_input) but carries no questions -- Codex is asking to run a tool,\n # not asking the operator a multiple-choice question. Publish it as a\n # notification-kind approval block naming the tool so the feed and the\n # phone notifier can surface it, and so AGI EXT can bridge\n # it to a VS Code notification.\n tool_name = payload.get(\"tool_name\") or \"a tool\"\n tool_input = payload.get(\"tool_input\", {})\n command = \"\"\n if isinstance(tool_input, dict):\n command = (\n tool_input.get(\"command\")\n or tool_input.get(\"cmd\")\n or tool_input.get(\"path\")\n or \"\"\n )\n if isinstance(command, list):\n command = \" \".join(str(c) for c in command)\n detail = f\": {command}\" if command else \"\"\n normalized_questions = [{\n \"text\": f\"Codex needs approval to run {tool_name}{detail}\",\n \"header\": \"Approval needed\",\n \"multiSelect\": False,\n }]\n kind = \"notification\"\n notification_type = \"permission_prompt\"\n codex_approval = True\n else:\n tool_input = payload.get(\"tool_input\", {})\n questions = tool_input.get(\"questions\", [])\n if not questions:\n return\n normalized_questions = []\n for q in questions:\n if not isinstance(q, dict):\n continue\n question = {\n \"text\": q.get(\"question\", q.get(\"header\", \"\")),\n \"header\": q.get(\"header\"),\n \"multiSelect\": q.get(\"multiSelect\", False),\n }\n raw_opts = q.get(\"options\", [])\n if raw_opts:\n question[\"options\"] = [\n {\"label\": o.get(\"label\", \"\"), \"description\": o.get(\"description\")}\n for o in raw_opts\n if isinstance(o, dict)\n ]\n normalized_questions.append(question)\n if not normalized_questions:\n return\n kind = \"question\"\n\n # Identity from env (set by agents-cli at spawn).\n mailbox_id = os.path.basename(\n os.environ.get(\"AGENTS_MAILBOX_DIR\", \"\").rstrip(\"/\")\n ) or session_id\n\n now = datetime.now(timezone.utc)\n now_iso = now.isoformat()\n now_ms = int(now.timestamp() * 1000)\n stats_path = os.path.join(asks_dir, f\"{safe_session_id}.json\")\n stats = read_json(stats_path) or {}\n recent = stats.get(\"recentAskTimestamps\") if isinstance(stats, dict) else []\n if not isinstance(recent, list):\n recent = []\n recent.append(now_iso)\n # Keep enough history for rolling one-hour needy detection without unbounded\n # per-session files. The TypeScript reader applies the exact time window.\n recent = recent[-200:]\n write_json(stats_path, {\n \"sessionId\": session_id,\n \"mailboxId\": mailbox_id,\n \"firstAskAt\": stats.get(\"firstAskAt\") or now_iso,\n \"lastAskAt\": now_iso,\n \"totalAskCount\": int(stats.get(\"totalAskCount\") or 0) + 1,\n \"recentAskTimestamps\": recent,\n })\n\n hostname = os.environ.get(\"AGENTS_SYNC_MACHINE_ID\") or socket.gethostname()\n host = hostname.split(\".\")[0].strip().lower()\n host = re.sub(r\"[^a-z0-9_-]\", \"-\", host) or \"unknown\"\n\n runtime = os.environ.get(\"AGENTS_RUNTIME\", \"headless\")\n cwd = payload.get(\"cwd\") or os.environ.get(\"AGENTS_CWD\")\n project = project_from_cwd(cwd)\n\n block = {\n \"blockId\": block_id,\n \"sessionId\": session_id,\n \"mailboxId\": mailbox_id,\n \"host\": host,\n \"runtime\": runtime,\n \"ts\": now_iso,\n # Write-time cursor so a new generation is not suppressed when\n # session.lastActivityMs is unresolvable (cloud / remote / index-lag).\n \"sourceCursor\": {\"lastActivityMs\": now_ms},\n \"questions\": normalized_questions,\n \"kind\": kind,\n }\n if project:\n block[\"project\"] = project\n if notification_type:\n block[\"notificationType\"] = notification_type\n\n # A Codex PermissionRequest is a real approval gate: mark it approval-class\n # with a high cost-of-delay so 'agents feed --dispatch' classifies it urgent\n # (isPhoneUrgent gates on costOfDelay >= phoneNotifyThreshold, default\n # 'medium') and pages the phone. A plain 'deny' is the safe default.\n if codex_approval:\n block[\"blockClass\"] = \"approval\"\n block[\"costOfDelay\"] = \"high\"\n block[\"safeDefault\"] = \"deny\"\n\n # Optional multi-operator control metadata passed by the agent in the\n # AskUserQuestion tool_input. Defaults keep the existing behavior. A Codex\n # PermissionRequest carries tool ARGS in tool_input (command/path), not\n # operator controls, so it is excluded here -- its class/cost is stamped\n # above from codex_approval.\n controls = payload.get(\"tool_input\", {}) if hook_event not in (\"Notification\", \"PermissionRequest\") else {}\n block_class = controls.get(\"blockClass\") if isinstance(controls, dict) else None\n if block_class in (\"approval\", \"decision\"):\n block[\"blockClass\"] = block_class\n consequence = controls.get(\"consequence\") if isinstance(controls, dict) else None\n if consequence:\n block[\"consequence\"] = consequence\n allowed = controls.get(\"allowedOperators\") if isinstance(controls, dict) else None\n if isinstance(allowed, list):\n block[\"allowedOperators\"] = [str(a) for a in allowed]\n timeout = controls.get(\"timeoutMinutes\") if isinstance(controls, dict) else None\n if isinstance(timeout, (int, float)) and timeout > 0:\n block[\"timeoutMinutes\"] = int(timeout)\n safe_default = controls.get(\"safeDefault\") if isinstance(controls, dict) else None\n if isinstance(safe_default, str):\n block[\"safeDefault\"] = safe_default\n cost = controls.get(\"costOfDelay\") if isinstance(controls, dict) else None\n if cost in (\"low\", \"medium\", \"high\"):\n block[\"costOfDelay\"] = cost\n\n # Publishing a new question clears any stale answered marker from the\n # previous question in this session.\n try:\n os.unlink(os.path.join(answered_dir, f\"{block_id}.json\"))\n except FileNotFoundError:\n pass\n except Exception:\n pass\n\n # Python's expanduser() ignores HOME on Windows, while agents-cli honors a\n # HOME override on every platform. Use the same anchor so hooks and the CLI\n # always read/write one feed store (including temp-home and sandbox runs).\n os.makedirs(feed_dir, exist_ok=True)\n\n fd, tmp = tempfile.mkstemp(dir=feed_dir, suffix=\".tmp\")\n try:\n with os.fdopen(fd, \"w\") as f:\n json.dump(block, f, indent=2)\n os.replace(tmp, target)\n except Exception:\n try:\n os.unlink(tmp)\n except Exception:\n pass\n\n\nif __name__ == \"__main__\":\n try:\n main()\n except Exception:\n pass # fail open\n";
|
|
350
|
-
/** Manifest entry for the feed-publish hook, matching the ManifestHook shape. */
|
|
351
|
-
export declare const FEED_PUBLISH_HOOK_MANIFEST: {
|
|
352
|
-
name: string;
|
|
353
|
-
events: string[];
|
|
354
|
-
matcher: string;
|
|
355
|
-
script: string;
|
|
356
|
-
timeout: number;
|
|
357
|
-
};
|
|
358
|
-
export declare const FEED_NOTIFICATION_HOOK_MANIFEST: {
|
|
359
|
-
name: string;
|
|
360
|
-
events: string[];
|
|
361
|
-
matcher: string;
|
|
362
|
-
script: string;
|
|
363
|
-
timeout: number;
|
|
364
|
-
};
|
|
365
|
-
export declare const FEED_PERMISSION_HOOK_MANIFEST: {
|
|
366
|
-
name: string;
|
|
367
|
-
events: string[];
|
|
368
|
-
script: string;
|
|
369
|
-
timeout: number;
|
|
370
|
-
};
|
|
371
|
-
export declare const FEED_ANSWERED_HOOK_MANIFEST: {
|
|
372
|
-
name: string;
|
|
373
|
-
events: string[];
|
|
374
|
-
matcher: string;
|
|
375
|
-
script: string;
|
|
376
|
-
timeout: number;
|
|
377
|
-
};
|
|
378
|
-
export declare const FEED_LIFECYCLE_HOOK_MANIFEST: {
|
|
379
|
-
name: string;
|
|
380
|
-
events: string[];
|
|
381
|
-
script: string;
|
|
382
|
-
timeout: number;
|
|
383
|
-
};
|
|
384
350
|
/**
|
|
385
351
|
* Install the feed-publish hook script into the user hooks dir and add its
|
|
386
352
|
* manifest entry to the user agents.yaml. The system repo is an auto-pulled,
|
|
@@ -391,3 +357,4 @@ export declare function ensureFeedPublishHook(userAgentsDir?: string): {
|
|
|
391
357
|
installed: boolean;
|
|
392
358
|
error?: string;
|
|
393
359
|
};
|
|
360
|
+
export {};
|
package/dist/lib/feed/feed.js
CHANGED
|
@@ -85,24 +85,6 @@ export function recordResolution(resolution, root) {
|
|
|
85
85
|
export function readResolution(blockId, root) {
|
|
86
86
|
return safeReadJson(path.join(resolutionDir(root ?? getFeedDir()), `${blockId}.json`));
|
|
87
87
|
}
|
|
88
|
-
/** Read every resolution tombstone. Returns them sorted by stable block filename. */
|
|
89
|
-
export function listResolutions(root) {
|
|
90
|
-
const dir = resolutionDir(root ?? getFeedDir());
|
|
91
|
-
let names;
|
|
92
|
-
try {
|
|
93
|
-
names = fs.readdirSync(dir);
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
return [];
|
|
97
|
-
}
|
|
98
|
-
const out = [];
|
|
99
|
-
for (const name of names.filter(n => n.endsWith('.json')).sort()) {
|
|
100
|
-
const parsed = safeReadJson(path.join(dir, name));
|
|
101
|
-
if (parsed?.blockId && parsed.generation && parsed.reason)
|
|
102
|
-
out.push(parsed);
|
|
103
|
-
}
|
|
104
|
-
return out;
|
|
105
|
-
}
|
|
106
88
|
/**
|
|
107
89
|
* Stable block id for a session. One block per session -- a new question
|
|
108
90
|
* replaces the previous one (the agent can only ask one question at a time).
|
|
@@ -345,12 +327,8 @@ export function recordNotified(blockId, root) {
|
|
|
345
327
|
block.notifiedAt = new Date().toISOString();
|
|
346
328
|
publishBlock(block, dir);
|
|
347
329
|
}
|
|
348
|
-
/** Convenience: record that a terminal answer closed the block. */
|
|
349
|
-
export function recordTerminalAnswer(blockId, root) {
|
|
350
|
-
recordAnswer(blockId, { answeredFrom: 'terminal' }, root);
|
|
351
|
-
}
|
|
352
330
|
/** Remove answered marker and receipts for a block (used by block removal/GC). */
|
|
353
|
-
|
|
331
|
+
function clearBlockLifecycle(blockId, root) {
|
|
354
332
|
const dir = root ?? getFeedDir();
|
|
355
333
|
for (const sub of [answeredDir(dir), receiptDir(dir)]) {
|
|
356
334
|
try {
|
|
@@ -913,43 +891,6 @@ if __name__ == "__main__":
|
|
|
913
891
|
except Exception:
|
|
914
892
|
pass # fail open
|
|
915
893
|
`;
|
|
916
|
-
/** Manifest entry for the feed-publish hook, matching the ManifestHook shape. */
|
|
917
|
-
export const FEED_PUBLISH_HOOK_MANIFEST = {
|
|
918
|
-
name: 'feed-publish',
|
|
919
|
-
events: ['PreToolUse'],
|
|
920
|
-
matcher: 'AskUserQuestion',
|
|
921
|
-
script: '10-feed-publish.py',
|
|
922
|
-
timeout: 5,
|
|
923
|
-
};
|
|
924
|
-
export const FEED_NOTIFICATION_HOOK_MANIFEST = {
|
|
925
|
-
name: 'feed-publish-notification',
|
|
926
|
-
events: ['Notification'],
|
|
927
|
-
matcher: 'permission_prompt|elicitation_dialog',
|
|
928
|
-
script: '10-feed-publish.py',
|
|
929
|
-
timeout: 5,
|
|
930
|
-
};
|
|
931
|
-
// Codex fires PermissionRequest (not Claude's Notification) when it blocks on an
|
|
932
|
-
// approval prompt. The same script handles it, publishing a high-cost approval
|
|
933
|
-
// block so the feed dispatch pages the phone. PermissionRequest has no matcher.
|
|
934
|
-
export const FEED_PERMISSION_HOOK_MANIFEST = {
|
|
935
|
-
name: 'feed-publish-permission',
|
|
936
|
-
events: ['PermissionRequest'],
|
|
937
|
-
script: '10-feed-publish.py',
|
|
938
|
-
timeout: 5,
|
|
939
|
-
};
|
|
940
|
-
export const FEED_ANSWERED_HOOK_MANIFEST = {
|
|
941
|
-
name: 'feed-clear-answered',
|
|
942
|
-
events: ['PostToolUse'],
|
|
943
|
-
matcher: 'AskUserQuestion',
|
|
944
|
-
script: '10-feed-publish.py',
|
|
945
|
-
timeout: 5,
|
|
946
|
-
};
|
|
947
|
-
export const FEED_LIFECYCLE_HOOK_MANIFEST = {
|
|
948
|
-
name: 'feed-clear-lifecycle',
|
|
949
|
-
events: ['Stop', 'UserPromptSubmit', 'SessionEnd'],
|
|
950
|
-
script: '10-feed-publish.py',
|
|
951
|
-
timeout: 5,
|
|
952
|
-
};
|
|
953
894
|
/**
|
|
954
895
|
* Install the feed-publish hook script into the user hooks dir and add its
|
|
955
896
|
* manifest entry to the user agents.yaml. The system repo is an auto-pulled,
|
|
@@ -3,7 +3,6 @@ import type { DetectedPr } from '../session/state.js';
|
|
|
3
3
|
import type { GhExec } from '../github/pr-mergeable.js';
|
|
4
4
|
import type { PullRequestAttentionSignal } from './attention.js';
|
|
5
5
|
export declare const PR_STATUS_TTL_MS = 45000;
|
|
6
|
-
export declare const PR_STATUS_FIELDS = "number,title,state,isDraft,reviewDecision,mergeable,statusCheckRollup";
|
|
7
6
|
export interface PullRequestStatus extends PullRequestAttentionSignal {
|
|
8
7
|
statusCheckRollup?: unknown[];
|
|
9
8
|
}
|
|
@@ -13,7 +12,6 @@ export declare function readPullRequestStatus(session: ActiveSession, options?:
|
|
|
13
12
|
ttlMs?: number;
|
|
14
13
|
gh?: GhExec;
|
|
15
14
|
}): Promise<PullRequestStatus | undefined>;
|
|
16
|
-
export declare function projectPullRequestBoard(sessions: ActiveSession[]): Promise<PullRequestStatus[]>;
|
|
17
15
|
export declare function resetPullRequestStatusCache(): void;
|
|
18
16
|
/**
|
|
19
17
|
* The check rollup folded to one verdict; undefined when the PR has no checks.
|
|
@@ -2,7 +2,7 @@ import { execFile } from 'node:child_process';
|
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
3
|
const execFileAsync = promisify(execFile);
|
|
4
4
|
export const PR_STATUS_TTL_MS = 45_000;
|
|
5
|
-
|
|
5
|
+
const PR_STATUS_FIELDS = 'number,title,state,isDraft,reviewDecision,mergeable,statusCheckRollup';
|
|
6
6
|
const cache = new Map();
|
|
7
7
|
function needsHuman(value) {
|
|
8
8
|
if (value.state !== 'OPEN' || value.isDraft)
|
|
@@ -38,10 +38,6 @@ export async function readPullRequestStatus(session, options = {}) {
|
|
|
38
38
|
return undefined;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
export async function projectPullRequestBoard(sessions) {
|
|
42
|
-
const rows = await Promise.all(sessions.map((session) => readPullRequestStatus(session)));
|
|
43
|
-
return rows.filter((row) => row !== undefined);
|
|
44
|
-
}
|
|
45
41
|
export function resetPullRequestStatusCache() { cache.clear(); }
|
|
46
42
|
/**
|
|
47
43
|
* The check rollup folded to one verdict; undefined when the PR has no checks.
|
package/dist/lib/feed/watch.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { type SessionWatchEnvelope, type SessionWatchRow, type SessionWatchScope
|
|
|
2
2
|
import { type AttentionItem } from './attention.js';
|
|
3
3
|
import { type ActivityEvent } from './activity.js';
|
|
4
4
|
import type { GhExec } from '../github/pr-mergeable.js';
|
|
5
|
-
export declare const FEED_WATCH_VERSION: 1;
|
|
6
5
|
type Base = {
|
|
7
6
|
v: 1;
|
|
8
7
|
type: string;
|
|
@@ -48,8 +47,17 @@ export declare class FeedWatchState {
|
|
|
48
47
|
constructor(streamId?: `${string}-${string}-${string}-${string}-${string}`);
|
|
49
48
|
emit(event: FeedWatchPayload): FeedWatchEnvelope;
|
|
50
49
|
}
|
|
50
|
+
/** Reuse session ownership reconciliation for the combined operator stream. */
|
|
51
|
+
export declare class FeedSessionProjection {
|
|
52
|
+
private readonly state;
|
|
53
|
+
private readonly sessions;
|
|
54
|
+
private readonly observations;
|
|
55
|
+
private projectedAttention;
|
|
56
|
+
constructor(state?: FeedWatchState);
|
|
57
|
+
apply(event: FeedWatchEnvelope): FeedWatchEnvelope[];
|
|
58
|
+
}
|
|
51
59
|
export declare function projectSessionEnvelope(event: SessionWatchEnvelope, state: FeedWatchState, gh?: GhExec): Promise<FeedWatchEnvelope[]>;
|
|
52
|
-
|
|
60
|
+
interface WatchLocalFeedOptions {
|
|
53
61
|
scope: string;
|
|
54
62
|
signal: AbortSignal;
|
|
55
63
|
emit: (event: FeedWatchEnvelope) => void;
|
package/dist/lib/feed/watch.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SessionProjection } from '../session/projection.js';
|
|
1
2
|
import { randomUUID } from 'node:crypto';
|
|
2
3
|
import * as fs from 'node:fs';
|
|
3
4
|
import * as path from 'node:path';
|
|
@@ -12,7 +13,6 @@ import { readBlock, readResolution, blockIdForSession } from './feed.js';
|
|
|
12
13
|
import { reconcileAttention } from './attention.js';
|
|
13
14
|
import { ActivityStream } from './activity-stream.js';
|
|
14
15
|
import { PR_STATUS_TTL_MS, readPullRequestStatus, withPullRequestStatus } from './pr-status.js';
|
|
15
|
-
export const FEED_WATCH_VERSION = 1;
|
|
16
16
|
export class FeedWatchState {
|
|
17
17
|
streamId;
|
|
18
18
|
sequence = 0;
|
|
@@ -21,6 +21,86 @@ export class FeedWatchState {
|
|
|
21
21
|
return { v: 1, streamId: this.streamId, sequence: ++this.sequence, ...event };
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
/** Reuse session ownership reconciliation for the combined operator stream. */
|
|
25
|
+
export class FeedSessionProjection {
|
|
26
|
+
state;
|
|
27
|
+
sessions = new SessionProjection();
|
|
28
|
+
observations = new Map();
|
|
29
|
+
projectedAttention = new Map();
|
|
30
|
+
constructor(state = new FeedWatchState()) {
|
|
31
|
+
this.state = state;
|
|
32
|
+
}
|
|
33
|
+
apply(event) {
|
|
34
|
+
const scope = normalizeHost(event.scope);
|
|
35
|
+
const base = { version: 1, streamId: event.streamId, sequence: event.sequence, capturedAt: 'capturedAt' in event ? event.capturedAt : Date.now(), scope };
|
|
36
|
+
let sessionEvent;
|
|
37
|
+
if (event.type === 'reset') {
|
|
38
|
+
sessionEvent = { ...base, type: 'reset', rows: event.agents };
|
|
39
|
+
const attention = new Map();
|
|
40
|
+
for (const row of event.agents) {
|
|
41
|
+
const item = event.attention.find(item => item.sessionId === row.sessionId);
|
|
42
|
+
if (item && !row.previous)
|
|
43
|
+
attention.set(row.rowKey, item);
|
|
44
|
+
}
|
|
45
|
+
this.observations.set(scope, attention);
|
|
46
|
+
}
|
|
47
|
+
else if (event.type === 'agent.upsert') {
|
|
48
|
+
sessionEvent = { ...base, type: 'upsert', rowKey: event.rowKey, row: event.agent };
|
|
49
|
+
}
|
|
50
|
+
else if (event.type === 'agent.remove') {
|
|
51
|
+
sessionEvent = { ...base, type: 'remove', rowKey: event.rowKey };
|
|
52
|
+
this.observations.get(scope)?.delete(event.rowKey);
|
|
53
|
+
}
|
|
54
|
+
else if (event.type === 'attention.upsert') {
|
|
55
|
+
if (!this.observations.has(scope))
|
|
56
|
+
this.observations.set(scope, new Map());
|
|
57
|
+
this.observations.get(scope).set(event.rowKey, event.attention);
|
|
58
|
+
}
|
|
59
|
+
else if (event.type === 'attention.remove') {
|
|
60
|
+
this.observations.get(scope)?.delete(event.rowKey);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const { v: _v, streamId: _streamId, sequence: _sequence, ...payload } = event;
|
|
64
|
+
return [this.state.emit(payload)];
|
|
65
|
+
}
|
|
66
|
+
const projected = sessionEvent ? this.sessions.apply(sessionEvent) : [];
|
|
67
|
+
const next = new Map();
|
|
68
|
+
for (const [observer, items] of this.observations)
|
|
69
|
+
for (const [rowKey, item] of items) {
|
|
70
|
+
const row = this.sessions.rowForObservation(observer, rowKey);
|
|
71
|
+
if (row && !row.previous && row.sourceDevice === observer)
|
|
72
|
+
next.set(item.key, { scope: observer, item });
|
|
73
|
+
}
|
|
74
|
+
const result = [];
|
|
75
|
+
const resetScopes = new Set();
|
|
76
|
+
for (const rowEvent of projected) {
|
|
77
|
+
if (rowEvent.type === 'reset') {
|
|
78
|
+
resetScopes.add(rowEvent.scope);
|
|
79
|
+
result.push(this.state.emit({ type: 'reset', scope: rowEvent.scope, capturedAt: rowEvent.capturedAt, agents: rowEvent.rows,
|
|
80
|
+
attention: [...next.values()].filter(value => value.scope === rowEvent.scope).map(value => value.item) }));
|
|
81
|
+
}
|
|
82
|
+
else if (rowEvent.type === 'upsert') {
|
|
83
|
+
result.push(this.state.emit({ type: 'agent.upsert', scope: rowEvent.scope, rowKey: rowEvent.rowKey, agent: rowEvent.row }));
|
|
84
|
+
}
|
|
85
|
+
else if (rowEvent.type === 'remove') {
|
|
86
|
+
result.push(this.state.emit({ type: 'agent.remove', scope: rowEvent.scope, rowKey: rowEvent.rowKey }));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Attention has its own stable generation key, also used by feed answer.
|
|
90
|
+
// Never substitute the projected agent row key: reset consumers key by item.key.
|
|
91
|
+
for (const [key, previous] of this.projectedAttention) {
|
|
92
|
+
if (!next.has(key) && !resetScopes.has(previous.scope))
|
|
93
|
+
result.push(this.state.emit({ type: 'attention.remove', scope: previous.scope, rowKey: key }));
|
|
94
|
+
}
|
|
95
|
+
for (const [key, value] of next) {
|
|
96
|
+
if (!resetScopes.has(value.scope) && JSON.stringify(this.projectedAttention.get(key)) !== JSON.stringify(value)) {
|
|
97
|
+
result.push(this.state.emit({ type: 'attention.upsert', scope: value.scope, rowKey: key, attention: value.item }));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
this.projectedAttention = next;
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
24
104
|
/**
|
|
25
105
|
* Live rows only: durable Previous rows share the operator stream for Sessions
|
|
26
106
|
* history, but they are not live work and must never synthesize Needs-you
|
|
@@ -92,13 +172,19 @@ function watchAttentionStores(onChange) {
|
|
|
92
172
|
const watchers = [];
|
|
93
173
|
for (const dir of [feedDir, path.join(feedDir, 'resolutions')]) {
|
|
94
174
|
try {
|
|
175
|
+
// `resolutions` is created lazily by the first `recordResolution` call, so
|
|
176
|
+
// a fresh feed dir has no directory to watch yet. Create it up front —
|
|
177
|
+
// otherwise fs.watch throws ENOENT here, is swallowed, and never retried,
|
|
178
|
+
// silently downgrading every resolution to the 45 s PR-status fallback
|
|
179
|
+
// instead of the event-driven reconcile this function exists to provide.
|
|
180
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
95
181
|
const watcher = fs.watch(dir, () => onChange());
|
|
96
182
|
// A directory that disappears must not take the watcher process down; the
|
|
97
183
|
// PR-status cadence below still reconciles on its own timer.
|
|
98
184
|
watcher.on('error', () => watcher.close());
|
|
99
185
|
watchers.push(watcher);
|
|
100
186
|
}
|
|
101
|
-
catch { /* the
|
|
187
|
+
catch { /* best-effort: the timed pass still reconciles on its own cadence */ }
|
|
102
188
|
}
|
|
103
189
|
return () => { for (const watcher of watchers)
|
|
104
190
|
watcher.close(); };
|
|
@@ -217,9 +303,10 @@ function remoteFeedWatchCommand(os) {
|
|
|
217
303
|
}
|
|
218
304
|
export async function watchFleetFeed(options) {
|
|
219
305
|
const coordinator = new FeedWatchState();
|
|
306
|
+
const projection = new FeedSessionProjection(coordinator);
|
|
220
307
|
const forward = (event) => {
|
|
221
|
-
const
|
|
222
|
-
|
|
308
|
+
for (const projected of projection.apply(event))
|
|
309
|
+
options.emit(projected);
|
|
223
310
|
};
|
|
224
311
|
const local = watchLocalFeed({ scope: machineId(), signal: options.signal, emit: forward });
|
|
225
312
|
let devices;
|
|
@@ -14,9 +14,9 @@ export interface FeedSinkConfig {
|
|
|
14
14
|
command?: string[];
|
|
15
15
|
/**
|
|
16
16
|
* In-process delivery through the same channel-provider registry `agents
|
|
17
|
-
* send`/`agents
|
|
17
|
+
* send`/`agents send --to owner` use — the composed `{message}` body, no argv, no
|
|
18
18
|
* spawn. `'owner'` is the address alias (expands to `notify.owner.{channel,to}`
|
|
19
|
-
* in agents.yaml, same as `agents
|
|
19
|
+
* in agents.yaml, same as `agents send --to owner`); any other value is a registered
|
|
20
20
|
* channel name (or a `notify.transports` mapping) and requires `to`.
|
|
21
21
|
*/
|
|
22
22
|
channel?: string;
|
|
@@ -113,7 +113,7 @@ export declare function blockBroadcastContext(block: {
|
|
|
113
113
|
* not mask a delivered desktop notification.
|
|
114
114
|
*/
|
|
115
115
|
export declare function blockDeliveryFailure(blocked: boolean, outcomes: SinkOutcome[]): string | undefined;
|
|
116
|
-
|
|
116
|
+
interface PlannedSink {
|
|
117
117
|
name: string;
|
|
118
118
|
/** Command sink: argv to spawn (mutually exclusive with `channel`). */
|
|
119
119
|
argv?: string[];
|
|
@@ -141,49 +141,6 @@ export interface SinkOutcome {
|
|
|
141
141
|
/** stderr tail when the sink failed, for the warning line. */
|
|
142
142
|
error?: string;
|
|
143
143
|
}
|
|
144
|
-
/**
|
|
145
|
-
* Short host label for a phone line — strip user@ and domain so
|
|
146
|
-
* `muqsit@mac-mini.tailnet.ts.net` reads as `mac-mini`.
|
|
147
|
-
*/
|
|
148
|
-
export declare function shortHost(host: string | undefined): string | undefined;
|
|
149
|
-
/** First 8 hex chars of a session id for the footer (readable, not a full uuid). */
|
|
150
|
-
export declare function shortSessionChunk(session: string | undefined): string | undefined;
|
|
151
|
-
/**
|
|
152
|
-
* Tap-to-view link for the session behind a post: the addressable console page
|
|
153
|
-
* ({@link https://prix.dev/console/sessions/<id>}, prix/web). The footer already
|
|
154
|
-
* carries a short session crumb for disambiguation; this rides the link trail so
|
|
155
|
-
* the owner can open the full transcript straight from an iMessage broadcast
|
|
156
|
-
* instead of hunting for it in the console.
|
|
157
|
-
*
|
|
158
|
-
* Accepts any real, path-safe session id — a Claude/Codex UUID *and* a native
|
|
159
|
-
* `ses_…` id from OpenCode or another harness. The console shard uploader
|
|
160
|
-
* (`traces/sync.ts`) syncs sessions with no harness filter, so all of them are
|
|
161
|
-
* addressable; a UUID-only gate would silently drop the link for every non-Claude
|
|
162
|
-
* harness (the whole point of the link). Reject only an id that could not resolve:
|
|
163
|
-
* one with a path separator (URL-unsafe, via {@link isValidMailboxId}) or the bare
|
|
164
|
-
* 8-char footer crumb (a truncated id that would 404).
|
|
165
|
-
*/
|
|
166
|
-
export declare function sessionConsoleUrl(session: string | undefined): string | undefined;
|
|
167
|
-
/**
|
|
168
|
-
* Scrub em/en dashes from outbound phone copy (house rule + iMessage readability).
|
|
169
|
-
* Collapses whitespace; does not invent meaning.
|
|
170
|
-
*/
|
|
171
|
-
export declare function scrubOutboundDashes(text: string): string;
|
|
172
|
-
/**
|
|
173
|
-
* Footer like "Sent from my iPhone" — who posted, a session crumb, which box.
|
|
174
|
-
*
|
|
175
|
-
* Sent from grok/a02da0e2 on mac-mini
|
|
176
|
-
*
|
|
177
|
-
* Agent name first; session chunk for disambiguation when many groks run;
|
|
178
|
-
* host last. Skip the uninformative default label `agent`.
|
|
179
|
-
*
|
|
180
|
-
* In `mrkdwn` the crumb (`agent/short`) becomes a Slack labeled link to the
|
|
181
|
-
* session's console page, so the human sentence reads identically while the
|
|
182
|
-
* crumb turns blue and taps through (PHNX-3698). `plain` keeps the bare sentence
|
|
183
|
-
* — it can't render a labeled link and must not dump the URL.
|
|
184
|
-
*/
|
|
185
|
-
export declare function composeBroadcastFooter(ctx: FeedBroadcastContext, format?: SinkMessageFormat): string | undefined;
|
|
186
|
-
export declare function truncateBroadcastBody(body: string): string;
|
|
187
144
|
export declare function composeBroadcastMessage(ctx: FeedBroadcastContext, format?: SinkMessageFormat): string;
|
|
188
145
|
/**
|
|
189
146
|
* Substitute `{placeholder}` tokens in an argv template. Returns undefined when
|
|
@@ -221,7 +178,7 @@ export declare function planFeedBroadcast(config: FeedBroadcastConfig | undefine
|
|
|
221
178
|
* moment `feed.broadcast` was empty, even when `notify.owner` was fully
|
|
222
179
|
* configured — so the common case (an operator who set up owner notifications
|
|
223
180
|
* but never wrote a `feed.broadcast` block) produced a `--blocked` post that
|
|
224
|
-
* looked recorded and reached nobody. `agents
|
|
181
|
+
* looked recorded and reached nobody. `agents send --to owner` already treats
|
|
225
182
|
* `notify.owner` as the default human destination; this makes an important
|
|
226
183
|
* feed post/block use that same default instead of requiring a second,
|
|
227
184
|
* redundant config block that says the same thing.
|
|
@@ -265,3 +222,4 @@ export declare function withDesktopNotify(config: FeedBroadcastConfig | undefine
|
|
|
265
222
|
* reached.
|
|
266
223
|
*/
|
|
267
224
|
export declare function runFeedBroadcast(planned: PlannedSink[], meta: Meta, timeoutMs?: number): Promise<SinkOutcome[]>;
|
|
225
|
+
export {};
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* A second sink shape (RUSH-2123) delivers **in-process** through the same
|
|
28
28
|
* channel-provider registry `agents send` uses (`channel:` instead of
|
|
29
29
|
* `command:`) — no spawn, no argv templating. `channel: owner` is the address
|
|
30
|
-
* alias that expands to `notify.owner.{channel,to}`, matching `agents
|
|
30
|
+
* alias that expands to `notify.owner.{channel,to}`, matching `agents send --to owner`.
|
|
31
31
|
* When the operator has never written a `feed.broadcast` block at all, an
|
|
32
32
|
* important-level post falls back to that owner address implicitly
|
|
33
33
|
* ({@link effectiveBroadcastConfig}) rather than reaching nobody — see that
|
|
@@ -127,7 +127,7 @@ const PLACEHOLDER = /\{([a-z_]+)\}/g;
|
|
|
127
127
|
* Short host label for a phone line — strip user@ and domain so
|
|
128
128
|
* `muqsit@mac-mini.tailnet.ts.net` reads as `mac-mini`.
|
|
129
129
|
*/
|
|
130
|
-
|
|
130
|
+
function shortHost(host) {
|
|
131
131
|
if (!host?.trim())
|
|
132
132
|
return undefined;
|
|
133
133
|
let h = host.trim();
|
|
@@ -140,7 +140,7 @@ export function shortHost(host) {
|
|
|
140
140
|
return h || undefined;
|
|
141
141
|
}
|
|
142
142
|
/** First 8 hex chars of a session id for the footer (readable, not a full uuid). */
|
|
143
|
-
|
|
143
|
+
function shortSessionChunk(session) {
|
|
144
144
|
if (!session?.trim())
|
|
145
145
|
return undefined;
|
|
146
146
|
const hex = session.replace(/-/g, '').toLowerCase();
|
|
@@ -162,7 +162,7 @@ export function shortSessionChunk(session) {
|
|
|
162
162
|
* one with a path separator (URL-unsafe, via {@link isValidMailboxId}) or the bare
|
|
163
163
|
* 8-char footer crumb (a truncated id that would 404).
|
|
164
164
|
*/
|
|
165
|
-
|
|
165
|
+
function sessionConsoleUrl(session) {
|
|
166
166
|
const id = session?.trim();
|
|
167
167
|
if (!id || !isValidMailboxId(id) || /^[0-9a-f]{8}$/i.test(id))
|
|
168
168
|
return undefined;
|
|
@@ -172,7 +172,7 @@ export function sessionConsoleUrl(session) {
|
|
|
172
172
|
* Scrub em/en dashes from outbound phone copy (house rule + iMessage readability).
|
|
173
173
|
* Collapses whitespace; does not invent meaning.
|
|
174
174
|
*/
|
|
175
|
-
|
|
175
|
+
function scrubOutboundDashes(text) {
|
|
176
176
|
return text
|
|
177
177
|
.replace(/\u2014/g, ' - ')
|
|
178
178
|
.replace(/\u2013/g, ' - ')
|
|
@@ -227,7 +227,7 @@ function linkifyKeys(text, format) {
|
|
|
227
227
|
* crumb turns blue and taps through (PHNX-3698). `plain` keeps the bare sentence
|
|
228
228
|
* — it can't render a labeled link and must not dump the URL.
|
|
229
229
|
*/
|
|
230
|
-
|
|
230
|
+
function composeBroadcastFooter(ctx, format = 'plain') {
|
|
231
231
|
const agent = ctx.agent?.trim();
|
|
232
232
|
const agentLabel = agent && agent !== 'agent' ? agent : undefined;
|
|
233
233
|
const session = shortSessionChunk(ctx.session);
|
|
@@ -283,7 +283,7 @@ export function composeBroadcastFooter(ctx, format = 'plain') {
|
|
|
283
283
|
*/
|
|
284
284
|
const PHONE_BODY_MAX_CHARS = 500;
|
|
285
285
|
const PHONE_BODY_MAX_LINES = 8;
|
|
286
|
-
|
|
286
|
+
function truncateBroadcastBody(body) {
|
|
287
287
|
if (!body)
|
|
288
288
|
return body;
|
|
289
289
|
let out = body;
|
|
@@ -508,7 +508,7 @@ export function planFeedBroadcast(config, ctx, meta) {
|
|
|
508
508
|
* moment `feed.broadcast` was empty, even when `notify.owner` was fully
|
|
509
509
|
* configured — so the common case (an operator who set up owner notifications
|
|
510
510
|
* but never wrote a `feed.broadcast` block) produced a `--blocked` post that
|
|
511
|
-
* looked recorded and reached nobody. `agents
|
|
511
|
+
* looked recorded and reached nobody. `agents send --to owner` already treats
|
|
512
512
|
* `notify.owner` as the default human destination; this makes an important
|
|
513
513
|
* feed post/block use that same default instead of requiring a second,
|
|
514
514
|
* redundant config block that says the same thing.
|
|
@@ -577,7 +577,7 @@ function runCommandSink(name, argv, timeoutMs) {
|
|
|
577
577
|
}
|
|
578
578
|
/**
|
|
579
579
|
* Deliver one `channel:` sink through the real provider registry —
|
|
580
|
-
* `resolveSendEnvelope` reuses `agents
|
|
580
|
+
* `resolveSendEnvelope` reuses `agents send --to owner`'s owner-alias expansion, and
|
|
581
581
|
* `deliverEnvelope` is the same seam `agents send` calls. A bad channel name
|
|
582
582
|
* is checked with `lookupTransport` (the non-throwing lookup) BEFORE handing
|
|
583
583
|
* off to `deliverEnvelope`: that function's own resolution `die()`s on an
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OpenBlock } from './feed/feed.js';
|
|
2
|
-
|
|
2
|
+
type OutcomeKind = 'ticket' | 'pr' | 'worktree' | 'unassigned';
|
|
3
3
|
/** Stable attribution of a block (or agent) to one deliverable. */
|
|
4
4
|
export interface OutcomeRef {
|
|
5
5
|
/** Map/JSON key, e.g. `ticket:RUSH-1125`, `pr:#534`, `worktree:headless-secrets`, `unassigned`. */
|
|
@@ -12,7 +12,7 @@ export interface OutcomeRef {
|
|
|
12
12
|
* Signals used to derive an outcome. All optional — callers pass whatever they
|
|
13
13
|
* already know (block fields, session meta, free-text questions).
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
interface OutcomeSignals {
|
|
16
16
|
ticket?: string | null;
|
|
17
17
|
pr?: string | null;
|
|
18
18
|
worktreeSlug?: string | null;
|
|
@@ -29,8 +29,6 @@ export interface OutcomeSignals {
|
|
|
29
29
|
* - Bare `#123` / `PR#123` → `#123` (no repo known)
|
|
30
30
|
*/
|
|
31
31
|
export declare function normalizePrRef(raw: string | null | undefined): string | undefined;
|
|
32
|
-
/** `https://github.com/owner/repo/pull/N` → `owner/repo`. */
|
|
33
|
-
export declare function repoFromPrUrl(url: string | null | undefined): string | undefined;
|
|
34
32
|
/** Canonical ticket id (uppercase team key). */
|
|
35
33
|
export declare function normalizeTicketRef(raw: string | null | undefined): string | undefined;
|
|
36
34
|
/**
|
|
@@ -38,8 +36,6 @@ export declare function normalizeTicketRef(raw: string | null | undefined): stri
|
|
|
38
36
|
* Exactly one outcome per call — never ambiguous, never empty.
|
|
39
37
|
*/
|
|
40
38
|
export declare function deriveOutcome(signals: OutcomeSignals): OutcomeRef;
|
|
41
|
-
/** Join question headers + bodies into one scan target for ticket/PR detection. */
|
|
42
|
-
export declare function blockScanText(block: Pick<OpenBlock, 'questions'>): string;
|
|
43
39
|
/** Outcome for a stored open block (uses stamped fields + question text). */
|
|
44
40
|
export declare function outcomeForBlock(block: OpenBlock): OutcomeRef;
|
|
45
41
|
/** Per-outcome rollup used by the default `agents feed` view. */
|
|
@@ -103,3 +99,4 @@ export declare function enrichBlockFromSession(block: OpenBlock, hint: SessionOu
|
|
|
103
99
|
* Matching order: mailboxId, then sessionId, then agentId.
|
|
104
100
|
*/
|
|
105
101
|
export declare function enrichBlocksFromSessions(blocks: OpenBlock[], sessions: SessionOutcomeHint[]): OpenBlock[];
|
|
102
|
+
export {};
|
package/dist/lib/feed-outcome.js
CHANGED
|
@@ -44,7 +44,7 @@ export function normalizePrRef(raw) {
|
|
|
44
44
|
return undefined;
|
|
45
45
|
}
|
|
46
46
|
/** `https://github.com/owner/repo/pull/N` → `owner/repo`. */
|
|
47
|
-
|
|
47
|
+
function repoFromPrUrl(url) {
|
|
48
48
|
if (!url)
|
|
49
49
|
return undefined;
|
|
50
50
|
const m = /github\.com\/([^/\s]+)\/([^/\s]+)\/pull\/\d+/i.exec(url);
|
|
@@ -116,7 +116,7 @@ export function deriveOutcome(signals) {
|
|
|
116
116
|
return UNASSIGNED;
|
|
117
117
|
}
|
|
118
118
|
/** Join question headers + bodies into one scan target for ticket/PR detection. */
|
|
119
|
-
|
|
119
|
+
function blockScanText(block) {
|
|
120
120
|
return block.questions
|
|
121
121
|
.map((q) => [q.header, q.text].filter(Boolean).join(' '))
|
|
122
122
|
.filter(Boolean)
|