@openrig/cli 0.6.10 → 0.6.11
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/daemon/assets/plugins/openrig-core/skills/openrig-skills/SKILL.md +1 -1
- package/daemon/assets/plugins/openrig-core/skills/refocusing/scripts/trace-to-root.py +6 -1
- package/daemon/assets/skills/rigs/SKILL.md +1 -1
- package/daemon/context-packs/help/manifest.yaml +1 -1
- package/daemon/context-packs/onboarding-width/manifest.yaml +1 -1
- package/daemon/context-packs/onboarding-width/public-what-you-can-do.md +36 -11
- package/daemon/context-packs/reference/manifest.yaml +1 -1
- package/daemon/context-packs/reference/rig-spec.md +2 -2
- package/daemon/context-packs/reference/whats-new.md +135 -134
- package/daemon/context-packs/skills/agent-operated-software/manifest.yaml +1 -1
- package/daemon/context-packs/skills/agent-operated-workflows/manifest.yaml +1 -1
- package/daemon/context-packs/skills/applying-a-permission-policy/manifest.yaml +1 -1
- package/daemon/context-packs/skills/claude-compaction-restore/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/agent-starters/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/agent-startup-and-context-ingestion/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/cross-host-rig-commands/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/human-in-the-loop/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/messaging-the-human/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/openrig-architect/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/openrig-cmux/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/openrig-herdr/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/openrig-skills/SKILL.md +1 -1
- package/daemon/context-packs/skills/core/openrig-skills/manifest.yaml +3 -3
- package/daemon/context-packs/skills/core/openrig-software-factory/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/openrig-upgrade/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/rig-bundles-and-shareable-artifacts/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/rig-lifecycle/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/session-source-fork/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/specification-system/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/topology-mutation-and-seat-management/manifest.yaml +1 -1
- package/daemon/context-packs/skills/core/watchdog/manifest.yaml +1 -1
- package/daemon/context-packs/skills/delegating-work/manifest.yaml +1 -1
- package/daemon/context-packs/skills/forming-an-openrig-mental-model/manifest.yaml +1 -1
- package/daemon/context-packs/skills/loading-addressable-markdown/manifest.yaml +1 -1
- package/daemon/context-packs/skills/mission-slice-sop/manifest.yaml +1 -1
- package/daemon/context-packs/skills/openrig-operating-model/manifest.yaml +1 -1
- package/daemon/context-packs/skills/openrig-user/manifest.yaml +1 -1
- package/daemon/context-packs/skills/orienting-to-an-inherited-seat/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pm/backlog-capture/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pm/context-builder/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pm/exec-summary/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pm/office-hours/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pm/plan-review/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pm/requirements-writer/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pm/ui-mockup/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pods/development-team/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pods/orchestration-team/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pods/oversight-team/manifest.yaml +1 -1
- package/daemon/context-packs/skills/pods/review-team/manifest.yaml +1 -1
- package/daemon/context-packs/skills/process/agent-browser/manifest.yaml +1 -1
- package/daemon/context-packs/skills/process/context-engineering/manifest.yaml +1 -1
- package/daemon/context-packs/skills/process/dogfood/manifest.yaml +1 -1
- package/daemon/context-packs/skills/process/frontend-design/manifest.yaml +1 -1
- package/daemon/context-packs/skills/process/systematic-debugging/manifest.yaml +1 -1
- package/daemon/context-packs/skills/process/test-driven-development/manifest.yaml +1 -1
- package/daemon/context-packs/skills/process/verification-before-completion/manifest.yaml +1 -1
- package/daemon/context-packs/skills/queue-handoff/manifest.yaml +1 -1
- package/daemon/context-packs/skills/refocusing/manifest.yaml +1 -1
- package/daemon/context-packs/skills/refocusing/scripts/trace-to-root.py +6 -1
- package/daemon/context-packs/skills/retiring-and-inheriting-a-seat/manifest.yaml +1 -1
- package/daemon/context-packs/skills/seat-continuity-and-handover/manifest.yaml +1 -1
- package/daemon/context-packs/skills/session-compaction-and-restore/manifest.yaml +1 -1
- package/daemon/context-packs/skills/software-for-agents/manifest.yaml +1 -1
- package/daemon/context-packs/world-example/manifest.yaml +1 -1
- package/daemon/context-packs/world-public/manifest.yaml +1 -1
- package/daemon/dist/adapters/claude-code-adapter.d.ts +0 -14
- package/daemon/dist/adapters/claude-code-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/claude-code-adapter.js +27 -73
- package/daemon/dist/adapters/claude-code-adapter.js.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts +35 -0
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.js +94 -44
- package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
- package/daemon/dist/adapters/pi-runner.d.ts.map +1 -1
- package/daemon/dist/adapters/pi-runner.js +6 -3
- package/daemon/dist/adapters/pi-runner.js.map +1 -1
- package/daemon/dist/adapters/pi-runtime-adapter.js +1 -1
- package/daemon/dist/adapters/pi-runtime-adapter.js.map +1 -1
- package/daemon/dist/adapters/tmux.d.ts +23 -0
- package/daemon/dist/adapters/tmux.d.ts.map +1 -1
- package/daemon/dist/adapters/tmux.js +127 -6
- package/daemon/dist/adapters/tmux.js.map +1 -1
- package/daemon/dist/build-info.js +3 -3
- package/daemon/dist/db/all-migrations.d.ts.map +1 -1
- package/daemon/dist/db/all-migrations.js +2 -0
- package/daemon/dist/db/all-migrations.js.map +1 -1
- package/daemon/dist/db/migrations/103_session_stop_intent.d.ts +4 -0
- package/daemon/dist/db/migrations/103_session_stop_intent.d.ts.map +1 -0
- package/daemon/dist/db/migrations/103_session_stop_intent.js +9 -0
- package/daemon/dist/db/migrations/103_session_stop_intent.js.map +1 -0
- package/daemon/dist/domain/active-occupant.d.ts +14 -0
- package/daemon/dist/domain/active-occupant.d.ts.map +1 -1
- package/daemon/dist/domain/active-occupant.js +17 -0
- package/daemon/dist/domain/active-occupant.js.map +1 -1
- package/daemon/dist/domain/codex-network-default.d.ts +3 -0
- package/daemon/dist/domain/codex-network-default.d.ts.map +1 -1
- package/daemon/dist/domain/codex-network-default.js +1 -1
- package/daemon/dist/domain/codex-network-default.js.map +1 -1
- package/daemon/dist/domain/codex-pane-patterns.d.ts +2 -0
- package/daemon/dist/domain/codex-pane-patterns.d.ts.map +1 -0
- package/daemon/dist/domain/codex-pane-patterns.js +5 -0
- package/daemon/dist/domain/codex-pane-patterns.js.map +1 -0
- package/daemon/dist/domain/context-monitor.d.ts.map +1 -1
- package/daemon/dist/domain/context-monitor.js +46 -22
- package/daemon/dist/domain/context-monitor.js.map +1 -1
- package/daemon/dist/domain/cwd-resolution.d.ts +8 -0
- package/daemon/dist/domain/cwd-resolution.d.ts.map +1 -1
- package/daemon/dist/domain/cwd-resolution.js +24 -3
- package/daemon/dist/domain/cwd-resolution.js.map +1 -1
- package/daemon/dist/domain/gateway/slack/channel-recovery.d.ts.map +1 -1
- package/daemon/dist/domain/gateway/slack/channel-recovery.js +4 -3
- package/daemon/dist/domain/gateway/slack/channel-recovery.js.map +1 -1
- package/daemon/dist/domain/native-process-lineage.d.ts +5 -0
- package/daemon/dist/domain/native-process-lineage.d.ts.map +1 -1
- package/daemon/dist/domain/native-process-lineage.js +53 -15
- package/daemon/dist/domain/native-process-lineage.js.map +1 -1
- package/daemon/dist/domain/node-inventory.d.ts.map +1 -1
- package/daemon/dist/domain/node-inventory.js +15 -7
- package/daemon/dist/domain/node-inventory.js.map +1 -1
- package/daemon/dist/domain/node-launcher.d.ts.map +1 -1
- package/daemon/dist/domain/node-launcher.js +2 -1
- package/daemon/dist/domain/node-launcher.js.map +1 -1
- package/daemon/dist/domain/pane-cutover.d.ts +27 -0
- package/daemon/dist/domain/pane-cutover.d.ts.map +1 -0
- package/daemon/dist/domain/pane-cutover.js +37 -0
- package/daemon/dist/domain/pane-cutover.js.map +1 -0
- package/daemon/dist/domain/parent-session-env.d.ts +8 -0
- package/daemon/dist/domain/parent-session-env.d.ts.map +1 -0
- package/daemon/dist/domain/parent-session-env.js +37 -0
- package/daemon/dist/domain/parent-session-env.js.map +1 -0
- package/daemon/dist/domain/policies/parked-owner-consumer.d.ts +11 -0
- package/daemon/dist/domain/policies/parked-owner-consumer.d.ts.map +1 -1
- package/daemon/dist/domain/policies/parked-owner-consumer.js +81 -11
- package/daemon/dist/domain/policies/parked-owner-consumer.js.map +1 -1
- package/daemon/dist/domain/profile-resolver.d.ts.map +1 -1
- package/daemon/dist/domain/profile-resolver.js +2 -3
- package/daemon/dist/domain/profile-resolver.js.map +1 -1
- package/daemon/dist/domain/proof/judgments.d.ts +10 -5
- package/daemon/dist/domain/proof/judgments.d.ts.map +1 -1
- package/daemon/dist/domain/proof/judgments.js +27 -19
- package/daemon/dist/domain/proof/judgments.js.map +1 -1
- package/daemon/dist/domain/provider/codex-limit-banner.d.ts +2 -2
- package/daemon/dist/domain/provider/codex-limit-banner.d.ts.map +1 -1
- package/daemon/dist/domain/provider/codex-limit-banner.js +56 -9
- package/daemon/dist/domain/provider/codex-limit-banner.js.map +1 -1
- package/daemon/dist/domain/provider/codex-usage-reader.d.ts +31 -0
- package/daemon/dist/domain/provider/codex-usage-reader.d.ts.map +1 -0
- package/daemon/dist/domain/provider/codex-usage-reader.js +115 -0
- package/daemon/dist/domain/provider/codex-usage-reader.js.map +1 -0
- package/daemon/dist/domain/provider/codex-usage-windows.d.ts +78 -0
- package/daemon/dist/domain/provider/codex-usage-windows.d.ts.map +1 -0
- package/daemon/dist/domain/provider/codex-usage-windows.js +259 -0
- package/daemon/dist/domain/provider/codex-usage-windows.js.map +1 -0
- package/daemon/dist/domain/provider/provider-service-impl.d.ts +10 -0
- package/daemon/dist/domain/provider/provider-service-impl.d.ts.map +1 -1
- package/daemon/dist/domain/provider/provider-service-impl.js +27 -1
- package/daemon/dist/domain/provider/provider-service-impl.js.map +1 -1
- package/daemon/dist/domain/provider/provider-service.d.ts +5 -0
- package/daemon/dist/domain/provider/provider-service.d.ts.map +1 -1
- package/daemon/dist/domain/provider/provider-types.d.ts +65 -0
- package/daemon/dist/domain/provider/provider-types.d.ts.map +1 -1
- package/daemon/dist/domain/ps-projection.d.ts +5 -2
- package/daemon/dist/domain/ps-projection.d.ts.map +1 -1
- package/daemon/dist/domain/ps-projection.js +27 -25
- package/daemon/dist/domain/ps-projection.js.map +1 -1
- package/daemon/dist/domain/queue-repository.d.ts +2 -0
- package/daemon/dist/domain/queue-repository.d.ts.map +1 -1
- package/daemon/dist/domain/queue-repository.js +16 -3
- package/daemon/dist/domain/queue-repository.js.map +1 -1
- package/daemon/dist/domain/queue-stuck-sweep.d.ts.map +1 -1
- package/daemon/dist/domain/queue-stuck-sweep.js +21 -7
- package/daemon/dist/domain/queue-stuck-sweep.js.map +1 -1
- package/daemon/dist/domain/restore-check-service.d.ts +8 -0
- package/daemon/dist/domain/restore-check-service.d.ts.map +1 -1
- package/daemon/dist/domain/restore-check-service.js +12 -3
- package/daemon/dist/domain/restore-check-service.js.map +1 -1
- package/daemon/dist/domain/restore-orchestrator.d.ts +4 -0
- package/daemon/dist/domain/restore-orchestrator.d.ts.map +1 -1
- package/daemon/dist/domain/restore-orchestrator.js +34 -5
- package/daemon/dist/domain/restore-orchestrator.js.map +1 -1
- package/daemon/dist/domain/restore-plan-preview.d.ts +4 -0
- package/daemon/dist/domain/restore-plan-preview.d.ts.map +1 -1
- package/daemon/dist/domain/restore-plan-preview.js +14 -3
- package/daemon/dist/domain/restore-plan-preview.js.map +1 -1
- package/daemon/dist/domain/rigspec-preflight.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-preflight.js +7 -6
- package/daemon/dist/domain/rigspec-preflight.js.map +1 -1
- package/daemon/dist/domain/runtime-adapter.d.ts +1 -0
- package/daemon/dist/domain/runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/domain/runtime-adapter.js.map +1 -1
- package/daemon/dist/domain/scope/scope-view-projection.d.ts +4 -2
- package/daemon/dist/domain/scope/scope-view-projection.d.ts.map +1 -1
- package/daemon/dist/domain/scope/scope-view-projection.js +6 -4
- package/daemon/dist/domain/scope/scope-view-projection.js.map +1 -1
- package/daemon/dist/domain/seat-lifecycle-service.d.ts +117 -2
- package/daemon/dist/domain/seat-lifecycle-service.d.ts.map +1 -1
- package/daemon/dist/domain/seat-lifecycle-service.js +335 -74
- package/daemon/dist/domain/seat-lifecycle-service.js.map +1 -1
- package/daemon/dist/domain/seat-restart-in-place.d.ts +292 -0
- package/daemon/dist/domain/seat-restart-in-place.d.ts.map +1 -0
- package/daemon/dist/domain/seat-restart-in-place.js +895 -0
- package/daemon/dist/domain/seat-restart-in-place.js.map +1 -0
- package/daemon/dist/domain/seat-structural-activity-service.d.ts +1 -1
- package/daemon/dist/domain/seat-structural-activity-service.d.ts.map +1 -1
- package/daemon/dist/domain/seat-structural-activity-service.js +5 -6
- package/daemon/dist/domain/seat-structural-activity-service.js.map +1 -1
- package/daemon/dist/domain/session-fingerprinter.d.ts.map +1 -1
- package/daemon/dist/domain/session-fingerprinter.js +9 -5
- package/daemon/dist/domain/session-fingerprinter.js.map +1 -1
- package/daemon/dist/domain/session-registry.d.ts +3 -0
- package/daemon/dist/domain/session-registry.d.ts.map +1 -1
- package/daemon/dist/domain/session-registry.js +6 -1
- package/daemon/dist/domain/session-registry.js.map +1 -1
- package/daemon/dist/domain/session-transport.d.ts +33 -3
- package/daemon/dist/domain/session-transport.d.ts.map +1 -1
- package/daemon/dist/domain/session-transport.js +391 -21
- package/daemon/dist/domain/session-transport.js.map +1 -1
- package/daemon/dist/domain/startup-orchestrator.d.ts +2 -0
- package/daemon/dist/domain/startup-orchestrator.d.ts.map +1 -1
- package/daemon/dist/domain/startup-orchestrator.js +4 -3
- package/daemon/dist/domain/startup-orchestrator.js.map +1 -1
- package/daemon/dist/domain/successor-session-launcher.d.ts +3 -7
- package/daemon/dist/domain/successor-session-launcher.d.ts.map +1 -1
- package/daemon/dist/domain/successor-session-launcher.js +6 -32
- package/daemon/dist/domain/successor-session-launcher.js.map +1 -1
- package/daemon/dist/domain/types.d.ts +29 -0
- package/daemon/dist/domain/types.d.ts.map +1 -1
- package/daemon/dist/domain/types.js.map +1 -1
- package/daemon/dist/domain/user-settings/settings-store.d.ts +1 -1
- package/daemon/dist/domain/user-settings/settings-store.d.ts.map +1 -1
- package/daemon/dist/domain/user-settings/settings-store.js +31 -0
- package/daemon/dist/domain/user-settings/settings-store.js.map +1 -1
- package/daemon/dist/domain/wake-resolver.js +2 -2
- package/daemon/dist/domain/wake-resolver.js.map +1 -1
- package/daemon/dist/domain/watchdog-jobs-repository.d.ts.map +1 -1
- package/daemon/dist/domain/watchdog-jobs-repository.js +19 -3
- package/daemon/dist/domain/watchdog-jobs-repository.js.map +1 -1
- package/daemon/dist/domain/whoami-service.d.ts +4 -1
- package/daemon/dist/domain/whoami-service.d.ts.map +1 -1
- package/daemon/dist/domain/whoami-service.js +25 -19
- package/daemon/dist/domain/whoami-service.js.map +1 -1
- package/daemon/dist/domain/workspace/project-read.d.ts +2 -0
- package/daemon/dist/domain/workspace/project-read.d.ts.map +1 -1
- package/daemon/dist/domain/workspace/project-read.js +19 -8
- package/daemon/dist/domain/workspace/project-read.js.map +1 -1
- package/daemon/dist/index.d.ts.map +1 -1
- package/daemon/dist/index.js +6 -0
- package/daemon/dist/index.js.map +1 -1
- package/daemon/dist/routes/chat.d.ts.map +1 -1
- package/daemon/dist/routes/chat.js +23 -2
- package/daemon/dist/routes/chat.js.map +1 -1
- package/daemon/dist/routes/proof.d.ts.map +1 -1
- package/daemon/dist/routes/proof.js +99 -10
- package/daemon/dist/routes/proof.js.map +1 -1
- package/daemon/dist/routes/provider.d.ts.map +1 -1
- package/daemon/dist/routes/provider.js +31 -0
- package/daemon/dist/routes/provider.js.map +1 -1
- package/daemon/dist/routes/queue.d.ts.map +1 -1
- package/daemon/dist/routes/queue.js +18 -6
- package/daemon/dist/routes/queue.js.map +1 -1
- package/daemon/dist/routes/rigs.js +5 -3
- package/daemon/dist/routes/rigs.js.map +1 -1
- package/daemon/dist/routes/scopes.d.ts.map +1 -1
- package/daemon/dist/routes/scopes.js +5 -3
- package/daemon/dist/routes/scopes.js.map +1 -1
- package/daemon/dist/routes/seat.d.ts.map +1 -1
- package/daemon/dist/routes/seat.js +32 -0
- package/daemon/dist/routes/seat.js.map +1 -1
- package/daemon/dist/startup.d.ts.map +1 -1
- package/daemon/dist/startup.js +12 -2
- package/daemon/dist/startup.js.map +1 -1
- package/daemon/docs/reference/agent-startup-guide.md +19 -0
- package/daemon/docs/reference/keeping-a-watch.md +156 -0
- package/daemon/docs/reference/rig-spec.md +2 -2
- package/daemon/docs/reference/sdlc-conventions.md +11 -1
- package/daemon/docs/reference/slack-app-setup.md +6 -4
- package/daemon/docs/reference/whats-new.md +135 -134
- package/daemon/specs/agents/shared/skills/core/openrig-skills/SKILL.md +1 -1
- package/dist/build-info.js +3 -3
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +2 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +7 -0
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/proof.d.ts.map +1 -1
- package/dist/commands/proof.js +11 -5
- package/dist/commands/proof.js.map +1 -1
- package/dist/commands/provider.d.ts.map +1 -1
- package/dist/commands/provider.js +72 -0
- package/dist/commands/provider.js.map +1 -1
- package/dist/commands/ps.d.ts +4 -0
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +13 -4
- package/dist/commands/ps.js.map +1 -1
- package/dist/commands/queue.d.ts +15 -5
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/queue.js +113 -37
- package/dist/commands/queue.js.map +1 -1
- package/dist/commands/scope.d.ts.map +1 -1
- package/dist/commands/scope.js +57 -36
- package/dist/commands/scope.js.map +1 -1
- package/dist/commands/seat.d.ts.map +1 -1
- package/dist/commands/seat.js +161 -10
- package/dist/commands/seat.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +4 -3
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +10 -0
- package/dist/commands/up.js.map +1 -1
- package/dist/config-store.d.ts +7 -1
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +43 -0
- package/dist/config-store.js.map +1 -1
- package/dist/lib/scope/mission-composition.d.ts +5 -1
- package/dist/lib/scope/mission-composition.d.ts.map +1 -1
- package/dist/lib/scope/mission-composition.js +61 -1
- package/dist/lib/scope/mission-composition.js.map +1 -1
- package/dist/lib/scope/scope-fs.d.ts +2 -1
- package/dist/lib/scope/scope-fs.d.ts.map +1 -1
- package/dist/lib/scope/scope-fs.js +4 -4
- package/dist/lib/scope/scope-fs.js.map +1 -1
- package/dist/lib/scope/slice-claims.d.ts +8 -0
- package/dist/lib/scope/slice-claims.d.ts.map +1 -0
- package/dist/lib/scope/slice-claims.js +88 -0
- package/dist/lib/scope/slice-claims.js.map +1 -0
- package/dist/queue-receipt.d.ts +41 -0
- package/dist/queue-receipt.d.ts.map +1 -0
- package/dist/queue-receipt.js +272 -0
- package/dist/queue-receipt.js.map +1 -0
- package/package.json +1 -1
- package/tui/dist/config/config-model.d.ts.map +1 -1
- package/tui/dist/config/config-model.js +2 -0
- package/tui/dist/config/config-model.js.map +1 -1
- package/tui/dist/hydrate.d.ts.map +1 -1
- package/tui/dist/hydrate.js +11 -4
- package/tui/dist/hydrate.js.map +1 -1
- package/tui/dist/pulse/pulse-model.d.ts +1 -0
- package/tui/dist/pulse/pulse-model.d.ts.map +1 -1
- package/tui/dist/pulse/pulse-model.js +7 -3
- package/tui/dist/pulse/pulse-model.js.map +1 -1
- package/tui/dist/pulse/render-pulse.d.ts.map +1 -1
- package/tui/dist/pulse/render-pulse.js +3 -1
- package/tui/dist/pulse/render-pulse.js.map +1 -1
- package/tui/dist/render.d.ts.map +1 -1
- package/tui/dist/render.js +26 -11
- package/tui/dist/render.js.map +1 -1
- package/tui/dist/types.d.ts +3 -0
- package/tui/dist/types.d.ts.map +1 -1
- package/ui/dist/assets/{index-D5n8EwkG.js → index-DhmxKuZf.js} +159 -159
- package/ui/dist/index.html +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CODEX_TURN_STATUS_PATTERN } from "./codex-pane-patterns.js";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
import { inspectStartupStagedText, startupSubmissionEvidence } from "./startup-submission-evidence.js";
|
|
3
4
|
export { inspectStartupStagedText } from "./startup-submission-evidence.js";
|
|
@@ -37,10 +38,6 @@ const MID_WORK_PATTERNS = [
|
|
|
37
38
|
// placeholder counts as idle only through MID_WORK_PATTERNS here, and classifySendReadiness
|
|
38
39
|
// never lets a placeholder-only verdict override a display-fresh running/needs_input hook.
|
|
39
40
|
const CODEX_EMPTY_COMPOSER_PATTERN = /^›\s+Ask Codex to do anything\s*$/;
|
|
40
|
-
// Codex's live turn-status row: a bullet, a header ("Working", or the reasoning summary Codex shows in its place),
|
|
41
|
-
// then the elapsed time and "esc to interrupt" in parentheses, e.g. "• Working (1h 09m 39s • esc to interrupt)".
|
|
42
|
-
// Completed output that merely says "Working directory: …" or "Working tree is clean." never matches.
|
|
43
|
-
const CODEX_TURN_STATUS_PATTERN = /^[•◦]\s+\S.*\((?:\d+[hms]\s*)+•\s*esc to interrupt\)/;
|
|
44
41
|
const IDLE_PROMPT_PATTERNS = [
|
|
45
42
|
/^[❯›]\s*$/, // prompt char + optional whitespace + end-of-line only
|
|
46
43
|
CODEX_EMPTY_COMPOSER_PATTERN,
|
|
@@ -48,11 +45,19 @@ const IDLE_PROMPT_PATTERNS = [
|
|
|
48
45
|
const PROMPT_DRAFT_PATTERNS = [
|
|
49
46
|
/^[❯›]\s+\S/,
|
|
50
47
|
];
|
|
48
|
+
// Claude's permission-mode footers: default, accept edits, bypass, auto and plan, optionally after a
|
|
49
|
+
// vim-mode marker such as "-- INSERT --" (#808). A suffix such as "· 1 shell" can follow the mode.
|
|
50
|
+
const CLAUDE_MODE_FOOTER = /^(?:-- [A-Z]+ -- )?(?:⏵⏵ (?:accept edits|bypass permissions|auto mode) on\b|⏸ plan mode on\b|\? for shortcuts\b)/;
|
|
51
|
+
// Sibling pattern identical to CLAUDE_MODE_FOOTER except that it ends in \? for shortcuts$,
|
|
52
|
+
// keeping unframed-composer and selectionLines checks anchored on the default footer (#808).
|
|
53
|
+
const CLAUDE_ANCHORED_MODE_FOOTER = /^(?:-- [A-Z]+ -- )?(?:⏵⏵ (?:accept edits|bypass permissions|auto mode) on\b|⏸ plan mode on\b|\? for shortcuts$)/;
|
|
54
|
+
// Permission mode status footers specifically (excluding shortcuts hint that appears in Codex footers).
|
|
55
|
+
const CLAUDE_PERMISSION_MODE_FOOTER = /(?:-- [A-Z]+ -- )?(?:⏵⏵ (?:accept edits|bypass permissions|auto mode) on\b|⏸ plan mode on\b)/;
|
|
51
56
|
// Footer hints, not proof of inactivity: Claude also renders its mode bar
|
|
52
57
|
// during a turn. Current live-status evidence must take precedence below.
|
|
53
58
|
const IDLE_STATUS_BAR_PATTERNS = [
|
|
54
59
|
/gpt-\d[\d.]* .+ · Context \[/, // Codex model/context footer
|
|
55
|
-
|
|
60
|
+
CLAUDE_PERMISSION_MODE_FOOTER, // Claude Code mode footers (#808)
|
|
56
61
|
];
|
|
57
62
|
const IDLE_TERMINAL_COMMANDS = new Set(["zsh", "bash", "sh", "fish", "nu", "tmux"]);
|
|
58
63
|
// OPR.0.4.1.10 — permission / confirmation question signatures. The numbered-selector pattern
|
|
@@ -119,9 +124,6 @@ const CLAUDE_STATUS_WARNINGS = [
|
|
|
119
124
|
/^tmux focus-events off · add 'set -g focus-events on' to ~\/\.tmux\.conf and re…$/,
|
|
120
125
|
/^You've used (?:\d|[1-9]\d)% of your weekly limit · resets \d{1,2}(?::\d{2})?(?:am|pm) \(UTC\)$/,
|
|
121
126
|
];
|
|
122
|
-
// Claude's permission-mode footers: default, accept edits, bypass, auto and plan, optionally after a
|
|
123
|
-
// vim-mode marker such as "-- INSERT --" (#808). A suffix such as "· 1 shell" can follow the mode.
|
|
124
|
-
const CLAUDE_MODE_FOOTER = /^(?:-- [A-Z]+ -- )?(?:⏵⏵ (?:accept edits|bypass permissions|auto mode) on\b|⏸ plan mode on\b|\? for shortcuts\b)/;
|
|
125
127
|
// Current Claude status rows need not end in "thinking)" or show "esc to interrupt".
|
|
126
128
|
// Completed summaries such as "✻ Crunched for 2s" lack the live ellipsis/timer shape.
|
|
127
129
|
// While a hook runs, the timer follows its label: "(running PostToolUse hook · 3m 12s · …)".
|
|
@@ -149,7 +151,7 @@ function findClaudeComposer(paneContent, options = {}) {
|
|
|
149
151
|
if (indent === undefined) {
|
|
150
152
|
// The unframed Claude prompt has the same current status/task block.
|
|
151
153
|
// Keep Codex footers and a bare prompt with no visible block on their old path.
|
|
152
|
-
if (bar < 2 ||
|
|
154
|
+
if (bar < 2 || !CLAUDE_ANCHORED_MODE_FOOTER.test(lines[bar].trim()))
|
|
153
155
|
return null;
|
|
154
156
|
prompt = lines[bar - 1] ?? "";
|
|
155
157
|
indent = /^([ \t]*)❯\s*$/.exec(prompt)?.[1];
|
|
@@ -300,7 +302,7 @@ export function classifyPaneActivity(paneContent, options = {}) {
|
|
|
300
302
|
// A complete later empty composer with a recognized Claude bar makes the preceding question history.
|
|
301
303
|
// Keep draft handling and selectors without this dialog boundary unchanged.
|
|
302
304
|
const selectionLines = claudeComposer?.framed &&
|
|
303
|
-
|
|
305
|
+
CLAUDE_ANCHORED_MODE_FOOTER.test(claudeComposer.bar) &&
|
|
304
306
|
IDLE_PROMPT_PATTERNS.some(pattern => pattern.test(claudeComposer.text)) &&
|
|
305
307
|
oldQuestionEnd >= 0 && oldQuestionEnd < promptScanLines.length - 1
|
|
306
308
|
? promptScanLines.slice(oldQuestionEnd + 1) : promptScanLines;
|
|
@@ -354,7 +356,8 @@ export function classifyPaneActivity(paneContent, options = {}) {
|
|
|
354
356
|
CLAUDE_LIVE_STATUS_PATTERN,
|
|
355
357
|
...(options.timerlessStatusIsLive ? [CLAUDE_TIMERLESS_STATUS_PATTERN] : []),
|
|
356
358
|
]);
|
|
357
|
-
|
|
359
|
+
const isClaudeStatusBar = CLAUDE_PERMISSION_MODE_FOOTER.test(idleStatusBarLine ?? "");
|
|
360
|
+
if (idleStatusBarLine && (!isClaudeStatusBar || !midWorkEvidence)) {
|
|
358
361
|
return {
|
|
359
362
|
state: "agent_idle",
|
|
360
363
|
reason: "idle_status_bar",
|
|
@@ -604,6 +607,98 @@ function countOccurrences(haystack, needle) {
|
|
|
604
607
|
}
|
|
605
608
|
return count;
|
|
606
609
|
}
|
|
610
|
+
/**
|
|
611
|
+
* Claude indents continuation lines in submitted prompts. Compare the same
|
|
612
|
+
* line content in the sent text and both captures, retaining line breaks and
|
|
613
|
+
* within-line spacing rather than allowing unrelated words to match.
|
|
614
|
+
*/
|
|
615
|
+
function normalizeVerificationText(text) {
|
|
616
|
+
return text.replace(/\r?\n[ \t]*/g, "\n");
|
|
617
|
+
}
|
|
618
|
+
/** Match the full envelope with whitespace collapsed, including body and recipient.
|
|
619
|
+
* Raw sends retain their normalized 40-character prefix and spacing. */
|
|
620
|
+
function verificationSnippet(text) {
|
|
621
|
+
const normalized = normalizeVerificationText(text);
|
|
622
|
+
const header = /^From: [^\n]+\nTo: [^\n]+\n(?:Sent: [^\n]+\n)?---\n/.exec(normalized);
|
|
623
|
+
return { snippet: header ? normalized.replace(/\s+/g, " ").trim() : normalized.slice(0, 40), envelope: !!header };
|
|
624
|
+
}
|
|
625
|
+
/** Count whole visible envelope blocks, not prefixes of longer messages.
|
|
626
|
+
* A new envelope, prompt or same-column output ends an indented user block.
|
|
627
|
+
* Whitespace is compared only after retaining boundaries and quote indentation. */
|
|
628
|
+
function countEnvelopeOccurrences(transcript, expected) {
|
|
629
|
+
const lines = transcript.split("\n");
|
|
630
|
+
let count = 0;
|
|
631
|
+
let block = null;
|
|
632
|
+
let blockIndent = 0;
|
|
633
|
+
let blockPrompted = false;
|
|
634
|
+
let inAgentOutput = false;
|
|
635
|
+
const finish = () => {
|
|
636
|
+
if (block?.join("\n").replace(/\s+/g, " ").trim() === expected)
|
|
637
|
+
count++;
|
|
638
|
+
block = null;
|
|
639
|
+
};
|
|
640
|
+
for (let i = 0; i < lines.length; i++) {
|
|
641
|
+
const line = lines[i];
|
|
642
|
+
const indent = /^[ \t]*/.exec(line)[0].length;
|
|
643
|
+
const prompted = /^[❯›]\s+/.test(line.slice(indent));
|
|
644
|
+
const header = line.slice(indent).replace(/^[❯›]\s+/, "");
|
|
645
|
+
const atBoundary = (!block && !inAgentOutput) || indent <= blockIndent;
|
|
646
|
+
const candidate = normalizeVerificationText([header, ...lines.slice(i + 1, i + 5)].join("\n"));
|
|
647
|
+
const envelopeHeader = /^From: [^\n]+\nTo: [^\n]+\n(?:Sent: [^\n]+\n)?---\n/.test(candidate);
|
|
648
|
+
if (atBoundary && envelopeHeader && (!inAgentOutput || prompted)) {
|
|
649
|
+
finish();
|
|
650
|
+
block = [header];
|
|
651
|
+
blockIndent = indent;
|
|
652
|
+
// Flat historical captures have no role columns; retain whole-block
|
|
653
|
+
// equality there instead of treating their own header/body as output.
|
|
654
|
+
blockPrompted = prompted && /^[ \t]*/.exec(lines[i + 1] ?? "")[0].length > indent;
|
|
655
|
+
inAgentOutput = false;
|
|
656
|
+
}
|
|
657
|
+
else if (atBoundary && blockPrompted && line.trim().length > 0) {
|
|
658
|
+
// Any nonblank boundary line is outside an indented user block. Deeper
|
|
659
|
+
// quotes stay in the body, and blank separators do not change its text.
|
|
660
|
+
finish();
|
|
661
|
+
inAgentOutput = true;
|
|
662
|
+
}
|
|
663
|
+
else if (atBoundary && /^[❯›](?:\s|$)/.test(line.slice(indent))) {
|
|
664
|
+
finish();
|
|
665
|
+
}
|
|
666
|
+
else if (block) {
|
|
667
|
+
block.push(line);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
finish();
|
|
671
|
+
return count;
|
|
672
|
+
}
|
|
673
|
+
/** The last prompt marker owns the current input region. Never count it or its
|
|
674
|
+
* continuation lines as submitted transcript, in either capture. If a capture
|
|
675
|
+
* ends at a historical prompt with no later input marker, leave it unconfirmed. */
|
|
676
|
+
function verificationTranscript(content) {
|
|
677
|
+
const lines = (content ?? "").replace(/\r\n/g, "\n").split("\n");
|
|
678
|
+
let inputAt = lastPromptLine(lines);
|
|
679
|
+
if (inputAt >= 0) {
|
|
680
|
+
let indent = /^[ \t]*/.exec(lines[inputAt])[0].length;
|
|
681
|
+
// Claude indents draft continuation lines. A quoted prompt on one of them
|
|
682
|
+
// belongs to the enclosing input, not a new transcript/composer boundary.
|
|
683
|
+
for (let i = inputAt - 1; i >= 0; i--) {
|
|
684
|
+
const prompt = /^([ \t]*)[❯›]/.exec(lines[i]);
|
|
685
|
+
if (prompt && prompt[1].length < indent) {
|
|
686
|
+
inputAt = i;
|
|
687
|
+
indent = prompt[1].length;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
// A visible framed composer starts at its upper rule, not its prompt.
|
|
692
|
+
// Keep quoted/indented rules in the message; require a matching lower frame.
|
|
693
|
+
if (inputAt > 0) {
|
|
694
|
+
const indent = /^[ \t]*/.exec(lines[inputAt])[0];
|
|
695
|
+
const frame = (line) => line.startsWith(indent) &&
|
|
696
|
+
/^─{3,}(?: .+ ─+)?$/.test(line.slice(indent.length).trimEnd());
|
|
697
|
+
if (frame(lines[inputAt - 1]) && lines.slice(inputAt + 1).some(frame))
|
|
698
|
+
inputAt--;
|
|
699
|
+
}
|
|
700
|
+
return (inputAt < 0 ? lines : lines.slice(0, inputAt)).join("\n");
|
|
701
|
+
}
|
|
607
702
|
/** Map a resolved fan-out target + its recipient list → the EnvelopeScope (ruling 03c35295). The
|
|
608
703
|
* transport knows the target shape + resolved seats, so it builds the honest scale daemon-side:
|
|
609
704
|
* DM / multi (full list) / rig- or pod-scoped broadcast (with seat count) / topology. */
|
|
@@ -1037,6 +1132,9 @@ export class SessionTransport {
|
|
|
1037
1132
|
const pref = guard.preference(target.nodeId);
|
|
1038
1133
|
return pref.desired || pref.effective ? target : null;
|
|
1039
1134
|
}
|
|
1135
|
+
/** Deliver text and Enter to the resolved recipient under the send guards.
|
|
1136
|
+
* With verification requested, compare rendered message counts, excluding
|
|
1137
|
+
* agent input; a confirmed render does not prove agent consumption. */
|
|
1040
1138
|
async send(sessionName, text, opts) {
|
|
1041
1139
|
const guard = this.tmuxAdapter.deliveryGuard;
|
|
1042
1140
|
if (!guard)
|
|
@@ -1069,7 +1167,44 @@ export class SessionTransport {
|
|
|
1069
1167
|
return retainedResult();
|
|
1070
1168
|
}
|
|
1071
1169
|
}
|
|
1072
|
-
|
|
1170
|
+
// #1084 — the idle wait must not occupy the seat's serial lease: a long
|
|
1171
|
+
// --wait-for-idle inside guard.operation holds up other sends and queue
|
|
1172
|
+
// creates to this seat for the whole wait. The lease-free wait, main's
|
|
1173
|
+
// quick refusals ahead of it, and the occupant binding all live in
|
|
1174
|
+
// preWaitForIdle; the lease is entered only for the idle re-check +
|
|
1175
|
+
// write. A null return means go through guard.operation exactly as on
|
|
1176
|
+
// main (guard held, target unresolvable, or a quick refusal).
|
|
1177
|
+
let sendOpts = opts;
|
|
1178
|
+
if (opts?.waitForIdleMs !== undefined && !opts.submitOnly && !opts.preWaitedIdle) {
|
|
1179
|
+
const pre = await this.preWaitForIdle(sessionName, opts, guard);
|
|
1180
|
+
if (pre === null) {
|
|
1181
|
+
// Fall through with today's path (in-lease wait / retain / throw).
|
|
1182
|
+
}
|
|
1183
|
+
else if (!pre.ok) {
|
|
1184
|
+
return pre.failure;
|
|
1185
|
+
}
|
|
1186
|
+
else {
|
|
1187
|
+
// Occupant check (review round 3): the lease starts only after the
|
|
1188
|
+
// pre-wait, so refuse here when the seat changed hands meanwhile —
|
|
1189
|
+
// exactly as main refuses with guard_target_changed. Retention must
|
|
1190
|
+
// not adopt the new occupant either, so this runs before operation.
|
|
1191
|
+
const current = guard.target(sessionName);
|
|
1192
|
+
if (JSON.stringify(pre.bound) !== JSON.stringify(current)) {
|
|
1193
|
+
return {
|
|
1194
|
+
ok: false,
|
|
1195
|
+
sessionName,
|
|
1196
|
+
sent: false,
|
|
1197
|
+
reason: "guard_target_changed",
|
|
1198
|
+
error: "Input target/occupant changed; no input written.",
|
|
1199
|
+
activity: pre.evidence.activity,
|
|
1200
|
+
waitedMs: pre.evidence.waitedMs,
|
|
1201
|
+
attempts: pre.evidence.attempts,
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
sendOpts = { ...opts, preWaitedIdle: pre.evidence, preWaitBound: pre.bound };
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
return await guard.operation(sessionName, () => this.sendUnguarded(sessionName, text, sendOpts), async (target) => {
|
|
1073
1208
|
if (opts?.submitOnly)
|
|
1074
1209
|
return { ok: false, sessionName, sent: false, reason: "typing_guard_enabled", error: "Typing guard prevents submit-only; no Enter was sent." };
|
|
1075
1210
|
this.db.transaction(() => {
|
|
@@ -1104,6 +1239,131 @@ export class SessionTransport {
|
|
|
1104
1239
|
return { ok: false, sessionName, sent: false, reason: error.code ?? "guard_unavailable", error: error.message };
|
|
1105
1240
|
}
|
|
1106
1241
|
}
|
|
1242
|
+
/**
|
|
1243
|
+
* #1084/#1103: lease-free idle wait before the serial lease, so a long
|
|
1244
|
+
* --wait-for-idle holds up no other send or queue create to this seat.
|
|
1245
|
+
* Returns the wait evidence plus the occupant bound before the wait (both
|
|
1246
|
+
* threaded into the leased send), a failure result using main's exact
|
|
1247
|
+
* reasons, or null when the send must go through guard.operation exactly
|
|
1248
|
+
* as on main. Order matters: typing-guard decision first, then main's
|
|
1249
|
+
* quick refusals (runtime identity, wait validations, session probe),
|
|
1250
|
+
* then the wait. Only the lookups sit inside try: a late throw surfaces
|
|
1251
|
+
* instead of silently running a second full wait inside the lease.
|
|
1252
|
+
*/
|
|
1253
|
+
async preWaitForIdle(sessionName, opts, guard) {
|
|
1254
|
+
const timeoutMs = opts.waitForIdleMs;
|
|
1255
|
+
if (timeoutMs === undefined)
|
|
1256
|
+
return null;
|
|
1257
|
+
let meta;
|
|
1258
|
+
let bound;
|
|
1259
|
+
try {
|
|
1260
|
+
const preTarget = guard.maybeTarget(sessionName);
|
|
1261
|
+
if (!preTarget)
|
|
1262
|
+
return null;
|
|
1263
|
+
const prePref = guard.preference(preTarget.nodeId);
|
|
1264
|
+
if (prePref.effective || prePref.desired)
|
|
1265
|
+
return null;
|
|
1266
|
+
meta = this.getSessionMeta(sessionName);
|
|
1267
|
+
bound = guard.target(sessionName);
|
|
1268
|
+
}
|
|
1269
|
+
catch {
|
|
1270
|
+
return null;
|
|
1271
|
+
}
|
|
1272
|
+
// External CLI seats never wait: main refuses them before anything else,
|
|
1273
|
+
// and a probe or wait would only delay that refusal (or mistake it for
|
|
1274
|
+
// an absent session).
|
|
1275
|
+
if (meta.attachmentType === "external_cli") {
|
|
1276
|
+
return { ok: false, failure: {
|
|
1277
|
+
ok: false,
|
|
1278
|
+
sessionName,
|
|
1279
|
+
reason: "transport_unavailable",
|
|
1280
|
+
error: `Session '${sessionName}' is attached as an external CLI node. Inbound tmux transport is unavailable for this target.`,
|
|
1281
|
+
} };
|
|
1282
|
+
}
|
|
1283
|
+
const runtime = meta.runtime;
|
|
1284
|
+
if (runtime && runtime !== "terminal" && runtime !== "claude-code") {
|
|
1285
|
+
const unverified = await this.unverifiedShellForeground(sessionName, runtime, meta.pane, meta.resumeToken);
|
|
1286
|
+
if (unverified) {
|
|
1287
|
+
return { ok: false, failure: {
|
|
1288
|
+
ok: false,
|
|
1289
|
+
sessionName,
|
|
1290
|
+
sent: false,
|
|
1291
|
+
reason: "target_runtime_unverified",
|
|
1292
|
+
error: `Refused: '${sessionName}' reports ${unverified} as the foreground command, but OpenRig could not verify its expected ${runtime} agent in the bound pane. The agent may still be running behind a wrapper. No text was sent.`,
|
|
1293
|
+
} };
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
if (opts.force) {
|
|
1297
|
+
return { ok: false, failure: {
|
|
1298
|
+
ok: false,
|
|
1299
|
+
sessionName,
|
|
1300
|
+
reason: "invalid_wait_for_idle",
|
|
1301
|
+
error: "--wait-for-idle cannot be combined with force. No text was sent.",
|
|
1302
|
+
sent: false,
|
|
1303
|
+
} };
|
|
1304
|
+
}
|
|
1305
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
1306
|
+
return { ok: false, failure: {
|
|
1307
|
+
ok: false,
|
|
1308
|
+
sessionName,
|
|
1309
|
+
reason: "invalid_wait_for_idle",
|
|
1310
|
+
error: "waitForIdleMs must be a positive number. No text was sent.",
|
|
1311
|
+
sent: false,
|
|
1312
|
+
} };
|
|
1313
|
+
}
|
|
1314
|
+
try {
|
|
1315
|
+
const target = this.absenceProbeTarget(sessionName);
|
|
1316
|
+
const observedAt = this.now().toISOString();
|
|
1317
|
+
const probe = await this.tmuxAdapter.probeSession(sessionName);
|
|
1318
|
+
if (probe.state === "absent") {
|
|
1319
|
+
this.recordSessionMissingVerdict(target, observedAt);
|
|
1320
|
+
return { ok: false, failure: {
|
|
1321
|
+
ok: false,
|
|
1322
|
+
sessionName,
|
|
1323
|
+
reason: "session_missing",
|
|
1324
|
+
error: `Session '${sessionName}' not found: tmux reports no session with this name. No text was sent. Check available sessions with: rig ps --nodes`,
|
|
1325
|
+
} };
|
|
1326
|
+
}
|
|
1327
|
+
if (probe.state === "transport_unavailable") {
|
|
1328
|
+
return { ok: false, failure: {
|
|
1329
|
+
ok: false,
|
|
1330
|
+
sessionName,
|
|
1331
|
+
reason: "tmux_unavailable",
|
|
1332
|
+
error: `The tmux server could not be reached (${probe.cause}). Whether session '${sessionName}' exists was not determined. No text was sent.`,
|
|
1333
|
+
} };
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
catch (err) {
|
|
1337
|
+
return { ok: false, failure: {
|
|
1338
|
+
ok: false,
|
|
1339
|
+
sessionName,
|
|
1340
|
+
reason: "tmux_unavailable",
|
|
1341
|
+
error: `The tmux session probe failed unexpectedly (${err instanceof Error ? err.message : String(err)}). Whether session '${sessionName}' exists was not determined. No text was sent.`,
|
|
1342
|
+
} };
|
|
1343
|
+
}
|
|
1344
|
+
const deadlineAt = Date.now() + timeoutMs;
|
|
1345
|
+
const preWait = await this.waitForIdle({
|
|
1346
|
+
sessionName,
|
|
1347
|
+
runtime: meta.runtime,
|
|
1348
|
+
attachmentType: meta.attachmentType,
|
|
1349
|
+
timeoutMs,
|
|
1350
|
+
binding: { sessionName, nodeId: meta.nodeId, occupant: meta.occupant, pane: meta.pane },
|
|
1351
|
+
readinessFromPaneOnly: opts.readinessFromPaneOnly === true,
|
|
1352
|
+
});
|
|
1353
|
+
if (!preWait.ok) {
|
|
1354
|
+
return { ok: false, failure: {
|
|
1355
|
+
ok: false,
|
|
1356
|
+
sessionName,
|
|
1357
|
+
reason: preWait.reason,
|
|
1358
|
+
error: preWait.error,
|
|
1359
|
+
sent: false,
|
|
1360
|
+
activity: preWait.activity,
|
|
1361
|
+
waitedMs: preWait.waitedMs,
|
|
1362
|
+
attempts: preWait.attempts,
|
|
1363
|
+
} };
|
|
1364
|
+
}
|
|
1365
|
+
return { ok: true, evidence: { activity: preWait.activity, waitedMs: preWait.waitedMs, attempts: preWait.attempts, deadlineAt }, bound };
|
|
1366
|
+
}
|
|
1107
1367
|
async sendUnguarded(sessionName, text, opts) {
|
|
1108
1368
|
let preVerifyContent = null;
|
|
1109
1369
|
const sessionMeta = this.getSessionMeta(sessionName);
|
|
@@ -1282,7 +1542,10 @@ export class SessionTransport {
|
|
|
1282
1542
|
}
|
|
1283
1543
|
return observe({ ok: true, sessionName, outcome: "rendered-unconfirmed", submitOnly: true });
|
|
1284
1544
|
}
|
|
1285
|
-
|
|
1545
|
+
// #1084: when send() already waited lease-free (preWaitedIdle), the wait
|
|
1546
|
+
// below is skipped; otherwise wait here, exactly as before
|
|
1547
|
+
// (typing-guard flip and unresolvable-target races keep today's behavior).
|
|
1548
|
+
if (waitForIdleMs !== undefined && !opts?.preWaitedIdle) {
|
|
1286
1549
|
const waitResult = await this.waitForIdle({
|
|
1287
1550
|
sessionName,
|
|
1288
1551
|
runtime,
|
|
@@ -1307,6 +1570,104 @@ export class SessionTransport {
|
|
|
1307
1570
|
};
|
|
1308
1571
|
}
|
|
1309
1572
|
}
|
|
1573
|
+
else if (opts?.preWaitedIdle && waitForIdleMs !== undefined) {
|
|
1574
|
+
// Occupant check (review round 3): the lease started only after the
|
|
1575
|
+
// pre-wait, so refuse when the seat changed hands meanwhile, exactly
|
|
1576
|
+
// as main refuses with guard_target_changed. No new refusal.
|
|
1577
|
+
const preGuard = this.tmuxAdapter.deliveryGuard;
|
|
1578
|
+
if (preGuard && opts.preWaitBound) {
|
|
1579
|
+
const current = preGuard.target(sessionName);
|
|
1580
|
+
if (JSON.stringify(opts.preWaitBound) !== JSON.stringify(current)) {
|
|
1581
|
+
return {
|
|
1582
|
+
ok: false,
|
|
1583
|
+
sessionName,
|
|
1584
|
+
sent: false,
|
|
1585
|
+
reason: "guard_target_changed",
|
|
1586
|
+
error: "Input target/occupant changed; no input written.",
|
|
1587
|
+
activity: opts.preWaitedIdle.activity,
|
|
1588
|
+
waitedMs: opts.preWaitedIdle.waitedMs,
|
|
1589
|
+
attempts: opts.preWaitedIdle.attempts,
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
// Idle re-check (review round 1 + bot round 2): the wait-mode contract
|
|
1594
|
+
// holds at type time too — only idle types. The budget is measured
|
|
1595
|
+
// from the ORIGINAL deadline (lease-queue time counts too), so the
|
|
1596
|
+
// total wait never exceeds what the caller asked for. Below one poll
|
|
1597
|
+
// interval, waiting buys nothing: one unraced observation decides, so
|
|
1598
|
+
// an idle seat at a dead budget still sends instead of losing a race
|
|
1599
|
+
// against a zero timer.
|
|
1600
|
+
const preEvidence = opts.preWaitedIdle;
|
|
1601
|
+
const deadlineRemainingMs = preEvidence.deadlineAt - Date.now();
|
|
1602
|
+
if (deadlineRemainingMs > this.waitForIdlePollMs) {
|
|
1603
|
+
const rewait = await this.waitForIdle({
|
|
1604
|
+
sessionName,
|
|
1605
|
+
runtime,
|
|
1606
|
+
attachmentType: sessionMeta.attachmentType,
|
|
1607
|
+
timeoutMs: deadlineRemainingMs,
|
|
1608
|
+
// Message-only: the re-wait runs on the leftover budget, but the
|
|
1609
|
+
// timeout names the configured --wait-for-idle value.
|
|
1610
|
+
timeoutLabelMs: waitForIdleMs,
|
|
1611
|
+
binding: observed?.binding,
|
|
1612
|
+
readinessFromPaneOnly: opts.readinessFromPaneOnly === true,
|
|
1613
|
+
});
|
|
1614
|
+
waitEvidence = {
|
|
1615
|
+
activity: rewait.activity,
|
|
1616
|
+
waitedMs: preEvidence.waitedMs + rewait.waitedMs,
|
|
1617
|
+
attempts: preEvidence.attempts + rewait.attempts,
|
|
1618
|
+
};
|
|
1619
|
+
if (!rewait.ok) {
|
|
1620
|
+
return {
|
|
1621
|
+
ok: false,
|
|
1622
|
+
sessionName,
|
|
1623
|
+
reason: rewait.reason,
|
|
1624
|
+
error: rewait.error,
|
|
1625
|
+
sent: false,
|
|
1626
|
+
...waitEvidence,
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
else {
|
|
1631
|
+
const recheck = await this.classifySendReadiness({
|
|
1632
|
+
sessionName,
|
|
1633
|
+
runtime,
|
|
1634
|
+
attachmentType: sessionMeta.attachmentType,
|
|
1635
|
+
binding: observed?.binding,
|
|
1636
|
+
readinessFromPaneOnly: opts.readinessFromPaneOnly === true,
|
|
1637
|
+
});
|
|
1638
|
+
if (recheck.state !== "idle") {
|
|
1639
|
+
const late = recheck.state === "needs_input"
|
|
1640
|
+
? {
|
|
1641
|
+
reason: "target_needs_input",
|
|
1642
|
+
error: `Refused: '${sessionName}' is at an interactive prompt (${recheck.reason}). A message must not select or approve it. To deliberately drive the prompt: rig send ${sessionName} "<text>" --dangerously-interact --reason "<why>". No text was sent.`,
|
|
1643
|
+
}
|
|
1644
|
+
: recheck.state === "unknown"
|
|
1645
|
+
? {
|
|
1646
|
+
reason: "target_activity_unknown",
|
|
1647
|
+
error: `Target activity could not be determined (${recheck.reason}) when the ${waitForIdleMs}ms wait ended. No text was sent.`,
|
|
1648
|
+
}
|
|
1649
|
+
: {
|
|
1650
|
+
reason: "wait_for_idle_timeout",
|
|
1651
|
+
error: `Target was still busy (${recheck.reason}) when the ${waitForIdleMs}ms wait ended. No text was sent.`,
|
|
1652
|
+
};
|
|
1653
|
+
return {
|
|
1654
|
+
ok: false,
|
|
1655
|
+
sessionName,
|
|
1656
|
+
sent: false,
|
|
1657
|
+
reason: late.reason,
|
|
1658
|
+
error: late.error,
|
|
1659
|
+
activity: recheck,
|
|
1660
|
+
waitedMs: preEvidence.waitedMs,
|
|
1661
|
+
attempts: preEvidence.attempts + 1,
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
waitEvidence = {
|
|
1665
|
+
activity: recheck,
|
|
1666
|
+
waitedMs: preEvidence.waitedMs,
|
|
1667
|
+
attempts: preEvidence.attempts + 1,
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1310
1671
|
// 2. OPR.0.4.1.10 — robust prompt/permission + mid-work guard on the DEFAULT path.
|
|
1311
1672
|
// Runs the same detector previously reachable only via --wait-for-idle: fresh runtime-hook primary
|
|
1312
1673
|
// (within the send-readiness window) + hardened capture-pane fallback. This closes the rig-send
|
|
@@ -1397,7 +1758,8 @@ export class SessionTransport {
|
|
|
1397
1758
|
if (opts?.verify) {
|
|
1398
1759
|
const captureSeq = observed ? nextCaptureSeq++ : 0;
|
|
1399
1760
|
try {
|
|
1400
|
-
preVerifyContent = await this.runStage("session_transport.pre_capture", () => this.tmuxAdapter.capturePaneContent(sessionName, 30)
|
|
1761
|
+
preVerifyContent = await this.runStage("session_transport.pre_capture", () => runtime === "terminal" || !verificationSnippet(text).envelope ? this.tmuxAdapter.capturePaneContent(sessionName, 30)
|
|
1762
|
+
: this.tmuxAdapter.capturePaneContent(sessionName, 30, { joinWrappedLines: true }));
|
|
1401
1763
|
if (observed)
|
|
1402
1764
|
observed.pre = captureSlot(preVerifyContent, this.now().toISOString(), captureSeq);
|
|
1403
1765
|
}
|
|
@@ -1472,12 +1834,19 @@ export class SessionTransport {
|
|
|
1472
1834
|
await this.sleep(500);
|
|
1473
1835
|
const captureSeq = observed ? nextCaptureSeq++ : 0;
|
|
1474
1836
|
try {
|
|
1475
|
-
const content = await this.runStage("session_transport.post_capture", () => this.tmuxAdapter.capturePaneContent(sessionName, 30)
|
|
1837
|
+
const content = await this.runStage("session_transport.post_capture", () => runtime === "terminal" || !verificationSnippet(text).envelope ? this.tmuxAdapter.capturePaneContent(sessionName, 30)
|
|
1838
|
+
: this.tmuxAdapter.capturePaneContent(sessionName, 30, { joinWrappedLines: true }));
|
|
1476
1839
|
if (observed)
|
|
1477
1840
|
observed.post = captureSlot(content, this.now().toISOString(), captureSeq);
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
const
|
|
1841
|
+
// A terminal prompt is command history, not an agent composer. Preserve
|
|
1842
|
+
// its original prefix-count verification even while a command is running.
|
|
1843
|
+
const terminal = runtime === "terminal";
|
|
1844
|
+
const { snippet, envelope } = terminal ? { snippet: text.slice(0, 40), envelope: false } : verificationSnippet(text);
|
|
1845
|
+
const transcript = terminal ? (pane) => pane ?? ""
|
|
1846
|
+
: envelope ? verificationTranscript : (pane) => normalizeVerificationText(verificationTranscript(pane));
|
|
1847
|
+
const count = envelope ? countEnvelopeOccurrences : countOccurrences;
|
|
1848
|
+
const preCount = count(transcript(preVerifyContent), snippet);
|
|
1849
|
+
const postCount = count(transcript(content), snippet);
|
|
1481
1850
|
const verified = postCount > preCount;
|
|
1482
1851
|
return observe({ ok: true, sessionName, ...interaction, verified, outcome: verified ? "delivered" : "rendered-unconfirmed", ...(sendAdvisory ? { warning: sendAdvisory } : {}), ...(waitMode ? { sent: true, ...waitEvidence } : {}) });
|
|
1483
1852
|
}
|
|
@@ -1510,6 +1879,7 @@ export class SessionTransport {
|
|
|
1510
1879
|
const deadline = Date.now() + input.timeoutMs;
|
|
1511
1880
|
let attempts = 0;
|
|
1512
1881
|
let last = null;
|
|
1882
|
+
const labelMs = input.timeoutLabelMs ?? input.timeoutMs;
|
|
1513
1883
|
const expire = () => {
|
|
1514
1884
|
const count = `${attempts} observation${attempts === 1 ? "" : "s"}`;
|
|
1515
1885
|
const activity = last ?? {
|
|
@@ -1521,14 +1891,14 @@ export class SessionTransport {
|
|
|
1521
1891
|
ok: false,
|
|
1522
1892
|
reason: "target_activity_unknown",
|
|
1523
1893
|
error: last
|
|
1524
|
-
? `Target activity could not be determined (${activity.reason}) when the ${
|
|
1525
|
-
: `Target activity could not be determined: no observation completed within the ${
|
|
1894
|
+
? `Target activity could not be determined (${activity.reason}) when the ${labelMs}ms wait ended (${count}). No text was sent.`
|
|
1895
|
+
: `Target activity could not be determined: no observation completed within the ${labelMs}ms wait. No text was sent.`,
|
|
1526
1896
|
activity, waitedMs: input.timeoutMs, attempts,
|
|
1527
1897
|
}
|
|
1528
1898
|
: {
|
|
1529
1899
|
ok: false,
|
|
1530
1900
|
reason: "wait_for_idle_timeout",
|
|
1531
|
-
error: `Target was still busy (${activity.reason}) when the ${
|
|
1901
|
+
error: `Target was still busy (${activity.reason}) when the ${labelMs}ms wait ended (${count}). No text was sent.`,
|
|
1532
1902
|
activity, waitedMs: input.timeoutMs, attempts,
|
|
1533
1903
|
};
|
|
1534
1904
|
};
|