oh-my-codex 0.20.2 → 0.20.3
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/Cargo.lock +7 -6
- package/Cargo.toml +1 -1
- package/README.md +26 -0
- package/crates/omx-runtime/Cargo.toml +1 -0
- package/crates/omx-runtime/src/main.rs +25 -2
- package/crates/omx-runtime/tests/execution.rs +219 -0
- package/crates/omx-runtime-core/src/dispatch.rs +96 -10
- package/crates/omx-runtime-core/src/engine.rs +839 -29
- package/crates/omx-runtime-core/src/lib.rs +8 -0
- package/dist/agents/__tests__/definitions.test.js +81 -0
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +25 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts +2 -1
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js.map +1 -1
- package/dist/auth/hotswap.d.ts +6 -0
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +85 -15
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +60 -6
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +80 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +103 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +136 -0
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +258 -4
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +287 -1
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +4 -1
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +84 -6
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +3 -3
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +3 -3
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +56 -171
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan.test.js +37 -111
- package/dist/cli/__tests__/ralplan.test.js.map +1 -1
- package/dist/cli/__tests__/resume.test.js +11 -10
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-search-help.test.js +25 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +42 -4
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +105 -7
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +46 -0
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +2 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/doctor.d.ts +3 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +15 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +4 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +138 -38
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.js +2 -2
- package/dist/cli/mcp-parity.js.map +1 -1
- package/dist/cli/native-hook-claim-journal.d.ts +16 -5
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -1
- package/dist/cli/native-hook-claim-journal.js +42 -29
- package/dist/cli/native-hook-claim-journal.js.map +1 -1
- package/dist/cli/ralph.js +2 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +4 -8
- package/dist/cli/ralplan.d.ts.map +1 -1
- package/dist/cli/ralplan.js +19 -112
- package/dist/cli/ralplan.js.map +1 -1
- package/dist/cli/session-search.d.ts +5 -0
- package/dist/cli/session-search.d.ts.map +1 -1
- package/dist/cli/session-search.js +87 -0
- package/dist/cli/session-search.js.map +1 -1
- package/dist/cli/setup.d.ts +5 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +80 -31
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/uninstall.d.ts +9 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +61 -19
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +330 -1
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +2 -2
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/models.test.js +67 -3
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/generator.d.ts +4 -20
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +499 -119
- package/dist/config/generator.js.map +1 -1
- package/dist/config/models.d.ts +12 -2
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +15 -1
- package/dist/config/models.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +2 -2
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +4 -4
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +238 -543
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +38 -4
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +96 -9
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +531 -12
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +155 -23
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +482 -32
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +68 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +7 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +43 -4
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/session.test.js +348 -2
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +1 -1
- package/dist/hooks/session.d.ts +26 -2
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +169 -13
- package/dist/hooks/session.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +57 -7
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +16 -0
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +79 -4
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/code-intel-server.test.js +31 -3
- package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -1
- package/dist/mcp/__tests__/wiki-server.test.js +18 -0
- package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
- package/dist/mcp/code-intel-server.d.ts.map +1 -1
- package/dist/mcp/code-intel-server.js +13 -3
- package/dist/mcp/code-intel-server.js.map +1 -1
- package/dist/mcp/wiki-server.d.ts +11 -0
- package/dist/mcp/wiki-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.js +9 -2
- package/dist/mcp/wiki-server.js.map +1 -1
- package/dist/modes/__tests__/base-tmux-pane.test.js +4 -4
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
- package/dist/notifications/temp-contract.d.ts.map +1 -1
- package/dist/notifications/temp-contract.js +4 -0
- package/dist/notifications/temp-contract.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +4 -4
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +8 -8
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +134 -10
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts +2 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts.map +1 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js +46 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
- package/dist/ralplan/__tests__/runtime.test.js +8 -4
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +58 -50
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/documented-leader-preflight.d.ts +34 -0
- package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
- package/dist/ralplan/documented-leader-preflight.js +58 -0
- package/dist/ralplan/documented-leader-preflight.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +1 -0
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +11 -7
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/__tests__/bridge.test.js +42 -1
- package/dist/runtime/__tests__/bridge.test.js.map +1 -1
- package/dist/runtime/bridge.d.ts +12 -0
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js +52 -1
- package/dist/runtime/bridge.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +2620 -487
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts +2 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js +108 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js.map +1 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +46 -173
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +39 -159
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +254 -2
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts +4 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +11013 -1153
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-fallback-watcher.js +82 -108
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +74 -3
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts +9 -0
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +234 -79
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +39 -13
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +12 -4
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +365 -44
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +19 -18
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts +3 -0
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +37 -28
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +28 -2
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +1 -0
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +48 -3
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +2796 -13
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/state/__tests__/mode-state-context.test.js +54 -0
- package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +2 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/mode-state-context.d.ts +5 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +59 -0
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +24 -245
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -1
- package/dist/subagents/tracker.d.ts +1 -82
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +3 -275
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/api-interop.test.js +91 -1
- package/dist/team/__tests__/api-interop.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +52 -10
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/idle-nudge.test.js +45 -15
- package/dist/team/__tests__/idle-nudge.test.js.map +1 -1
- package/dist/team/__tests__/mcp-comm.test.js +93 -27
- package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +110 -3
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/runtime-cli.test.js +9 -0
- package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +3204 -335
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +2359 -142
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +804 -36
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/team-ops-contract.test.js +6 -0
- package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +3049 -784
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +38 -2
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/__tests__/worktree.test.js +6 -0
- package/dist/team/__tests__/worktree.test.js.map +1 -1
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js +15 -9
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/exact-pane.d.ts +23 -0
- package/dist/team/exact-pane.d.ts.map +1 -0
- package/dist/team/exact-pane.js +133 -0
- package/dist/team/exact-pane.js.map +1 -0
- package/dist/team/idle-nudge.d.ts +12 -1
- package/dist/team/idle-nudge.d.ts.map +1 -1
- package/dist/team/idle-nudge.js +41 -14
- package/dist/team/idle-nudge.js.map +1 -1
- package/dist/team/model-contract.d.ts +2 -5
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +59 -17
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/runtime.d.ts +1 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +1244 -180
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts +13 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +1430 -384
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/dispatch.d.ts.map +1 -1
- package/dist/team/state/dispatch.js +26 -8
- package/dist/team/state/dispatch.js.map +1 -1
- package/dist/team/state/locks.d.ts.map +1 -1
- package/dist/team/state/locks.js +61 -13
- package/dist/team/state/locks.js.map +1 -1
- package/dist/team/state/tasks.d.ts.map +1 -1
- package/dist/team/state/tasks.js +4 -3
- package/dist/team/state/tasks.js.map +1 -1
- package/dist/team/state.d.ts +67 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +636 -129
- package/dist/team/state.js.map +1 -1
- package/dist/team/team-ops.d.ts +5 -0
- package/dist/team/team-ops.d.ts.map +1 -1
- package/dist/team/team-ops.js +4 -0
- package/dist/team/team-ops.js.map +1 -1
- package/dist/team/tmux-session.d.ts +123 -23
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +1250 -291
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worktree.d.ts.map +1 -1
- package/dist/team/worktree.js +4 -0
- package/dist/team/worktree.js.map +1 -1
- package/dist/utils/__tests__/file-durability.test.d.ts +2 -0
- package/dist/utils/__tests__/file-durability.test.d.ts.map +1 -0
- package/dist/utils/__tests__/file-durability.test.js +57 -0
- package/dist/utils/__tests__/file-durability.test.js.map +1 -0
- package/dist/utils/file-durability.d.ts +15 -0
- package/dist/utils/file-durability.d.ts.map +1 -0
- package/dist/utils/file-durability.js +37 -0
- package/dist/utils/file-durability.js.map +1 -0
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +3 -0
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
- package/dist/wiki/lint.d.ts +4 -1
- package/dist/wiki/lint.d.ts.map +1 -1
- package/dist/wiki/lint.js +3 -2
- package/dist/wiki/lint.js.map +1 -1
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +24 -0
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -4
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +3 -2
- package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
- package/skills/ralph/SKILL.md +6 -4
- package/skills/ralplan/SKILL.md +3 -2
- package/skills/team/SKILL.md +13 -9
- package/src/scripts/__tests__/codex-native-hook.test.ts +2826 -497
- package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +48 -185
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +44 -177
- package/src/scripts/__tests__/smoke-packed-install.test.ts +320 -2
- package/src/scripts/codex-native-hook.ts +10715 -1069
- package/src/scripts/notify-fallback-watcher.ts +84 -115
- package/src/scripts/notify-hook/auto-nudge.ts +71 -3
- package/src/scripts/notify-hook/team-dispatch.ts +242 -75
- package/src/scripts/notify-hook/team-leader-nudge.ts +40 -18
- package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
- package/src/scripts/notify-hook/team-worker-stop.ts +20 -16
- package/src/scripts/notify-hook/team-worker.ts +39 -26
- package/src/scripts/notify-hook/tmux-injection.ts +28 -2
- package/src/scripts/notify-hook.ts +1 -0
- package/src/scripts/smoke-packed-install.ts +3196 -14
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts +0 -2
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts.map +0 -1
- package/dist/subagents/__tests__/adapted-role-binding.test.js +0 -988
- package/dist/subagents/__tests__/adapted-role-binding.test.js.map +0 -1
- package/dist/subagents/adapted-role-binding.d.ts +0 -17
- package/dist/subagents/adapted-role-binding.d.ts.map +0 -1
- package/dist/subagents/adapted-role-binding.js +0 -75
- package/dist/subagents/adapted-role-binding.js.map +0 -1
|
@@ -12,7 +12,14 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
12
12
|
const __dirname = dirname(__filename);
|
|
13
13
|
import { runProcess } from './process-runner.js';
|
|
14
14
|
import { resolvePaneTarget, resolveSessionToPane } from './tmux-injection.js';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
EXACT_PANE_UNAVAILABLE_REASON,
|
|
17
|
+
evaluatePaneInjectionReadiness,
|
|
18
|
+
normalizeExactPaneId,
|
|
19
|
+
sendPaneInput,
|
|
20
|
+
verifyExactPaneLive,
|
|
21
|
+
verifyExactPaneOwnerLive,
|
|
22
|
+
} from './team-tmux-guard.js';
|
|
16
23
|
import {
|
|
17
24
|
buildCapturePaneArgv,
|
|
18
25
|
normalizeTmuxCapture,
|
|
@@ -456,23 +463,83 @@ async function writeBridgeDispatchCompat(stateDir, teamName, requests) {
|
|
|
456
463
|
await writeJsonAtomic(compatPath, { records });
|
|
457
464
|
}
|
|
458
465
|
|
|
466
|
+
function explicitPaneIdentity(value) {
|
|
467
|
+
const rawPaneId = safeString(value).trim();
|
|
468
|
+
return { provided: rawPaneId !== '', paneId: normalizeExactPaneId(rawPaneId), rawPaneId };
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function positivePanePid(value) {
|
|
472
|
+
return Number.isInteger(value) && Number(value) > 0 ? Number(value) : undefined;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
function resolveAddressedWorker(request, config) {
|
|
477
|
+
const workers = Array.isArray(config?.workers) ? config.workers : [];
|
|
478
|
+
if (Number.isFinite(request?.worker_index)) {
|
|
479
|
+
const worker = workers.find((candidate) => Number(candidate?.index) === Number(request.worker_index));
|
|
480
|
+
if (worker) return worker;
|
|
481
|
+
}
|
|
482
|
+
const recipient = safeString(request?.to_worker).trim();
|
|
483
|
+
return workers.find((candidate) => safeString(candidate?.name).trim() === recipient) || null;
|
|
484
|
+
}
|
|
459
485
|
|
|
460
|
-
function
|
|
486
|
+
function resolveConfiguredPaneIdentity(request, config) {
|
|
461
487
|
if (request.to_worker === 'leader-fixed') {
|
|
462
|
-
|
|
463
|
-
if (leaderPaneId) return { type: 'pane', value: leaderPaneId };
|
|
464
|
-
return null;
|
|
488
|
+
return { source: 'leader_pane_id', expectedPanePid: positivePanePid(config?.leader_pane_pid), expectedPaneOwnerId: safeString(config?.tmux_pane_owner_id).trim(), ...explicitPaneIdentity(config?.leader_pane_id) };
|
|
465
489
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
490
|
+
const worker = resolveAddressedWorker(request, config);
|
|
491
|
+
const expectedPanePid = positivePanePid(worker?.pid);
|
|
492
|
+
return { source: 'worker_pane_id', expectedPanePid, expectedPaneOwnerId: safeString(config?.tmux_pane_owner_id).trim(), ...explicitPaneIdentity(worker?.pane_id) };
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function resolveDispatchTarget(request, config) {
|
|
496
|
+
const requestPane = explicitPaneIdentity(request?.pane_id);
|
|
497
|
+
const configuredPane = resolveConfiguredPaneIdentity(request, config);
|
|
498
|
+
const hudPaneId = explicitPaneIdentity(config?.hud_pane_id).paneId;
|
|
499
|
+
if (requestPane.provided) {
|
|
500
|
+
if (!requestPane.paneId) {
|
|
501
|
+
return { failure: 'invalid_explicit_pane', paneId: requestPane.paneId, paneSource: 'request_pane_id', rawPaneId: requestPane.rawPaneId };
|
|
502
|
+
}
|
|
503
|
+
if (requestPane.paneId === hudPaneId) {
|
|
504
|
+
return { failure: 'hud_pane_target', paneId: requestPane.paneId, paneSource: 'request_pane_id' };
|
|
505
|
+
}
|
|
506
|
+
if (configuredPane.provided) {
|
|
507
|
+
if (!configuredPane.paneId) {
|
|
508
|
+
return { failure: 'invalid_explicit_pane', paneId: configuredPane.paneId, paneSource: configuredPane.source, rawPaneId: configuredPane.rawPaneId };
|
|
509
|
+
}
|
|
510
|
+
if (requestPane.paneId !== configuredPane.paneId) {
|
|
511
|
+
return {
|
|
512
|
+
failure: 'exact_pane_mismatch',
|
|
513
|
+
paneId: requestPane.paneId,
|
|
514
|
+
paneSource: 'request_pane_id',
|
|
515
|
+
configuredPaneId: configuredPane.paneId,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if (!positivePanePid(configuredPane.expectedPanePid)) {
|
|
520
|
+
return { failure: 'missing_exact_pane_pid', paneId: requestPane.paneId, paneSource: configuredPane.source };
|
|
521
|
+
}
|
|
522
|
+
if (!configuredPane.expectedPaneOwnerId) {
|
|
523
|
+
return { failure: 'missing_expected_pane_owner', paneId: requestPane.paneId, paneSource: configuredPane.source };
|
|
524
|
+
}
|
|
525
|
+
return { target: { type: 'pane', value: requestPane.paneId }, exactPaneId: requestPane.paneId, expectedPanePid: configuredPane.expectedPanePid, expectedPaneOwnerId: configuredPane.expectedPaneOwnerId, expectedHudPaneId: hudPaneId, source: 'request_pane_id', reason: 'explicit_request_pane_id' };
|
|
470
526
|
}
|
|
471
|
-
if (
|
|
472
|
-
|
|
527
|
+
if (configuredPane.provided) {
|
|
528
|
+
if (!configuredPane.paneId) {
|
|
529
|
+
return { failure: 'invalid_explicit_pane', paneId: configuredPane.paneId, paneSource: configuredPane.source, rawPaneId: configuredPane.rawPaneId };
|
|
530
|
+
}
|
|
531
|
+
if (configuredPane.paneId === hudPaneId) {
|
|
532
|
+
return { failure: 'hud_pane_target', paneId: configuredPane.paneId, paneSource: configuredPane.source };
|
|
533
|
+
}
|
|
534
|
+
if (!positivePanePid(configuredPane.expectedPanePid)) {
|
|
535
|
+
return { failure: 'missing_exact_pane_pid', paneId: configuredPane.paneId, paneSource: configuredPane.source };
|
|
536
|
+
}
|
|
537
|
+
if (!configuredPane.expectedPaneOwnerId) {
|
|
538
|
+
return { failure: 'missing_expected_pane_owner', paneId: configuredPane.paneId, paneSource: configuredPane.source };
|
|
539
|
+
}
|
|
540
|
+
return { target: { type: 'pane', value: configuredPane.paneId }, exactPaneId: configuredPane.paneId, expectedPanePid: configuredPane.expectedPanePid, expectedPaneOwnerId: configuredPane.expectedPaneOwnerId, expectedHudPaneId: hudPaneId, source: configuredPane.source, reason: configuredPane.source };
|
|
473
541
|
}
|
|
474
|
-
|
|
475
|
-
return null;
|
|
542
|
+
return { target: null };
|
|
476
543
|
}
|
|
477
544
|
|
|
478
545
|
async function appendLeaderNotificationDeferredEvent({
|
|
@@ -754,13 +821,52 @@ const INJECT_VERIFY_DELAY_MS = 250;
|
|
|
754
821
|
const INJECT_VERIFY_ROUNDS = 3;
|
|
755
822
|
|
|
756
823
|
async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
757
|
-
const
|
|
824
|
+
const dispatchTarget = resolveDispatchTarget(request, config);
|
|
825
|
+
if (dispatchTarget.failure) {
|
|
826
|
+
if (dispatchTarget.failure !== 'exact_pane_mismatch' && dispatchTarget.failure !== 'invalid_explicit_pane') {
|
|
827
|
+
return {
|
|
828
|
+
ok: false,
|
|
829
|
+
reason: dispatchTarget.failure,
|
|
830
|
+
pane: dispatchTarget.paneId || null,
|
|
831
|
+
pane_source: dispatchTarget.paneSource || null,
|
|
832
|
+
exact_pane_proof: null,
|
|
833
|
+
tmux_injection_attempted: false,
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
const paneProof = dispatchTarget.failure === 'exact_pane_mismatch'
|
|
837
|
+
? {
|
|
838
|
+
reason: 'exact_pane_mismatch',
|
|
839
|
+
proof: {
|
|
840
|
+
status: 'unavailable',
|
|
841
|
+
paneId: dispatchTarget.paneId,
|
|
842
|
+
reason: 'pane_mismatch',
|
|
843
|
+
detail: `configured pane is ${dispatchTarget.configuredPaneId}`,
|
|
844
|
+
},
|
|
845
|
+
}
|
|
846
|
+
: await verifyExactPaneLive(dispatchTarget.rawPaneId);
|
|
847
|
+
return {
|
|
848
|
+
ok: false,
|
|
849
|
+
reason: paneProof.reason,
|
|
850
|
+
pane: dispatchTarget.paneId || null,
|
|
851
|
+
pane_source: dispatchTarget.paneSource || null,
|
|
852
|
+
exact_pane_proof: paneProof.proof || null,
|
|
853
|
+
tmux_injection_attempted: false,
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
const target = dispatchTarget.target;
|
|
758
858
|
if (!target) {
|
|
759
859
|
return { ok: false, reason: 'missing_tmux_target' };
|
|
760
860
|
}
|
|
761
861
|
const leaderTargeted = request.to_worker === 'leader-fixed';
|
|
762
862
|
let resolution;
|
|
763
|
-
if (
|
|
863
|
+
if (dispatchTarget.exactPaneId) {
|
|
864
|
+
resolution = {
|
|
865
|
+
paneTarget: dispatchTarget.exactPaneId,
|
|
866
|
+
reason: dispatchTarget.reason,
|
|
867
|
+
source: dispatchTarget.source,
|
|
868
|
+
};
|
|
869
|
+
} else if (target.type === 'session') {
|
|
764
870
|
const paneId = await resolveSessionToPane(target.value).catch(() => null);
|
|
765
871
|
resolution = paneId
|
|
766
872
|
? { paneTarget: paneId, reason: 'session_target_resolved' }
|
|
@@ -771,13 +877,26 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
771
877
|
if (!resolution.paneTarget) {
|
|
772
878
|
return { ok: false, reason: `target_resolution_failed:${resolution.reason}` };
|
|
773
879
|
}
|
|
774
|
-
|
|
880
|
+
|
|
881
|
+
const exactPaneId = dispatchTarget.exactPaneId || normalizeExactPaneId(resolution.paneTarget);
|
|
882
|
+
const exactPaneFailure = (paneProof, tmuxInjectionAttempted) => ({
|
|
883
|
+
ok: false,
|
|
884
|
+
reason: paneProof.reason,
|
|
885
|
+
pane: resolution.paneTarget,
|
|
886
|
+
pane_source: resolution.source || null,
|
|
887
|
+
exact_pane_proof: paneProof.proof || null,
|
|
888
|
+
tmux_injection_attempted: tmuxInjectionAttempted,
|
|
889
|
+
});
|
|
775
890
|
const paneGuard = await evaluatePaneInjectionReadiness(resolution.paneTarget, {
|
|
776
891
|
skipIfScrolling: true,
|
|
777
892
|
requireRunningAgent: leaderTargeted,
|
|
778
893
|
requireReady: false,
|
|
779
894
|
requireIdle: false,
|
|
780
895
|
requireObservableState: leaderTargeted,
|
|
896
|
+
exactPaneId,
|
|
897
|
+
expectedPanePid: dispatchTarget.expectedPanePid,
|
|
898
|
+
expectedPaneOwnerId: dispatchTarget.expectedPaneOwnerId,
|
|
899
|
+
expectedHudPaneId: dispatchTarget.expectedHudPaneId,
|
|
781
900
|
});
|
|
782
901
|
if (!paneGuard.ok) {
|
|
783
902
|
return {
|
|
@@ -787,16 +906,26 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
787
906
|
pane_source: resolution.source || null,
|
|
788
907
|
readiness_evidence: paneGuard.readinessEvidence || null,
|
|
789
908
|
pane_current_command: paneGuard.paneCurrentCommand || null,
|
|
909
|
+
exact_pane_proof: paneGuard.exactPaneProof || null,
|
|
790
910
|
tmux_injection_attempted: false,
|
|
791
911
|
};
|
|
792
912
|
}
|
|
793
913
|
|
|
914
|
+
let exactPaneProof = paneGuard.exactPaneProof || null;
|
|
915
|
+
const verifyExplicitPane = async () => {
|
|
916
|
+
const paneProof = await verifyExactPaneOwnerLive(exactPaneId, dispatchTarget.expectedPanePid, dispatchTarget.expectedPaneOwnerId);
|
|
917
|
+
exactPaneProof = paneProof.proof || null;
|
|
918
|
+
return paneProof;
|
|
919
|
+
};
|
|
920
|
+
|
|
794
921
|
const attemptCountAtStart = Number.isFinite(request.attempt_count)
|
|
795
922
|
? Math.max(0, Math.floor(request.attempt_count))
|
|
796
923
|
: 0;
|
|
797
924
|
const submitKeyPresses = resolveWorkerCliForRequest(request, config) === 'claude' ? 1 : 2;
|
|
798
925
|
let preCaptureHasTrigger = false;
|
|
799
926
|
if (attemptCountAtStart >= 1) {
|
|
927
|
+
const preCaptureProof = await verifyExplicitPane();
|
|
928
|
+
if (!preCaptureProof.ok) return exactPaneFailure(preCaptureProof, false);
|
|
800
929
|
try {
|
|
801
930
|
// Narrow capture (8 lines) to scope check to input area, not scrollback output
|
|
802
931
|
const preCapture = await runProcess('tmux', buildJoinedCapturePaneArgv(resolution.paneTarget, 8), 2000);
|
|
@@ -809,16 +938,20 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
809
938
|
// Retype whenever trigger text is NOT in the narrow input area, regardless of attempt count.
|
|
810
939
|
// Pre-0.7.4 bug: 80-line capture matched trigger in scrollback output, falsely skipping retype.
|
|
811
940
|
const shouldTypePrompt = attemptCountAtStart === 0 || !preCaptureHasTrigger;
|
|
812
|
-
if (shouldTypePrompt) {
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
941
|
+
if (shouldTypePrompt && attemptCountAtStart >= 1) {
|
|
942
|
+
// Clear stale text in input buffer before retyping (mirrors sync path tmux-session.ts:1270)
|
|
943
|
+
const clearProof = await verifyExplicitPane();
|
|
944
|
+
if (!clearProof.ok) return exactPaneFailure(clearProof, false);
|
|
945
|
+
await runProcess('tmux', ['send-keys', '-t', resolution.paneTarget, 'C-u'], 1000).catch(() => {});
|
|
946
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
818
947
|
}
|
|
819
948
|
|
|
820
949
|
const sendResult = await sendPaneInput({
|
|
821
950
|
paneTarget: resolution.paneTarget,
|
|
951
|
+
exactPaneId,
|
|
952
|
+
expectedPanePid: dispatchTarget.expectedPanePid,
|
|
953
|
+
expectedPaneOwnerId: dispatchTarget.expectedPaneOwnerId,
|
|
954
|
+
expectedHudPaneId: dispatchTarget.expectedHudPaneId,
|
|
822
955
|
prompt: request.trigger_message,
|
|
823
956
|
submitKeyPresses,
|
|
824
957
|
typePrompt: shouldTypePrompt,
|
|
@@ -832,9 +965,11 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
832
965
|
pane_source: resolution.source || null,
|
|
833
966
|
readiness_evidence: paneGuard.readinessEvidence || null,
|
|
834
967
|
pane_current_command: paneGuard.paneCurrentCommand || null,
|
|
968
|
+
exact_pane_proof: sendResult.exactPaneProof || null,
|
|
835
969
|
tmux_injection_attempted: true,
|
|
836
970
|
};
|
|
837
971
|
}
|
|
972
|
+
exactPaneProof = sendResult.exactPaneProof || exactPaneProof;
|
|
838
973
|
|
|
839
974
|
// Post-injection verification: confirm the trigger text was consumed.
|
|
840
975
|
// Fixes #391: without this, dispatch marks 'notified' even when the worker
|
|
@@ -843,72 +978,102 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
843
978
|
const verifyWideArgv = buildJoinedCapturePaneArgv(resolution.paneTarget);
|
|
844
979
|
for (let round = 0; round < INJECT_VERIFY_ROUNDS; round++) {
|
|
845
980
|
await new Promise((r) => setTimeout(r, INJECT_VERIFY_DELAY_MS));
|
|
981
|
+
const narrowProof = await verifyExplicitPane();
|
|
982
|
+
if (!narrowProof.ok) return exactPaneFailure(narrowProof, true);
|
|
983
|
+
|
|
984
|
+
let narrowCap;
|
|
846
985
|
try {
|
|
847
986
|
// Primary: trigger text no longer in narrow input area.
|
|
848
987
|
// Secondary guard: also inspect the recent non-empty tail of wide capture.
|
|
849
988
|
// This avoids false confirmations when Codex leaves the unsent draft just
|
|
850
989
|
// above a large blank area (narrow capture misses it) while still avoiding
|
|
851
990
|
// full-scrollback false positives.
|
|
852
|
-
|
|
853
|
-
const wideCap = await runProcess('tmux', verifyWideArgv, 2000);
|
|
854
|
-
const triggerInNarrow = capturedPaneContainsTrigger(narrowCap.stdout, request.trigger_message);
|
|
855
|
-
const triggerNearTail = capturedPaneContainsTriggerNearTail(wideCap.stdout, request.trigger_message);
|
|
856
|
-
if (triggerInNarrow || triggerNearTail) {
|
|
857
|
-
// Draft is still visible, so C-m has not actually submitted it yet.
|
|
858
|
-
// Do not let transient spinner/active-task text mask an unsent draft.
|
|
859
|
-
await sendPaneInput({
|
|
860
|
-
paneTarget: resolution.paneTarget,
|
|
861
|
-
prompt: request.trigger_message,
|
|
862
|
-
submitKeyPresses,
|
|
863
|
-
typePrompt: false,
|
|
864
|
-
}).catch(() => {});
|
|
865
|
-
continue;
|
|
866
|
-
}
|
|
867
|
-
// Worker is actively processing (mirrors sync path tmux-session.ts:1292-1294)
|
|
868
|
-
if (paneHasActiveTask(wideCap.stdout)) {
|
|
869
|
-
runtimeExec({ command: 'MarkDelivered', request_id: request.request_id }, stateDir, request.team_name);
|
|
870
|
-
return {
|
|
871
|
-
ok: true,
|
|
872
|
-
reason: 'tmux_send_keys_confirmed_active_task',
|
|
873
|
-
pane: resolution.paneTarget,
|
|
874
|
-
pane_source: resolution.source || null,
|
|
875
|
-
readiness_evidence: paneGuard.readinessEvidence || null,
|
|
876
|
-
pane_current_command: paneGuard.paneCurrentCommand || null,
|
|
877
|
-
tmux_injection_attempted: true,
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
// Do not declare success while a pane is not input-ready. Otherwise a
|
|
881
|
-
// pre-ready send can be marked "confirmed" and later appear as a stuck
|
|
882
|
-
// unsent draft once the UI finishes loading. This includes leader-fixed:
|
|
883
|
-
// its Codex UI can show "tab to queue message" while busy, and marking
|
|
884
|
-
// delivered before queue/consumption confirmation loses the orchestration
|
|
885
|
-
// nudge until a human presses Tab manually.
|
|
886
|
-
if (!paneLooksReady(wideCap.stdout)) {
|
|
887
|
-
continue;
|
|
888
|
-
}
|
|
889
|
-
if (!triggerInNarrow && !triggerNearTail) {
|
|
890
|
-
runtimeExec({ command: 'MarkDelivered', request_id: request.request_id }, stateDir, request.team_name);
|
|
891
|
-
return {
|
|
892
|
-
ok: true,
|
|
893
|
-
reason: 'tmux_send_keys_confirmed',
|
|
894
|
-
pane: resolution.paneTarget,
|
|
895
|
-
pane_source: resolution.source || null,
|
|
896
|
-
readiness_evidence: paneGuard.readinessEvidence || null,
|
|
897
|
-
pane_current_command: paneGuard.paneCurrentCommand || null,
|
|
898
|
-
tmux_injection_attempted: true,
|
|
899
|
-
};
|
|
900
|
-
}
|
|
991
|
+
narrowCap = await runProcess('tmux', verifyNarrowArgv, 2000);
|
|
901
992
|
} catch {
|
|
902
|
-
//
|
|
993
|
+
// Capture failed; fall through to retry C-m.
|
|
994
|
+
}
|
|
995
|
+
if (narrowCap) {
|
|
996
|
+
const wideProof = await verifyExplicitPane();
|
|
997
|
+
if (!wideProof.ok) return exactPaneFailure(wideProof, true);
|
|
998
|
+
try {
|
|
999
|
+
const wideCap = await runProcess('tmux', verifyWideArgv, 2000);
|
|
1000
|
+
const triggerInNarrow = capturedPaneContainsTrigger(narrowCap.stdout, request.trigger_message);
|
|
1001
|
+
const triggerNearTail = capturedPaneContainsTriggerNearTail(wideCap.stdout, request.trigger_message);
|
|
1002
|
+
if (triggerInNarrow || triggerNearTail) {
|
|
1003
|
+
// Draft is still visible, so C-m has not actually submitted it yet.
|
|
1004
|
+
// Do not let transient spinner/active-task text mask an unsent draft.
|
|
1005
|
+
const retrySend = await sendPaneInput({
|
|
1006
|
+
paneTarget: resolution.paneTarget,
|
|
1007
|
+
exactPaneId,
|
|
1008
|
+
expectedPanePid: dispatchTarget.expectedPanePid,
|
|
1009
|
+
expectedPaneOwnerId: dispatchTarget.expectedPaneOwnerId,
|
|
1010
|
+
expectedHudPaneId: dispatchTarget.expectedHudPaneId,
|
|
1011
|
+
prompt: request.trigger_message,
|
|
1012
|
+
submitKeyPresses,
|
|
1013
|
+
typePrompt: false,
|
|
1014
|
+
});
|
|
1015
|
+
if (!retrySend.ok && retrySend.reason === EXACT_PANE_UNAVAILABLE_REASON) {
|
|
1016
|
+
return exactPaneFailure({ reason: retrySend.reason, proof: retrySend.exactPaneProof }, true);
|
|
1017
|
+
}
|
|
1018
|
+
exactPaneProof = retrySend.exactPaneProof || exactPaneProof;
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
// Worker is actively processing (mirrors sync path tmux-session.ts:1292-1294)
|
|
1022
|
+
if (paneHasActiveTask(wideCap.stdout)) {
|
|
1023
|
+
runtimeExec({ command: 'MarkDelivered', request_id: request.request_id }, stateDir, request.team_name);
|
|
1024
|
+
return {
|
|
1025
|
+
ok: true,
|
|
1026
|
+
reason: 'tmux_send_keys_confirmed_active_task',
|
|
1027
|
+
pane: resolution.paneTarget,
|
|
1028
|
+
pane_source: resolution.source || null,
|
|
1029
|
+
readiness_evidence: paneGuard.readinessEvidence || null,
|
|
1030
|
+
pane_current_command: paneGuard.paneCurrentCommand || null,
|
|
1031
|
+
exact_pane_proof: exactPaneProof,
|
|
1032
|
+
tmux_injection_attempted: true,
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
// Do not declare success while a pane is not input-ready. Otherwise a
|
|
1036
|
+
// pre-ready send can be marked "confirmed" and later appear as a stuck
|
|
1037
|
+
// unsent draft once the UI finishes loading. This includes leader-fixed:
|
|
1038
|
+
// its Codex UI can show "tab to queue message" while busy, and marking
|
|
1039
|
+
// delivered before queue/consumption confirmation loses the orchestration
|
|
1040
|
+
// nudge until a human presses Tab manually.
|
|
1041
|
+
if (!paneLooksReady(wideCap.stdout)) {
|
|
1042
|
+
continue;
|
|
1043
|
+
}
|
|
1044
|
+
if (!triggerInNarrow && !triggerNearTail) {
|
|
1045
|
+
runtimeExec({ command: 'MarkDelivered', request_id: request.request_id }, stateDir, request.team_name);
|
|
1046
|
+
return {
|
|
1047
|
+
ok: true,
|
|
1048
|
+
reason: 'tmux_send_keys_confirmed',
|
|
1049
|
+
pane: resolution.paneTarget,
|
|
1050
|
+
pane_source: resolution.source || null,
|
|
1051
|
+
readiness_evidence: paneGuard.readinessEvidence || null,
|
|
1052
|
+
pane_current_command: paneGuard.paneCurrentCommand || null,
|
|
1053
|
+
exact_pane_proof: exactPaneProof,
|
|
1054
|
+
tmux_injection_attempted: true,
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
} catch {
|
|
1058
|
+
// Capture failed; fall through to retry C-m.
|
|
1059
|
+
}
|
|
903
1060
|
}
|
|
904
1061
|
// Draft still visible and no active task — retry C-m
|
|
905
|
-
await sendPaneInput({
|
|
1062
|
+
const retrySend = await sendPaneInput({
|
|
906
1063
|
paneTarget: resolution.paneTarget,
|
|
1064
|
+
exactPaneId,
|
|
1065
|
+
expectedPanePid: dispatchTarget.expectedPanePid,
|
|
1066
|
+
expectedPaneOwnerId: dispatchTarget.expectedPaneOwnerId,
|
|
1067
|
+
expectedHudPaneId: dispatchTarget.expectedHudPaneId,
|
|
907
1068
|
prompt: request.trigger_message,
|
|
908
1069
|
submitKeyPresses,
|
|
909
1070
|
typePrompt: false,
|
|
910
1071
|
queueFirstSubmit: leaderTargeted,
|
|
911
|
-
})
|
|
1072
|
+
});
|
|
1073
|
+
if (!retrySend.ok && retrySend.reason === EXACT_PANE_UNAVAILABLE_REASON) {
|
|
1074
|
+
return exactPaneFailure({ reason: retrySend.reason, proof: retrySend.exactPaneProof }, true);
|
|
1075
|
+
}
|
|
1076
|
+
exactPaneProof = retrySend.exactPaneProof || exactPaneProof;
|
|
912
1077
|
}
|
|
913
1078
|
|
|
914
1079
|
// Trigger text is still visible after all retry rounds.
|
|
@@ -919,6 +1084,7 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
919
1084
|
pane_source: resolution.source || null,
|
|
920
1085
|
readiness_evidence: paneGuard.readinessEvidence || null,
|
|
921
1086
|
pane_current_command: paneGuard.paneCurrentCommand || null,
|
|
1087
|
+
exact_pane_proof: exactPaneProof,
|
|
922
1088
|
tmux_injection_attempted: true,
|
|
923
1089
|
};
|
|
924
1090
|
}
|
|
@@ -962,6 +1128,7 @@ function buildDispatchAttemptEvidence(result, fallback = {}) {
|
|
|
962
1128
|
pane_source: safeString(result?.pane_source || fallback.pane_source || '').trim() || null,
|
|
963
1129
|
readiness_evidence: safeString(result?.readiness_evidence || fallback.readiness_evidence || '').trim() || null,
|
|
964
1130
|
pane_current_command: safeString(result?.pane_current_command || fallback.pane_current_command || '').trim() || null,
|
|
1131
|
+
exact_pane_proof: result?.exact_pane_proof ?? fallback.exact_pane_proof ?? null,
|
|
965
1132
|
tmux_injection_attempted:
|
|
966
1133
|
typeof result?.tmux_injection_attempted === 'boolean'
|
|
967
1134
|
? result.tmux_injection_attempted
|
|
@@ -1024,7 +1191,7 @@ export async function drainPendingTeamDispatch({
|
|
|
1024
1191
|
continue;
|
|
1025
1192
|
}
|
|
1026
1193
|
|
|
1027
|
-
if (request.to_worker === 'leader-fixed' && !resolveLeaderPaneId(config)) {
|
|
1194
|
+
if (request.to_worker === 'leader-fixed' && !resolveLeaderPaneId(config) && !explicitPaneIdentity(request.pane_id).provided) {
|
|
1028
1195
|
const nowIso = new Date().toISOString();
|
|
1029
1196
|
const alreadyDeferred = safeString(request.last_reason).trim() === LEADER_PANE_MISSING_DEFERRED_REASON;
|
|
1030
1197
|
request.updated_at = nowIso;
|
|
@@ -11,8 +11,7 @@ import { asNumber, safeString, isTerminalPhase } from './utils.js';
|
|
|
11
11
|
import { readJsonIfExists, getScopedStateDirsForCurrentSession } from './state-io.js';
|
|
12
12
|
import { runProcess } from './process-runner.js';
|
|
13
13
|
import { logTmuxHookEvent } from './log.js';
|
|
14
|
-
import { evaluatePaneInjectionReadiness,
|
|
15
|
-
import { resolvePaneTarget } from './tmux-injection.js';
|
|
14
|
+
import { evaluatePaneInjectionReadiness, normalizeExactPaneId, sendPaneInput } from './team-tmux-guard.js';
|
|
16
15
|
import { listNotifyCanonicalActiveTeams } from './active-team.js';
|
|
17
16
|
import {
|
|
18
17
|
classifyLeaderActionState,
|
|
@@ -28,6 +27,7 @@ import { isDeepInterviewStateActive } from './auto-nudge.js';
|
|
|
28
27
|
const LEADER_PANE_MISSING_NO_INJECTION_REASON = 'leader_pane_missing_no_injection';
|
|
29
28
|
const LEADER_PANE_SHELL_NO_INJECTION_REASON = 'leader_pane_shell_no_injection';
|
|
30
29
|
const TEAM_SHUTDOWN_NO_INJECTION_REASON = 'team_state_gone_or_shutdown';
|
|
30
|
+
const LEADER_PANE_OWNER_MISSING_NO_INJECTION_REASON = 'leader_pane_owner_missing_no_injection';
|
|
31
31
|
const LEADER_PANE_SAME_CLASSIFIED_STATE_SUPPRESSED_REASON = 'pane_already_shows_same_classified_state';
|
|
32
32
|
const LEADER_NOTIFICATION_DEFERRED_TYPE = 'leader_notification_deferred';
|
|
33
33
|
const ACK_WITHOUT_START_EVIDENCE_REASON = 'ack_without_start_evidence';
|
|
@@ -37,6 +37,10 @@ const ACK_LIKE_PATTERNS = [
|
|
|
37
37
|
/^(?:on it|will do|i(?:'|')ll do it|working on it)[.!]*$/i,
|
|
38
38
|
];
|
|
39
39
|
|
|
40
|
+
function positivePanePid(value) {
|
|
41
|
+
return Number.isInteger(value) && Number(value) > 0 ? Number(value) : undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
40
44
|
let atomicJsonWriteCounter = 0;
|
|
41
45
|
|
|
42
46
|
// Synchronous test-only callbacks let regression tests emulate filesystem races
|
|
@@ -729,6 +733,9 @@ export async function maybeNudgeTeamLeader({
|
|
|
729
733
|
let leaderPaneId = '';
|
|
730
734
|
let ownerSessionId = '';
|
|
731
735
|
let workers = [];
|
|
736
|
+
let hudPaneId = '';
|
|
737
|
+
let leaderPanePid;
|
|
738
|
+
let tmuxPaneOwnerId = '';
|
|
732
739
|
try {
|
|
733
740
|
const manifestPath = join(omxDir, 'state', 'team', teamName, 'manifest.v2.json');
|
|
734
741
|
const configPath = join(omxDir, 'state', 'team', teamName, 'config.json');
|
|
@@ -737,6 +744,9 @@ export async function maybeNudgeTeamLeader({
|
|
|
737
744
|
const raw = JSON.parse(await readFile(srcPath, 'utf-8'));
|
|
738
745
|
tmuxSession = safeString(raw && raw.tmux_session ? raw.tmux_session : '').trim();
|
|
739
746
|
leaderPaneId = safeString(raw && raw.leader_pane_id ? raw.leader_pane_id : '').trim();
|
|
747
|
+
hudPaneId = safeString(raw && raw.hud_pane_id ? raw.hud_pane_id : '').trim();
|
|
748
|
+
leaderPanePid = positivePanePid(raw && raw.leader_pane_pid);
|
|
749
|
+
tmuxPaneOwnerId = typeof raw?.tmux_pane_owner_id === 'string' ? raw.tmux_pane_owner_id.trim() : '';
|
|
740
750
|
ownerSessionId = safeString(raw && raw.leader && raw.leader.session_id ? raw.leader.session_id : '').trim();
|
|
741
751
|
if (Array.isArray(raw && raw.workers)) workers = raw.workers;
|
|
742
752
|
}
|
|
@@ -761,23 +771,20 @@ export async function maybeNudgeTeamLeader({
|
|
|
761
771
|
const workerPaneIds = Array.isArray(workers)
|
|
762
772
|
? workers.map((w) => safeString(w && w.pane_id ? w.pane_id : '')).filter(Boolean)
|
|
763
773
|
: [];
|
|
764
|
-
const
|
|
774
|
+
const normalizedLeaderPaneId = normalizeExactPaneId(leaderPaneId);
|
|
775
|
+
const canonicalLeaderPaneId = normalizedLeaderPaneId && normalizedLeaderPaneId !== normalizeExactPaneId(hudPaneId)
|
|
776
|
+
? normalizedLeaderPaneId
|
|
777
|
+
: '';
|
|
765
778
|
if (!tmuxSession && !canonicalLeaderPaneId) continue;
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
{ type: 'pane', value: canonicalLeaderPaneId },
|
|
770
|
-
'',
|
|
771
|
-
canonicalLeaderPaneId,
|
|
772
|
-
'',
|
|
773
|
-
{},
|
|
774
|
-
).catch(() => null);
|
|
775
|
-
if (resolvedLeaderTarget?.paneTarget) {
|
|
776
|
-
tmuxTarget = safeString(resolvedLeaderTarget.paneTarget).trim();
|
|
777
|
-
} else if (resolvedLeaderTarget && ['target_is_hud_pane', 'pane_cwd_mismatch'].includes(safeString(resolvedLeaderTarget.reason).trim())) {
|
|
778
|
-
tmuxTarget = '';
|
|
779
|
-
}
|
|
779
|
+
if (!tmuxPaneOwnerId) {
|
|
780
|
+
await recordSuppressedLeaderNudge({ logsDir, source, teamName, reason: LEADER_PANE_OWNER_MISSING_NO_INJECTION_REASON });
|
|
781
|
+
continue;
|
|
780
782
|
}
|
|
783
|
+
if (canonicalLeaderPaneId && !leaderPanePid) {
|
|
784
|
+
await recordSuppressedLeaderNudge({ logsDir, source, teamName, reason: 'leader_pane_pid_missing' });
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
const tmuxTarget = canonicalLeaderPaneId;
|
|
781
788
|
const paneStatus = tmuxSession
|
|
782
789
|
? await checkWorkerPanesAlive(tmuxSession, workerPaneIds)
|
|
783
790
|
: { alive: false, paneCount: 0 };
|
|
@@ -1087,6 +1094,10 @@ export async function maybeNudgeTeamLeader({
|
|
|
1087
1094
|
requireRunningAgent: true,
|
|
1088
1095
|
requireReady: false,
|
|
1089
1096
|
requireIdle: false,
|
|
1097
|
+
exactPaneId: canonicalLeaderPaneId,
|
|
1098
|
+
expectedPanePid: leaderPanePid,
|
|
1099
|
+
expectedPaneOwnerId: tmuxPaneOwnerId,
|
|
1100
|
+
expectedHudPaneId: hudPaneId,
|
|
1090
1101
|
});
|
|
1091
1102
|
if (!paneGuard.ok) {
|
|
1092
1103
|
const deferredReason = paneGuard.reason === 'pane_running_shell'
|
|
@@ -1188,9 +1199,16 @@ export async function maybeNudgeTeamLeader({
|
|
|
1188
1199
|
const leaderHasActiveTask = paneHasActiveTask(paneGuard.paneCapture);
|
|
1189
1200
|
let deliveryMode = 'sent';
|
|
1190
1201
|
if (leaderHasActiveTask) {
|
|
1191
|
-
const sendResult = await
|
|
1202
|
+
const sendResult = await sendPaneInput({
|
|
1192
1203
|
paneTarget: tmuxTarget,
|
|
1193
1204
|
prompt: markedText,
|
|
1205
|
+
submitKeyPresses: 1,
|
|
1206
|
+
submitDelayMs: 80,
|
|
1207
|
+
queueFirstSubmit: true,
|
|
1208
|
+
exactPaneId: canonicalLeaderPaneId,
|
|
1209
|
+
expectedPanePid: leaderPanePid,
|
|
1210
|
+
expectedPaneOwnerId: tmuxPaneOwnerId,
|
|
1211
|
+
expectedHudPaneId: hudPaneId,
|
|
1194
1212
|
});
|
|
1195
1213
|
if (!sendResult.ok) {
|
|
1196
1214
|
throw new Error(sendResult.error || sendResult.reason);
|
|
@@ -1202,6 +1220,10 @@ export async function maybeNudgeTeamLeader({
|
|
|
1202
1220
|
prompt: markedText,
|
|
1203
1221
|
submitKeyPresses: 2,
|
|
1204
1222
|
submitDelayMs: 100,
|
|
1223
|
+
exactPaneId: canonicalLeaderPaneId,
|
|
1224
|
+
expectedPanePid: leaderPanePid,
|
|
1225
|
+
expectedPaneOwnerId: tmuxPaneOwnerId,
|
|
1226
|
+
expectedHudPaneId: hudPaneId,
|
|
1205
1227
|
});
|
|
1206
1228
|
if (!sendResult.ok) {
|
|
1207
1229
|
throw new Error(sendResult.error || sendResult.reason);
|