oh-my-codex 0.15.0 → 0.15.2
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 +5 -5
- package/Cargo.toml +1 -1
- package/README.md +36 -5
- package/crates/omx-explore/src/main.rs +222 -12
- package/dist/agents/__tests__/native-config.test.js +40 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts +1 -0
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +6 -1
- package/dist/agents/native-config.js.map +1 -1
- package/dist/agents/policy.d.ts +1 -0
- package/dist/agents/policy.d.ts.map +1 -1
- package/dist/agents/policy.js +4 -0
- package/dist/agents/policy.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js +37 -13
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-team.test.js +46 -1
- package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +225 -111
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +96 -1
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +15 -2
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +292 -3
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +223 -0
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +86 -0
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +23 -0
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +76 -11
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +140 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +310 -4
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js +78 -19
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +79 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/sidecar.test.d.ts +2 -0
- package/dist/cli/__tests__/sidecar.test.d.ts.map +1 -0
- package/dist/cli/__tests__/sidecar.test.js +24 -0
- package/dist/cli/__tests__/sidecar.test.js.map +1 -0
- package/dist/cli/__tests__/team.test.js +54 -7
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/autoresearch-guided.d.ts.map +1 -1
- package/dist/cli/autoresearch-guided.js +12 -4
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/codex-home.d.ts +4 -6
- package/dist/cli/codex-home.d.ts.map +1 -1
- package/dist/cli/codex-home.js +9 -41
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +509 -279
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +6 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +284 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/omx.js +3 -1
- package/dist/cli/omx.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +13 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -0
- package/dist/cli/plugin-marketplace.js +77 -0
- package/dist/cli/plugin-marketplace.js.map +1 -0
- package/dist/cli/question.d.ts +1 -1
- package/dist/cli/question.d.ts.map +1 -1
- package/dist/cli/question.js +26 -12
- package/dist/cli/question.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +20 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -0
- package/dist/cli/setup-preferences.js +71 -0
- package/dist/cli/setup-preferences.js.map +1 -0
- package/dist/cli/setup.d.ts +7 -5
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +271 -152
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts +1 -0
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +70 -15
- package/dist/cli/team.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +100 -3
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +6 -5
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/generator-status-line-presets.test.d.ts +2 -0
- package/dist/config/__tests__/generator-status-line-presets.test.d.ts.map +1 -0
- package/dist/config/__tests__/generator-status-line-presets.test.js +203 -0
- package/dist/config/__tests__/generator-status-line-presets.test.js.map +1 -0
- package/dist/config/__tests__/models.test.js +23 -1
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/generator.d.ts +9 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +184 -16
- package/dist/config/generator.js.map +1 -1
- package/dist/config/models.d.ts +5 -1
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +12 -2
- package/dist/config/models.js.map +1 -1
- package/dist/exec/followup.d.ts +44 -0
- package/dist/exec/followup.d.ts.map +1 -0
- package/dist/exec/followup.js +349 -0
- package/dist/exec/followup.js.map +1 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +37 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/codebase-map.test.js +63 -1
- package/dist/hooks/__tests__/codebase-map.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js +5 -5
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +12 -9
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +25 -18
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +23 -2
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +45 -2
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +17 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +121 -0
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js +4 -4
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +103 -0
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +2 -2
- 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 +27 -13
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts +2 -0
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js +35 -0
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.test.js.map +1 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +215 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +70 -3
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js +5 -0
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +3 -2
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +9 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/prompt-refactor-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prompt-refactor-contract.test.js +22 -0
- package/dist/hooks/__tests__/prompt-refactor-contract.test.js.map +1 -0
- package/dist/hooks/codebase-map.d.ts.map +1 -1
- package/dist/hooks/codebase-map.js +83 -6
- package/dist/hooks/codebase-map.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +35 -4
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts +6 -0
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +117 -13
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hooks/session.d.ts +2 -0
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +6 -0
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/index.test.js +4 -4
- package/dist/hud/__tests__/index.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +4 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/types.test.js +27 -0
- package/dist/hud/__tests__/types.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +8 -0
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/types.d.ts +9 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js +3 -0
- package/dist/hud/types.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +23 -5
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +50 -7
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +70 -12
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +10 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +71 -26
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/state-server.d.ts +5 -11
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/state-server.js +16 -432
- package/dist/mcp/state-server.js.map +1 -1
- package/dist/modes/__tests__/base-autoresearch-contract.test.js +1 -1
- package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +89 -5
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +98 -1
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/index.d.ts +5 -3
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +4 -3
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts +7 -6
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +90 -11
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/review-verdict.d.ts +3 -0
- package/dist/pipeline/review-verdict.d.ts.map +1 -0
- package/dist/pipeline/review-verdict.js +14 -0
- package/dist/pipeline/review-verdict.js.map +1 -0
- package/dist/pipeline/stages/code-review.d.ts +33 -0
- package/dist/pipeline/stages/code-review.d.ts.map +1 -0
- package/dist/pipeline/stages/code-review.js +51 -0
- package/dist/pipeline/stages/code-review.js.map +1 -0
- package/dist/pipeline/stages/ralph-verify.d.ts +12 -2
- package/dist/pipeline/stages/ralph-verify.d.ts.map +1 -1
- package/dist/pipeline/stages/ralph-verify.js +24 -6
- package/dist/pipeline/stages/ralph-verify.js.map +1 -1
- package/dist/pipeline/stages/ralplan.d.ts +1 -1
- package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +21 -1
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/pipeline/types.d.ts +14 -7
- package/dist/pipeline/types.d.ts.map +1 -1
- package/dist/pipeline/types.js +2 -2
- package/dist/planning/__tests__/artifacts.test.js +152 -1
- package/dist/planning/__tests__/artifacts.test.js.map +1 -1
- package/dist/planning/artifacts.d.ts +9 -0
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +60 -1
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/question/__tests__/client.test.js +23 -3
- package/dist/question/__tests__/client.test.js.map +1 -1
- package/dist/question/__tests__/renderer.test.js +148 -37
- package/dist/question/__tests__/renderer.test.js.map +1 -1
- package/dist/question/__tests__/types.test.js +21 -0
- package/dist/question/__tests__/types.test.js.map +1 -1
- package/dist/question/__tests__/ui.test.js +155 -7
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/client.d.ts +14 -4
- package/dist/question/client.d.ts.map +1 -1
- package/dist/question/client.js.map +1 -1
- package/dist/question/renderer.d.ts +11 -1
- package/dist/question/renderer.d.ts.map +1 -1
- package/dist/question/renderer.js +102 -7
- package/dist/question/renderer.js.map +1 -1
- package/dist/question/state.d.ts +2 -2
- package/dist/question/state.d.ts.map +1 -1
- package/dist/question/state.js +26 -17
- package/dist/question/state.js.map +1 -1
- package/dist/question/types.d.ts +25 -1
- package/dist/question/types.d.ts.map +1 -1
- package/dist/question/types.js +48 -13
- package/dist/question/types.js.map +1 -1
- package/dist/question/ui.d.ts +15 -2
- package/dist/question/ui.d.ts.map +1 -1
- package/dist/question/ui.js +268 -162
- package/dist/question/ui.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +415 -94
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/generate-release-body.test.js +36 -0
- package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
- package/dist/scripts/__tests__/prompt-inventory.test.d.ts +2 -0
- package/dist/scripts/__tests__/prompt-inventory.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/prompt-inventory.test.js +56 -0
- package/dist/scripts/__tests__/prompt-inventory.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +232 -54
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +12 -9
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/generate-release-body.d.ts.map +1 -1
- package/dist/scripts/generate-release-body.js +12 -3
- package/dist/scripts/generate-release-body.js.map +1 -1
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts +2 -0
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.d.ts.map +1 -0
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js +153 -0
- package/dist/scripts/notify-hook/__tests__/team-worker-posttooluse.test.js.map +1 -0
- package/dist/scripts/notify-hook/managed-tmux.d.ts +4 -2
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +188 -6
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
- package/dist/scripts/notify-hook/process-runner.js +7 -3
- package/dist/scripts/notify-hook/process-runner.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +96 -11
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +3 -3
- package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts +34 -0
- package/dist/scripts/notify-hook/team-worker-posttooluse.d.ts.map +1 -0
- package/dist/scripts/notify-hook/team-worker-posttooluse.js +434 -0
- package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -0
- package/dist/scripts/notify-hook/team-worker.d.ts +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +3 -43
- 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 +25 -4
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +36 -5
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/prompt-inventory.d.ts +29 -0
- package/dist/scripts/prompt-inventory.d.ts.map +1 -0
- package/dist/scripts/prompt-inventory.js +178 -0
- package/dist/scripts/prompt-inventory.js.map +1 -0
- package/dist/scripts/run-test-files.js +1 -0
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/sidecar/__tests__/boundary.test.d.ts +2 -0
- package/dist/sidecar/__tests__/boundary.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/boundary.test.js +48 -0
- package/dist/sidecar/__tests__/boundary.test.js.map +1 -0
- package/dist/sidecar/__tests__/collector.test.d.ts +2 -0
- package/dist/sidecar/__tests__/collector.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/collector.test.js +162 -0
- package/dist/sidecar/__tests__/collector.test.js.map +1 -0
- package/dist/sidecar/__tests__/render.test.d.ts +2 -0
- package/dist/sidecar/__tests__/render.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/render.test.js +67 -0
- package/dist/sidecar/__tests__/render.test.js.map +1 -0
- package/dist/sidecar/__tests__/tmux.test.d.ts +2 -0
- package/dist/sidecar/__tests__/tmux.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/tmux.test.js +30 -0
- package/dist/sidecar/__tests__/tmux.test.js.map +1 -0
- package/dist/sidecar/__tests__/watch.test.d.ts +2 -0
- package/dist/sidecar/__tests__/watch.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/watch.test.js +42 -0
- package/dist/sidecar/__tests__/watch.test.js.map +1 -0
- package/dist/sidecar/collector.d.ts +4 -0
- package/dist/sidecar/collector.d.ts.map +1 -0
- package/dist/sidecar/collector.js +377 -0
- package/dist/sidecar/collector.js.map +1 -0
- package/dist/sidecar/index.d.ts +25 -0
- package/dist/sidecar/index.d.ts.map +1 -0
- package/dist/sidecar/index.js +165 -0
- package/dist/sidecar/index.js.map +1 -0
- package/dist/sidecar/render.d.ts +3 -0
- package/dist/sidecar/render.d.ts.map +1 -0
- package/dist/sidecar/render.js +72 -0
- package/dist/sidecar/render.js.map +1 -0
- package/dist/sidecar/tmux.d.ts +13 -0
- package/dist/sidecar/tmux.d.ts.map +1 -0
- package/dist/sidecar/tmux.js +44 -0
- package/dist/sidecar/tmux.js.map +1 -0
- package/dist/sidecar/types.d.ts +125 -0
- package/dist/sidecar/types.d.ts.map +1 -0
- package/dist/sidecar/types.js +2 -0
- package/dist/sidecar/types.js.map +1 -0
- package/dist/state/__tests__/operations.test.js +50 -22
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +9 -1
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/operations.d.ts +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +19 -7
- package/dist/state/operations.js.map +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +1 -0
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/commit-hygiene.test.d.ts +2 -0
- package/dist/team/__tests__/commit-hygiene.test.d.ts.map +1 -0
- package/dist/team/__tests__/commit-hygiene.test.js +93 -0
- package/dist/team/__tests__/commit-hygiene.test.js.map +1 -0
- package/dist/team/__tests__/delegation-policy.test.d.ts +2 -0
- package/dist/team/__tests__/delegation-policy.test.d.ts.map +1 -0
- package/dist/team/__tests__/delegation-policy.test.js +69 -0
- package/dist/team/__tests__/delegation-policy.test.js.map +1 -0
- package/dist/team/__tests__/events.test.js +54 -4
- package/dist/team/__tests__/events.test.js.map +1 -1
- package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts +2 -0
- package/dist/team/__tests__/hook-primary-e2e-contract.test.d.ts.map +1 -0
- package/dist/team/__tests__/hook-primary-e2e-contract.test.js +78 -0
- package/dist/team/__tests__/hook-primary-e2e-contract.test.js.map +1 -0
- package/dist/team/__tests__/model-contract.test.js +16 -0
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/repo-aware-decomposition.test.d.ts +2 -0
- package/dist/team/__tests__/repo-aware-decomposition.test.d.ts.map +1 -0
- package/dist/team/__tests__/repo-aware-decomposition.test.js +95 -0
- package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -0
- package/dist/team/__tests__/runtime.test.js +623 -14
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js +177 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +110 -0
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +399 -2
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +94 -0
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/commit-hygiene.d.ts +22 -3
- package/dist/team/commit-hygiene.d.ts.map +1 -1
- package/dist/team/commit-hygiene.js +134 -2
- package/dist/team/commit-hygiene.js.map +1 -1
- package/dist/team/contracts.d.ts +1 -1
- package/dist/team/contracts.d.ts.map +1 -1
- package/dist/team/contracts.js +2 -0
- package/dist/team/contracts.js.map +1 -1
- package/dist/team/dag-schema.d.ts +38 -0
- package/dist/team/dag-schema.d.ts.map +1 -0
- package/dist/team/dag-schema.js +221 -0
- package/dist/team/dag-schema.js.map +1 -0
- package/dist/team/delegation-policy.d.ts +3 -0
- package/dist/team/delegation-policy.d.ts.map +1 -0
- package/dist/team/delegation-policy.js +82 -0
- package/dist/team/delegation-policy.js.map +1 -0
- package/dist/team/model-contract.d.ts +3 -1
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +44 -5
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/repo-aware-decomposition.d.ts +60 -0
- package/dist/team/repo-aware-decomposition.d.ts.map +1 -0
- package/dist/team/repo-aware-decomposition.js +229 -0
- package/dist/team/repo-aware-decomposition.js.map +1 -0
- package/dist/team/runtime.d.ts +27 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +172 -52
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/state/tasks.d.ts.map +1 -1
- package/dist/team/state/tasks.js +33 -0
- package/dist/team/state/tasks.js.map +1 -1
- package/dist/team/state/types.d.ts +23 -1
- package/dist/team/state/types.d.ts.map +1 -1
- package/dist/team/state/types.js.map +1 -1
- package/dist/team/state-root.d.ts +35 -0
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +281 -1
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts +27 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +6 -0
- package/dist/team/state.js.map +1 -1
- package/dist/team/tmux-session.d.ts +1 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +105 -6
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +3 -0
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +77 -4
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/utils/agents-md.d.ts +3 -0
- package/dist/utils/agents-md.d.ts.map +1 -1
- package/dist/utils/agents-md.js +25 -0
- package/dist/utils/agents-md.js.map +1 -1
- package/package.json +3 -2
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +2 -2
- package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/analyze/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +134 -205
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +4 -4
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +14 -7
- package/plugins/oh-my-codex/skills/doctor/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/help/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +41 -10
- package/plugins/oh-my-codex/skills/plan/SKILL.md +12 -14
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +2 -4
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -9
- package/plugins/oh-my-codex/skills/security-review/SKILL.md +4 -4
- package/plugins/oh-my-codex/skills/team/SKILL.md +2 -5
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +2 -5
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +2 -3
- package/prompts/analyst.md +2 -2
- package/prompts/api-reviewer.md +2 -2
- package/prompts/architect.md +2 -2
- package/prompts/build-fixer.md +2 -2
- package/prompts/code-reviewer.md +15 -5
- package/prompts/code-simplifier.md +1 -1
- package/prompts/critic.md +35 -83
- package/prompts/debugger.md +2 -2
- package/prompts/dependency-expert.md +2 -2
- package/prompts/designer.md +2 -2
- package/prompts/executor.md +40 -114
- package/prompts/explore-harness.md +1 -1
- package/prompts/explore.md +37 -90
- package/prompts/git-master.md +2 -2
- package/prompts/information-architect.md +1 -1
- package/prompts/performance-reviewer.md +2 -2
- package/prompts/planner.md +35 -62
- package/prompts/product-analyst.md +2 -2
- package/prompts/product-manager.md +2 -2
- package/prompts/qa-tester.md +2 -2
- package/prompts/quality-reviewer.md +2 -2
- package/prompts/quality-strategist.md +2 -2
- package/prompts/researcher.md +46 -78
- package/prompts/security-reviewer.md +2 -2
- package/prompts/sisyphus-lite.md +2 -2
- package/prompts/style-reviewer.md +2 -2
- package/prompts/team-executor.md +1 -1
- package/prompts/test-engineer.md +2 -2
- package/prompts/ux-researcher.md +2 -2
- package/prompts/verifier.md +29 -34
- package/prompts/vision.md +2 -2
- package/prompts/writer.md +2 -2
- package/skills/ai-slop-cleaner/SKILL.md +1 -1
- package/skills/analyze/SKILL.md +1 -1
- package/skills/autopilot/SKILL.md +134 -205
- package/skills/build-fix/SKILL.md +4 -4
- package/skills/code-review/SKILL.md +4 -4
- package/skills/deep-interview/SKILL.md +14 -7
- package/skills/doctor/SKILL.md +1 -1
- package/skills/help/SKILL.md +1 -1
- package/skills/omx-setup/SKILL.md +41 -10
- package/skills/plan/SKILL.md +12 -14
- package/skills/ralph/SKILL.md +2 -4
- package/skills/ralplan/SKILL.md +5 -9
- package/skills/security-review/SKILL.md +4 -4
- package/skills/team/SKILL.md +2 -5
- package/skills/ultraqa/SKILL.md +2 -5
- package/skills/ultrawork/SKILL.md +2 -3
- package/src/scripts/__tests__/codex-native-hook.test.ts +502 -94
- package/src/scripts/__tests__/generate-release-body.test.ts +41 -0
- package/src/scripts/__tests__/prompt-inventory.test.ts +64 -0
- package/src/scripts/codex-native-hook.ts +293 -61
- package/src/scripts/codex-native-pre-post.ts +10 -8
- package/src/scripts/generate-release-body.ts +13 -2
- package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +180 -0
- package/src/scripts/notify-hook/managed-tmux.ts +196 -9
- package/src/scripts/notify-hook/process-runner.ts +7 -3
- package/src/scripts/notify-hook/team-dispatch.ts +103 -11
- package/src/scripts/notify-hook/team-tmux-guard.ts +3 -3
- package/src/scripts/notify-hook/team-worker-posttooluse.ts +536 -0
- package/src/scripts/notify-hook/team-worker.ts +4 -48
- package/src/scripts/notify-hook/tmux-injection.ts +24 -6
- package/src/scripts/notify-hook.ts +36 -5
- package/src/scripts/prompt-inventory.ts +218 -0
- package/src/scripts/run-test-files.ts +1 -0
- package/templates/AGENTS.md +34 -95
|
@@ -152,6 +152,7 @@ export function detectMcpTransportFailure(
|
|
|
152
152
|
payload: CodexHookPayload,
|
|
153
153
|
): McpTransportFailureSignal | null {
|
|
154
154
|
const normalized = normalizePostToolUsePayload(payload);
|
|
155
|
+
if (normalized.isBash) return null;
|
|
155
156
|
const combined = [
|
|
156
157
|
normalized.stderrText,
|
|
157
158
|
normalized.stdoutText,
|
|
@@ -591,10 +592,6 @@ function buildGitCommitEnforcementOutput(commandText: string): Record<string, un
|
|
|
591
592
|
"git commit is blocked until the inline commit message satisfies the Lore format and includes the required OmX co-author trailer.",
|
|
592
593
|
hookSpecificOutput: {
|
|
593
594
|
hookEventName: "PreToolUse",
|
|
594
|
-
additionalContext: [
|
|
595
|
-
"Lore-format git commit enforcement triggered.",
|
|
596
|
-
...errors.map((error) => `- ${error}`),
|
|
597
|
-
].join("\n"),
|
|
598
595
|
},
|
|
599
596
|
systemMessage: [
|
|
600
597
|
"git commit is blocked until the inline commit message follows the Lore protocol and includes `Co-authored-by: OmX <omx@oh-my-codex.dev>`.",
|
|
@@ -764,10 +761,17 @@ function containsHardFailure(text: string): boolean {
|
|
|
764
761
|
return /command not found|permission denied|no such file or directory/i.test(text);
|
|
765
762
|
}
|
|
766
763
|
|
|
764
|
+
function hasActionableBashHardFailure(normalized: NormalizedPostToolUsePayload): boolean {
|
|
765
|
+
if (containsHardFailure(normalized.stderrText)) return true;
|
|
766
|
+
if (normalized.exitCode === null || normalized.exitCode === 0) return false;
|
|
767
|
+
return containsHardFailure(`${normalized.stderrText}\n${normalized.stdoutText}`);
|
|
768
|
+
}
|
|
769
|
+
|
|
767
770
|
export function buildNativePostToolUseOutput(
|
|
768
771
|
payload: CodexHookPayload,
|
|
769
772
|
): Record<string, unknown> | null {
|
|
770
|
-
const
|
|
773
|
+
const normalized = normalizePostToolUsePayload(payload);
|
|
774
|
+
const mcpTransportFailure = normalized.isBash ? null : detectMcpTransportFailure(payload);
|
|
771
775
|
if (mcpTransportFailure) {
|
|
772
776
|
const fallbackCommand = buildOmxParityFallbackCommand(payload, mcpTransportFailure.toolName);
|
|
773
777
|
const fallbackText = fallbackCommand
|
|
@@ -784,12 +788,10 @@ export function buildNativePostToolUseOutput(
|
|
|
784
788
|
};
|
|
785
789
|
}
|
|
786
790
|
|
|
787
|
-
const normalized = normalizePostToolUsePayload(payload);
|
|
788
791
|
if (!normalized.isBash) return null;
|
|
789
792
|
|
|
790
793
|
const combined = `${normalized.stderrText}\n${normalized.stdoutText}`.trim();
|
|
791
|
-
if (normalized
|
|
792
|
-
if (containsHardFailure(combined)) {
|
|
794
|
+
if (hasActionableBashHardFailure(normalized)) {
|
|
793
795
|
return {
|
|
794
796
|
decision: "block",
|
|
795
797
|
reason: "The Bash output indicates a command/setup failure that should be fixed before retrying.",
|
|
@@ -75,6 +75,15 @@ export function resolveCurrentTag(cwd: string, explicit?: string): string {
|
|
|
75
75
|
throw new Error('unable to determine current release tag; pass --current-tag or set GITHUB_REF_NAME');
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
function isAncestorTag(cwd: string, possibleAncestor: string, currentTag: string): boolean {
|
|
79
|
+
const result = spawnSync('git', ['merge-base', '--is-ancestor', possibleAncestor, currentTag], {
|
|
80
|
+
cwd,
|
|
81
|
+
encoding: 'utf-8',
|
|
82
|
+
stdio: 'pipe',
|
|
83
|
+
});
|
|
84
|
+
return result.status === 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
78
87
|
export function resolvePreviousTag(cwd: string, currentTag: string, explicit?: string): string | undefined {
|
|
79
88
|
if (explicit) return explicit;
|
|
80
89
|
const tags = runGit(['tag', '--list', 'v*', '--sort=-v:refname'], cwd, true)
|
|
@@ -83,8 +92,10 @@ export function resolvePreviousTag(cwd: string, currentTag: string, explicit?: s
|
|
|
83
92
|
.filter(Boolean);
|
|
84
93
|
if (tags.length === 0) return undefined;
|
|
85
94
|
const currentIndex = tags.indexOf(currentTag);
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
const candidates = currentIndex >= 0
|
|
96
|
+
? tags.slice(currentIndex + 1)
|
|
97
|
+
: tags.filter((tag) => tag !== currentTag);
|
|
98
|
+
return candidates.find((tag) => isAncestorTag(cwd, tag, currentTag));
|
|
88
99
|
}
|
|
89
100
|
|
|
90
101
|
function verifyGitCommitRef(cwd: string, ref: string, label: string): void {
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { chmod, mkdtemp, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { tmpdir } from 'node:os';
|
|
8
|
+
import { handleTeamWorkerPostToolUseSuccess, teamWorkerPostToolUseInternals } from '../team-worker-posttooluse.js';
|
|
9
|
+
import { readTeamEvents } from '../../../team/state/events.js';
|
|
10
|
+
|
|
11
|
+
async function initWorkerFixture(): Promise<{ cwd: string; stateRoot: string; env: NodeJS.ProcessEnv }> {
|
|
12
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-posttooluse-worker-'));
|
|
13
|
+
execFileSync('git', ['init'], { cwd, stdio: 'ignore' });
|
|
14
|
+
execFileSync('git', ['config', 'user.email', 'test@example.com'], { cwd, stdio: 'ignore' });
|
|
15
|
+
execFileSync('git', ['config', 'user.name', 'Test User'], { cwd, stdio: 'ignore' });
|
|
16
|
+
await writeFile(join(cwd, 'README.md'), 'hello\n', 'utf-8');
|
|
17
|
+
execFileSync('git', ['add', 'README.md'], { cwd, stdio: 'ignore' });
|
|
18
|
+
execFileSync('git', ['commit', '-m', 'init'], { cwd, stdio: 'ignore' });
|
|
19
|
+
|
|
20
|
+
const stateRoot = join(cwd, '.omx', 'state');
|
|
21
|
+
const workerDir = join(stateRoot, 'team', 'demo-team', 'workers', 'worker-1');
|
|
22
|
+
await mkdir(workerDir, { recursive: true });
|
|
23
|
+
await writeFile(join(workerDir, 'identity.json'), JSON.stringify({
|
|
24
|
+
name: 'worker-1',
|
|
25
|
+
team_state_root: stateRoot,
|
|
26
|
+
worktree_path: cwd,
|
|
27
|
+
}, null, 2), 'utf-8');
|
|
28
|
+
await writeFile(join(stateRoot, 'team', 'demo-team', 'phase.json'), JSON.stringify({ current_phase: 'team-exec' }, null, 2), 'utf-8');
|
|
29
|
+
await writeFile(join(stateRoot, 'team', 'demo-team', 'config.json'), JSON.stringify({ leader_cwd: cwd }, null, 2), 'utf-8');
|
|
30
|
+
return {
|
|
31
|
+
cwd,
|
|
32
|
+
stateRoot,
|
|
33
|
+
env: {
|
|
34
|
+
...process.env,
|
|
35
|
+
OMX_TEAM_WORKER: 'demo-team/worker-1',
|
|
36
|
+
OMX_TEAM_STATE_ROOT: stateRoot,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const successPayload = {
|
|
42
|
+
hook_event_name: 'PostToolUse',
|
|
43
|
+
tool_name: 'Bash',
|
|
44
|
+
tool_response: { exit_code: 0 },
|
|
45
|
+
tool_use_id: 'tool-1',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
describe('handleTeamWorkerPostToolUseSuccess', () => {
|
|
49
|
+
it('creates a safe worker checkpoint, ledger entries, leader signal, and dedupe marker', async () => {
|
|
50
|
+
const fixture = await initWorkerFixture();
|
|
51
|
+
await writeFile(join(fixture.cwd, 'feature.txt'), 'feature\n', 'utf-8');
|
|
52
|
+
|
|
53
|
+
const result = await handleTeamWorkerPostToolUseSuccess(successPayload, fixture.cwd, fixture.env);
|
|
54
|
+
|
|
55
|
+
assert.equal(result.handled, true);
|
|
56
|
+
assert.equal(result.status, 'applied');
|
|
57
|
+
assert.ok(result.checkpointCommit);
|
|
58
|
+
assert.deepEqual(result.operationKinds, ['auto_checkpoint', 'worker_clean_rebase', 'leader_integration_attempt']);
|
|
59
|
+
|
|
60
|
+
const log = execFileSync('git', ['log', '-1', '--pretty=%s'], { cwd: fixture.cwd, encoding: 'utf-8' }).trim();
|
|
61
|
+
assert.equal(log, 'omx(team): auto-checkpoint worker-1');
|
|
62
|
+
|
|
63
|
+
const events = await readTeamEvents('demo-team', fixture.cwd, { type: 'worker_integration_attempt_requested' });
|
|
64
|
+
assert.equal(events.length, 1);
|
|
65
|
+
const event = events[0]!;
|
|
66
|
+
assert.equal(event.type, 'worker_integration_attempt_requested');
|
|
67
|
+
assert.equal(event.worker, 'worker-1');
|
|
68
|
+
const metadata = event.metadata as Record<string, unknown>;
|
|
69
|
+
assert.equal(metadata.operation_kind, 'leader_integration_attempt');
|
|
70
|
+
assert.equal(metadata.outcome_status, 'applied');
|
|
71
|
+
assert.equal(metadata.source, 'posttooluse');
|
|
72
|
+
assert.equal(metadata.dedupe_key, result.dedupeKey);
|
|
73
|
+
assert.match(String(metadata.leader_head_observed), /^[0-9a-f]{40}$/);
|
|
74
|
+
|
|
75
|
+
const dedupe = JSON.parse(await readFile(join(fixture.stateRoot, 'team', 'demo-team', 'workers', 'worker-1', 'posttooluse-dedupe.json'), 'utf-8')) as { keys: string[] };
|
|
76
|
+
assert.equal(dedupe.keys.includes(result.dedupeKey!), true);
|
|
77
|
+
|
|
78
|
+
const ledger = JSON.parse(await readFile(join(fixture.cwd, '.omx', 'reports', 'team-commit-hygiene', 'demo-team.ledger.json'), 'utf-8')) as { entries: Array<{ operation: string; status: string }> };
|
|
79
|
+
assert.equal(ledger.entries.some((entry) => entry.operation === 'auto_checkpoint' && entry.status === 'applied'), true);
|
|
80
|
+
assert.equal(ledger.entries.some((entry) => entry.operation === 'worker_clean_rebase' && entry.status === 'noop'), true);
|
|
81
|
+
assert.equal(ledger.entries.some((entry) => entry.operation === 'leader_integration_attempt' && entry.status === 'applied'), true);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('records noop without creating a checkpoint commit', async () => {
|
|
85
|
+
const fixture = await initWorkerFixture();
|
|
86
|
+
const before = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: fixture.cwd, encoding: 'utf-8' }).trim();
|
|
87
|
+
|
|
88
|
+
const result = await handleTeamWorkerPostToolUseSuccess(successPayload, fixture.cwd, fixture.env);
|
|
89
|
+
|
|
90
|
+
const after = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: fixture.cwd, encoding: 'utf-8' }).trim();
|
|
91
|
+
assert.equal(result.status, 'noop');
|
|
92
|
+
assert.equal(result.checkpointCommit, null);
|
|
93
|
+
assert.equal(after, before);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('skips protected runtime-only changes', async () => {
|
|
97
|
+
const fixture = await initWorkerFixture();
|
|
98
|
+
await writeFile(join(fixture.cwd, 'AGENTS.md'), 'generated worker instructions\n', 'utf-8');
|
|
99
|
+
|
|
100
|
+
const result = await handleTeamWorkerPostToolUseSuccess(successPayload, fixture.cwd, fixture.env);
|
|
101
|
+
|
|
102
|
+
assert.equal(result.status, 'skipped');
|
|
103
|
+
assert.equal(result.reason, 'only_protected_paths_changed');
|
|
104
|
+
assert.equal(result.checkpointCommit, null);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('does not checkpoint its own runtime report artifacts on a repeated PostToolUse turn', async () => {
|
|
108
|
+
const fixture = await initWorkerFixture();
|
|
109
|
+
await writeFile(join(fixture.cwd, 'feature.txt'), 'feature\n', 'utf-8');
|
|
110
|
+
|
|
111
|
+
const first = await handleTeamWorkerPostToolUseSuccess(successPayload, fixture.cwd, fixture.env);
|
|
112
|
+
const headAfterFirst = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: fixture.cwd, encoding: 'utf-8' }).trim();
|
|
113
|
+
const second = await handleTeamWorkerPostToolUseSuccess({ ...successPayload, tool_use_id: 'tool-2' }, fixture.cwd, fixture.env);
|
|
114
|
+
const headAfterSecond = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: fixture.cwd, encoding: 'utf-8' }).trim();
|
|
115
|
+
const events = await readTeamEvents('demo-team', fixture.cwd, { type: 'worker_integration_attempt_requested' });
|
|
116
|
+
|
|
117
|
+
assert.equal(first.status, 'applied');
|
|
118
|
+
assert.equal(second.status, 'noop');
|
|
119
|
+
assert.equal(headAfterSecond, headAfterFirst);
|
|
120
|
+
assert.equal(events.length, 1);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('skips checkpointing when the index is already staged and preserves staged changes', async () => {
|
|
124
|
+
const fixture = await initWorkerFixture();
|
|
125
|
+
await writeFile(join(fixture.cwd, 'pre-staged.txt'), 'already staged\n', 'utf-8');
|
|
126
|
+
execFileSync('git', ['add', 'pre-staged.txt'], { cwd: fixture.cwd, stdio: 'ignore' });
|
|
127
|
+
await writeFile(join(fixture.cwd, 'unstaged.txt'), 'new work\n', 'utf-8');
|
|
128
|
+
|
|
129
|
+
const result = await handleTeamWorkerPostToolUseSuccess(successPayload, fixture.cwd, fixture.env);
|
|
130
|
+
const staged = execFileSync('git', ['diff', '--name-only', '--cached'], { cwd: fixture.cwd, encoding: 'utf-8' }).trim().split('\n').filter(Boolean);
|
|
131
|
+
const status = execFileSync('git', ['status', '--porcelain=v1', '-uall'], { cwd: fixture.cwd, encoding: 'utf-8' });
|
|
132
|
+
|
|
133
|
+
assert.equal(result.status, 'skipped');
|
|
134
|
+
assert.equal(result.reason, 'index_not_clean');
|
|
135
|
+
assert.deepEqual(staged, ['pre-staged.txt']);
|
|
136
|
+
assert.match(status, /\?\? unstaged\.txt/);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('unstages checkpointable paths when checkpoint commit fails after staging', async () => {
|
|
140
|
+
const fixture = await initWorkerFixture();
|
|
141
|
+
const hookPath = join(fixture.cwd, '.git', 'hooks', 'prepare-commit-msg');
|
|
142
|
+
await writeFile(hookPath, '#!/bin/sh\nexit 42\n', 'utf-8');
|
|
143
|
+
await chmod(hookPath, 0o755);
|
|
144
|
+
await writeFile(join(fixture.cwd, 'commit-fail.txt'), 'must not remain staged\n', 'utf-8');
|
|
145
|
+
|
|
146
|
+
const result = await handleTeamWorkerPostToolUseSuccess(successPayload, fixture.cwd, fixture.env);
|
|
147
|
+
const staged = execFileSync('git', ['diff', '--name-only', '--cached'], { cwd: fixture.cwd, encoding: 'utf-8' }).trim();
|
|
148
|
+
const status = execFileSync('git', ['status', '--porcelain=v1', '-uall'], { cwd: fixture.cwd, encoding: 'utf-8' });
|
|
149
|
+
|
|
150
|
+
assert.equal(result.status, 'skipped');
|
|
151
|
+
assert.match(result.reason ?? '', /^git_commit_failed:/);
|
|
152
|
+
assert.equal(staged, '');
|
|
153
|
+
assert.match(status, /\?\? commit-fail\.txt/);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('exports canonical dedupe and protected-path helpers for fallback suppression', () => {
|
|
157
|
+
const key = teamWorkerPostToolUseInternals.buildDedupeKey({
|
|
158
|
+
teamName: 'team',
|
|
159
|
+
workerName: 'worker-1',
|
|
160
|
+
workerHeadAfter: 'after',
|
|
161
|
+
operationKind: 'leader_integration_attempt',
|
|
162
|
+
});
|
|
163
|
+
assert.equal(key, 'team|worker-1|after|leader_integration_attempt');
|
|
164
|
+
assert.equal(teamWorkerPostToolUseInternals.isProtectedCheckpointPath('.omx/state/team/x'), true);
|
|
165
|
+
assert.equal(teamWorkerPostToolUseInternals.isProtectedCheckpointPath('src/index.ts'), false);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('fails closed for missing worker identity without guessed state writes', async () => {
|
|
169
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-posttooluse-missing-identity-'));
|
|
170
|
+
const result = await handleTeamWorkerPostToolUseSuccess(successPayload, cwd, {
|
|
171
|
+
...process.env,
|
|
172
|
+
OMX_TEAM_WORKER: 'demo-team/worker-1',
|
|
173
|
+
OMX_TEAM_STATE_ROOT: join(cwd, '.omx', 'state'),
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
assert.equal(result.handled, false);
|
|
177
|
+
assert.equal(result.status, 'skipped');
|
|
178
|
+
assert.equal(existsSync(join(cwd, '.omx', 'state', 'team')), false);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -6,6 +6,9 @@ import { runProcess } from './process-runner.js';
|
|
|
6
6
|
import { safeString } from './utils.js';
|
|
7
7
|
import { sameFilePath } from '../../utils/paths.js';
|
|
8
8
|
|
|
9
|
+
const OMX_INSTANCE_OPTION = '@omx_instance_id';
|
|
10
|
+
const OMX_PANE_INSTANCE_OPTION = '@omx_pane_instance_id';
|
|
11
|
+
|
|
9
12
|
function sanitizeTmuxToken(value: string): string {
|
|
10
13
|
const cleaned = safeString(value)
|
|
11
14
|
.toLowerCase()
|
|
@@ -61,6 +64,10 @@ function readNativeSessionId(sessionState: { native_session_id?: unknown; codex_
|
|
|
61
64
|
return safeString(sessionState.native_session_id || sessionState.codex_session_id || '').trim();
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
function readAuthoritativeTmuxSessionName(sessionState: { tmux_session_name?: unknown; tmuxSessionName?: unknown }): string {
|
|
68
|
+
return safeString(sessionState.tmux_session_name || sessionState.tmuxSessionName || '').trim();
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
function readCurrentTmuxSessionName(): string {
|
|
65
72
|
if (!process.env.TMUX) return '';
|
|
66
73
|
try {
|
|
@@ -74,6 +81,54 @@ function readCurrentTmuxSessionName(): string {
|
|
|
74
81
|
}
|
|
75
82
|
}
|
|
76
83
|
|
|
84
|
+
async function readTmuxOption(targetValue: string, optionName: string, { pane = false } = {}): Promise<string> {
|
|
85
|
+
const target = safeString(targetValue).trim();
|
|
86
|
+
if (!target) return '';
|
|
87
|
+
const args = ['show-option', '-qv'];
|
|
88
|
+
if (pane) args.push('-p');
|
|
89
|
+
args.push('-t', target, optionName);
|
|
90
|
+
try {
|
|
91
|
+
const result = await runProcess('tmux', args, 2000);
|
|
92
|
+
return safeString(result.stdout).trim();
|
|
93
|
+
} catch {
|
|
94
|
+
return '';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function readTmuxSessionInstanceId(sessionTarget: string): Promise<string> {
|
|
99
|
+
return readTmuxOption(sessionTarget, OMX_INSTANCE_OPTION);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function readTmuxPaneInstanceId(paneTarget: string): Promise<string> {
|
|
103
|
+
return readTmuxOption(paneTarget, OMX_PANE_INSTANCE_OPTION, { pane: true });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function warnPaneInstanceFallback(paneTarget: string): void {
|
|
107
|
+
const target = safeString(paneTarget).trim();
|
|
108
|
+
if (!target) return;
|
|
109
|
+
try {
|
|
110
|
+
console.warn(`[omx] missing ${OMX_PANE_INSTANCE_OPTION} on ${target}; falling back to ${OMX_INSTANCE_OPTION}`);
|
|
111
|
+
} catch {
|
|
112
|
+
// warning is best effort only
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function resolveTmuxSessionForInstance(instanceId: string): Promise<string> {
|
|
117
|
+
const expected = safeString(instanceId).trim();
|
|
118
|
+
if (!expected) return '';
|
|
119
|
+
try {
|
|
120
|
+
const result = await runProcess('tmux', ['list-sessions', '-F', `#{session_name}\t#{${OMX_INSTANCE_OPTION}}`], 2000);
|
|
121
|
+
const rows = safeString(result.stdout).split('\n').map(line => line.trim()).filter(Boolean);
|
|
122
|
+
for (const row of rows) {
|
|
123
|
+
const [sessionName = '', taggedInstanceId = ''] = row.split('\t');
|
|
124
|
+
if (sessionName && taggedInstanceId === expected) return sessionName;
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
// best effort only
|
|
128
|
+
}
|
|
129
|
+
return '';
|
|
130
|
+
}
|
|
131
|
+
|
|
77
132
|
function readParentPid(pid: number): number | null {
|
|
78
133
|
if (!Number.isInteger(pid) || pid <= 1) return null;
|
|
79
134
|
try {
|
|
@@ -111,7 +166,11 @@ function processHasAncestorPid(targetPid: number, currentPid = process.pid): boo
|
|
|
111
166
|
return false;
|
|
112
167
|
}
|
|
113
168
|
|
|
114
|
-
export async function resolveManagedSessionContext(
|
|
169
|
+
export async function resolveManagedSessionContext(
|
|
170
|
+
cwd: string,
|
|
171
|
+
payload: any,
|
|
172
|
+
{ allowTeamWorker = true, paneTarget = '' }: { allowTeamWorker?: boolean; paneTarget?: string } = {},
|
|
173
|
+
): Promise<any> {
|
|
115
174
|
if (allowTeamWorker && safeString(process.env.OMX_TEAM_WORKER || '').trim() !== '') {
|
|
116
175
|
return {
|
|
117
176
|
managed: true,
|
|
@@ -150,15 +209,88 @@ export async function resolveManagedSessionContext(cwd: string, payload: any, {
|
|
|
150
209
|
return { managed: false, reason: 'session_id_mismatch', invocationSessionId, sessionState, expectedTmuxSessionName: '', currentTmuxSessionName: '' };
|
|
151
210
|
}
|
|
152
211
|
if (isSessionStale(sessionState)) {
|
|
153
|
-
return { managed: false, reason: 'stale_session', invocationSessionId, sessionState, expectedTmuxSessionName: '', currentTmuxSessionName: '' };
|
|
212
|
+
return { managed: false, reason: 'stale_session', invocationSessionId, sessionState, expectedTmuxSessionName: '', currentTmuxSessionName: '', taggedTmuxSessionName: '' };
|
|
154
213
|
}
|
|
155
214
|
|
|
156
215
|
const authoritativeSessionCwd = safeString(sessionState.cwd || cwd).trim() || cwd;
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
216
|
+
const authoritativeTmuxSessionName = readAuthoritativeTmuxSessionName(sessionState);
|
|
217
|
+
const expectedTmuxSessionName = authoritativeTmuxSessionName
|
|
218
|
+
|| buildExpectedManagedTmuxSessionName(
|
|
219
|
+
authoritativeSessionCwd,
|
|
220
|
+
canonicalSessionId || invocationSessionId,
|
|
221
|
+
);
|
|
161
222
|
const currentTmuxSessionName = readCurrentTmuxSessionName();
|
|
223
|
+
const currentTmuxPaneTarget = safeString(paneTarget || process.env.TMUX_PANE || '').trim();
|
|
224
|
+
const currentTmuxPaneInstanceId = currentTmuxPaneTarget ? await readTmuxPaneInstanceId(currentTmuxPaneTarget) : '';
|
|
225
|
+
if (currentTmuxPaneInstanceId && currentTmuxPaneInstanceId !== invocationSessionId) {
|
|
226
|
+
return {
|
|
227
|
+
managed: false,
|
|
228
|
+
reason: 'pane_instance_mismatch',
|
|
229
|
+
invocationSessionId,
|
|
230
|
+
sessionState,
|
|
231
|
+
expectedTmuxSessionName,
|
|
232
|
+
currentTmuxSessionName,
|
|
233
|
+
currentTmuxPaneTarget,
|
|
234
|
+
currentTmuxPaneInstanceId,
|
|
235
|
+
taggedTmuxSessionName: '',
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (currentTmuxPaneInstanceId === invocationSessionId) {
|
|
239
|
+
return {
|
|
240
|
+
managed: true,
|
|
241
|
+
reason: 'tmux_pane_instance_match',
|
|
242
|
+
invocationSessionId,
|
|
243
|
+
sessionState,
|
|
244
|
+
expectedTmuxSessionName,
|
|
245
|
+
currentTmuxSessionName,
|
|
246
|
+
currentTmuxPaneTarget,
|
|
247
|
+
currentTmuxPaneInstanceId,
|
|
248
|
+
taggedTmuxSessionName: currentTmuxSessionName,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const currentTmuxInstanceId = currentTmuxSessionName ? await readTmuxSessionInstanceId(currentTmuxSessionName) : '';
|
|
253
|
+
if (currentTmuxInstanceId && currentTmuxInstanceId !== invocationSessionId) {
|
|
254
|
+
return {
|
|
255
|
+
managed: false,
|
|
256
|
+
reason: 'tmux_instance_mismatch',
|
|
257
|
+
invocationSessionId,
|
|
258
|
+
sessionState,
|
|
259
|
+
expectedTmuxSessionName,
|
|
260
|
+
currentTmuxSessionName,
|
|
261
|
+
currentTmuxInstanceId,
|
|
262
|
+
taggedTmuxSessionName: '',
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (currentTmuxInstanceId === invocationSessionId) {
|
|
266
|
+
if (currentTmuxPaneTarget) warnPaneInstanceFallback(currentTmuxPaneTarget);
|
|
267
|
+
return {
|
|
268
|
+
managed: true,
|
|
269
|
+
reason: 'tmux_instance_match',
|
|
270
|
+
invocationSessionId,
|
|
271
|
+
sessionState,
|
|
272
|
+
expectedTmuxSessionName,
|
|
273
|
+
currentTmuxSessionName,
|
|
274
|
+
currentTmuxInstanceId,
|
|
275
|
+
currentTmuxPaneTarget,
|
|
276
|
+
paneInstanceWarning: 'missing_pane_instance_tag_session_fallback',
|
|
277
|
+
taggedTmuxSessionName: currentTmuxSessionName,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const taggedTmuxSessionName = await resolveTmuxSessionForInstance(invocationSessionId);
|
|
282
|
+
if (taggedTmuxSessionName) {
|
|
283
|
+
return {
|
|
284
|
+
managed: true,
|
|
285
|
+
reason: 'tmux_instance_tag_match',
|
|
286
|
+
invocationSessionId,
|
|
287
|
+
sessionState,
|
|
288
|
+
expectedTmuxSessionName,
|
|
289
|
+
currentTmuxSessionName,
|
|
290
|
+
taggedTmuxSessionName,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
162
294
|
if (currentTmuxSessionName && currentTmuxSessionName === expectedTmuxSessionName) {
|
|
163
295
|
return {
|
|
164
296
|
managed: true,
|
|
@@ -171,6 +303,19 @@ export async function resolveManagedSessionContext(cwd: string, payload: any, {
|
|
|
171
303
|
currentTmuxSessionName,
|
|
172
304
|
};
|
|
173
305
|
}
|
|
306
|
+
if (authoritativeTmuxSessionName && currentTmuxSessionName) {
|
|
307
|
+
return {
|
|
308
|
+
managed: false,
|
|
309
|
+
reason: 'tmux_session_mismatch',
|
|
310
|
+
invocationSessionId,
|
|
311
|
+
canonicalSessionId,
|
|
312
|
+
nativeSessionId,
|
|
313
|
+
sessionState,
|
|
314
|
+
expectedTmuxSessionName,
|
|
315
|
+
currentTmuxSessionName,
|
|
316
|
+
taggedTmuxSessionName: '',
|
|
317
|
+
};
|
|
318
|
+
}
|
|
174
319
|
|
|
175
320
|
if (processHasAncestorPid(sessionState.pid)) {
|
|
176
321
|
return {
|
|
@@ -182,6 +327,7 @@ export async function resolveManagedSessionContext(cwd: string, payload: any, {
|
|
|
182
327
|
sessionState,
|
|
183
328
|
expectedTmuxSessionName,
|
|
184
329
|
currentTmuxSessionName: '',
|
|
330
|
+
taggedTmuxSessionName: '',
|
|
185
331
|
};
|
|
186
332
|
}
|
|
187
333
|
|
|
@@ -194,6 +340,7 @@ export async function resolveManagedSessionContext(cwd: string, payload: any, {
|
|
|
194
340
|
sessionState,
|
|
195
341
|
expectedTmuxSessionName,
|
|
196
342
|
currentTmuxSessionName,
|
|
343
|
+
taggedTmuxSessionName: '',
|
|
197
344
|
};
|
|
198
345
|
} catch {
|
|
199
346
|
return {
|
|
@@ -203,6 +350,7 @@ export async function resolveManagedSessionContext(cwd: string, payload: any, {
|
|
|
203
350
|
sessionState: null,
|
|
204
351
|
expectedTmuxSessionName: '',
|
|
205
352
|
currentTmuxSessionName: '',
|
|
353
|
+
taggedTmuxSessionName: '',
|
|
206
354
|
};
|
|
207
355
|
}
|
|
208
356
|
}
|
|
@@ -218,7 +366,7 @@ export async function verifyManagedPaneTarget(paneId: string, cwd: string, paylo
|
|
|
218
366
|
return { ok: false, reason: 'missing_pane_target', paneTarget: '' };
|
|
219
367
|
}
|
|
220
368
|
|
|
221
|
-
const managedContext = await resolveManagedSessionContext(cwd, payload, { allowTeamWorker });
|
|
369
|
+
const managedContext = await resolveManagedSessionContext(cwd, payload, { allowTeamWorker, paneTarget });
|
|
222
370
|
if (!managedContext.managed) {
|
|
223
371
|
return { ok: false, reason: managedContext.reason || 'unmanaged_session', paneTarget, managedContext };
|
|
224
372
|
}
|
|
@@ -238,10 +386,49 @@ export async function verifyManagedPaneTarget(paneId: string, cwd: string, paylo
|
|
|
238
386
|
if (!paneSessionName) {
|
|
239
387
|
return { ok: false, reason: 'pane_session_missing', paneTarget, managedContext };
|
|
240
388
|
}
|
|
389
|
+
const paneInstanceId = await readTmuxPaneInstanceId(paneTarget);
|
|
390
|
+
const sessionInstanceId = paneInstanceId ? '' : await readTmuxSessionInstanceId(paneSessionName);
|
|
391
|
+
if (paneInstanceId && paneInstanceId !== managedContext.invocationSessionId) {
|
|
392
|
+
return { ok: false, reason: 'pane_instance_mismatch', paneTarget, paneSessionName, paneInstanceId, managedContext };
|
|
393
|
+
}
|
|
394
|
+
if (!paneInstanceId && sessionInstanceId) {
|
|
395
|
+
warnPaneInstanceFallback(paneTarget);
|
|
396
|
+
if (sessionInstanceId !== managedContext.invocationSessionId) {
|
|
397
|
+
return {
|
|
398
|
+
ok: false,
|
|
399
|
+
reason: 'pane_instance_mismatch',
|
|
400
|
+
paneTarget,
|
|
401
|
+
paneSessionName,
|
|
402
|
+
paneInstanceId: sessionInstanceId,
|
|
403
|
+
paneInstanceWarning: 'missing_pane_instance_tag_session_fallback',
|
|
404
|
+
managedContext,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
}
|
|
241
408
|
if (paneSessionName !== expectedSession) {
|
|
409
|
+
const taggedSession = safeString(managedContext.taggedTmuxSessionName).trim();
|
|
410
|
+
if (taggedSession && paneSessionName === taggedSession) {
|
|
411
|
+
return {
|
|
412
|
+
ok: true,
|
|
413
|
+
reason: 'ok',
|
|
414
|
+
paneTarget,
|
|
415
|
+
paneSessionName,
|
|
416
|
+
paneInstanceId: paneInstanceId || sessionInstanceId,
|
|
417
|
+
paneInstanceWarning: paneInstanceId ? '' : 'missing_pane_instance_tag_session_fallback',
|
|
418
|
+
managedContext,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
242
421
|
return { ok: false, reason: 'pane_not_managed_session', paneTarget, paneSessionName, managedContext };
|
|
243
422
|
}
|
|
244
|
-
return {
|
|
423
|
+
return {
|
|
424
|
+
ok: true,
|
|
425
|
+
reason: 'ok',
|
|
426
|
+
paneTarget,
|
|
427
|
+
paneSessionName,
|
|
428
|
+
paneInstanceId: paneInstanceId || sessionInstanceId,
|
|
429
|
+
paneInstanceWarning: paneInstanceId ? '' : 'missing_pane_instance_tag_session_fallback',
|
|
430
|
+
managedContext,
|
|
431
|
+
};
|
|
245
432
|
} catch {
|
|
246
433
|
return { ok: false, reason: 'pane_session_lookup_failed', paneTarget, managedContext };
|
|
247
434
|
}
|
|
@@ -334,7 +521,7 @@ export async function resolveManagedCurrentPane(cwd: string, payload: any, { all
|
|
|
334
521
|
export async function resolveManagedSessionPane(cwd: string, payload: any): Promise<string> {
|
|
335
522
|
const managedContext = await resolveManagedSessionContext(cwd, payload, { allowTeamWorker: false });
|
|
336
523
|
if (!managedContext.managed) return '';
|
|
337
|
-
const expectedSession = safeString(managedContext.expectedTmuxSessionName).trim();
|
|
524
|
+
const expectedSession = safeString(managedContext.taggedTmuxSessionName || managedContext.expectedTmuxSessionName).trim();
|
|
338
525
|
if (!expectedSession) return '';
|
|
339
526
|
|
|
340
527
|
try {
|
|
@@ -6,7 +6,11 @@ import { spawn } from 'child_process';
|
|
|
6
6
|
|
|
7
7
|
export function runProcess(command: string, args: string[], timeoutMs = 3000): Promise<{ stdout: string; stderr: string; code: number | null }> {
|
|
8
8
|
return new Promise((resolve, reject) => {
|
|
9
|
-
const
|
|
9
|
+
const usingTestTmux = command === 'tmux' && process.env.OMX_TEST_TMUX_BIN;
|
|
10
|
+
const relaxingTestTmuxTimeout = command === 'tmux' && process.env.OMX_TEST_RELAX_TMUX_TIMEOUT === '1';
|
|
11
|
+
const executable = usingTestTmux ? process.env.OMX_TEST_TMUX_BIN as string : command;
|
|
12
|
+
const effectiveTimeoutMs = usingTestTmux || relaxingTestTmuxTimeout ? Math.max(timeoutMs, 10_000) : timeoutMs;
|
|
13
|
+
const child = spawn(executable, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
10
14
|
let stdout = '';
|
|
11
15
|
let stderr = '';
|
|
12
16
|
let finished = false;
|
|
@@ -15,8 +19,8 @@ export function runProcess(command: string, args: string[], timeoutMs = 3000): P
|
|
|
15
19
|
if (finished) return;
|
|
16
20
|
finished = true;
|
|
17
21
|
child.kill('SIGTERM');
|
|
18
|
-
reject(new Error(`timeout after ${
|
|
19
|
-
},
|
|
22
|
+
reject(new Error(`timeout after ${effectiveTimeoutMs}ms`));
|
|
23
|
+
}, effectiveTimeoutMs);
|
|
20
24
|
|
|
21
25
|
child.stdout.on('data', (chunk: Buffer) => {
|
|
22
26
|
stdout += chunk.toString();
|