oh-my-codex 0.14.4 → 0.15.1
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/.agents/plugins/marketplace.json +20 -0
- package/Cargo.lock +6 -6
- package/Cargo.toml +2 -1
- package/README.md +40 -7
- package/crates/omx-explore/Cargo.toml +1 -0
- package/crates/omx-explore/src/main.rs +246 -24
- package/crates/omx-mux/Cargo.toml +1 -0
- package/crates/omx-runtime/Cargo.toml +1 -0
- package/crates/omx-runtime-core/Cargo.toml +1 -0
- package/crates/omx-runtime-core/src/dispatch.rs +2 -1
- package/crates/omx-runtime-core/src/engine.rs +2 -2
- package/crates/omx-runtime-core/src/mailbox.rs +2 -1
- package/crates/omx-sparkshell/Cargo.toml +1 -0
- package/crates/omx-sparkshell/src/codex_bridge.rs +1 -0
- package/crates/omx-sparkshell/src/prompt.rs +1 -0
- package/crates/omx-sparkshell/src/threshold.rs +1 -0
- package/dist/agents/__tests__/native-config.test.js +98 -4
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts +4 -0
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +19 -3
- package/dist/agents/native-config.js.map +1 -1
- package/dist/agents/policy.d.ts +10 -0
- package/dist/agents/policy.d.ts.map +1 -0
- package/dist/agents/policy.js +61 -0
- package/dist/agents/policy.js.map +1 -0
- package/dist/catalog/__tests__/generator.test.js +2 -0
- package/dist/catalog/__tests__/generator.test.js.map +1 -1
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts +2 -0
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.d.ts.map +1 -0
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +72 -0
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -0
- package/dist/catalog/installable.d.ts +5 -0
- package/dist/catalog/installable.d.ts.map +1 -0
- package/dist/catalog/installable.js +13 -0
- package/dist/catalog/installable.js.map +1 -0
- package/dist/catalog/skill-mirror.d.ts +20 -0
- package/dist/catalog/skill-mirror.d.ts.map +1 -0
- package/dist/catalog/skill-mirror.js +104 -0
- package/dist/catalog/skill-mirror.js.map +1 -0
- package/dist/cli/__tests__/ask.test.js +4 -1
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.d.ts +2 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.d.ts.map +1 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js +210 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -0
- 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 +26 -9
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +301 -7
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +358 -4
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/list.test.d.ts +2 -0
- package/dist/cli/__tests__/list.test.d.ts.map +1 -0
- package/dist/cli/__tests__/list.test.js +38 -0
- package/dist/cli/__tests__/list.test.js.map +1 -0
- 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__/mcp-serve.test.d.ts +2 -0
- package/dist/cli/__tests__/mcp-serve.test.d.ts.map +1 -0
- package/dist/cli/__tests__/mcp-serve.test.js +38 -0
- package/dist/cli/__tests__/mcp-serve.test.js.map +1 -0
- package/dist/cli/__tests__/nested-help-routing.test.js +1 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +58 -3
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +209 -5
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +146 -3
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-install-mode.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-install-mode.test.js +873 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -0
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js +83 -22
- package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +120 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +32 -13
- package/dist/cli/__tests__/setup-skills-overwrite.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 +90 -42
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/version-sync-contract.test.js +11 -0
- package/dist/cli/__tests__/version-sync-contract.test.js.map +1 -1
- package/dist/cli/codex-home.d.ts +4 -5
- package/dist/cli/codex-home.d.ts.map +1 -1
- package/dist/cli/codex-home.js +9 -37
- 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 -278
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +13 -5
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +351 -60
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/list.d.ts +2 -0
- package/dist/cli/list.d.ts.map +1 -0
- package/dist/cli/list.js +40 -0
- package/dist/cli/list.js.map +1 -0
- package/dist/cli/mcp-serve.d.ts +12 -0
- package/dist/cli/mcp-serve.d.ts.map +1 -0
- package/dist/cli/mcp-serve.js +63 -0
- package/dist/cli/mcp-serve.js.map +1 -0
- 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.map +1 -1
- package/dist/cli/question.js +27 -2
- 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 +12 -3
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1080 -254
- 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 +22 -3
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +2 -8
- package/dist/cli/uninstall.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 +35 -2
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +2 -7
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +10 -0
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +259 -76
- package/dist/config/generator.js.map +1 -1
- package/dist/config/models.d.ts +13 -3
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +25 -5
- package/dist/config/models.js.map +1 -1
- package/dist/config/omx-first-party-mcp.d.ts +18 -0
- package/dist/config/omx-first-party-mcp.d.ts.map +1 -0
- package/dist/config/omx-first-party-mcp.js +76 -0
- package/dist/config/omx-first-party-mcp.js.map +1 -0
- package/dist/document-refresh/__tests__/enforcer.test.d.ts +2 -0
- package/dist/document-refresh/__tests__/enforcer.test.d.ts.map +1 -0
- package/dist/document-refresh/__tests__/enforcer.test.js +128 -0
- package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -0
- package/dist/document-refresh/config.d.ts +9 -0
- package/dist/document-refresh/config.d.ts.map +1 -0
- package/dist/document-refresh/config.js +70 -0
- package/dist/document-refresh/config.js.map +1 -0
- package/dist/document-refresh/enforcer.d.ts +43 -0
- package/dist/document-refresh/enforcer.d.ts.map +1 -0
- package/dist/document-refresh/enforcer.js +329 -0
- package/dist/document-refresh/enforcer.js.map +1 -0
- 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__/codebase-map.test.js +63 -1
- package/dist/hooks/__tests__/codebase-map.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +10 -7
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +89 -0
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +84 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.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 +43 -0
- 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 +53 -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-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-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-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/__tests__/team-runtime-gating-docs-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js +28 -0
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/triage-heuristic.test.js +59 -4
- package/dist/hooks/__tests__/triage-heuristic.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts +2 -0
- package/dist/hooks/__tests__/visual-ralph-skill.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/visual-ralph-skill.test.js +44 -0
- package/dist/hooks/__tests__/visual-ralph-skill.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.map +1 -1
- package/dist/hooks/keyword-detector.js +19 -14
- 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 +89 -0
- 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/hooks/triage-heuristic.d.ts +2 -2
- package/dist/hooks/triage-heuristic.d.ts.map +1 -1
- package/dist/hooks/triage-heuristic.js +97 -20
- package/dist/hooks/triage-heuristic.js.map +1 -1
- package/dist/hooks/triage-state.d.ts +1 -1
- package/dist/hooks/triage-state.d.ts.map +1 -1
- package/dist/hooks/triage-state.js +2 -1
- package/dist/hooks/triage-state.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 +45 -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 +67 -9
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +12 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +87 -29
- 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/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__/deep-interview.test.js +1 -1
- package/dist/question/__tests__/deep-interview.test.js.map +1 -1
- package/dist/question/__tests__/renderer.test.js +70 -0
- package/dist/question/__tests__/renderer.test.js.map +1 -1
- package/dist/question/__tests__/ui.test.js +49 -0
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/renderer.d.ts +14 -1
- package/dist/question/renderer.d.ts.map +1 -1
- package/dist/question/renderer.js +109 -10
- package/dist/question/renderer.js.map +1 -1
- package/dist/question/state.d.ts +2 -0
- package/dist/question/state.d.ts.map +1 -1
- package/dist/question/state.js +4 -0
- package/dist/question/state.js.map +1 -1
- package/dist/question/types.d.ts +2 -1
- package/dist/question/types.d.ts.map +1 -1
- package/dist/question/types.js.map +1 -1
- package/dist/question/ui.d.ts.map +1 -1
- package/dist/question/ui.js +28 -8
- package/dist/question/ui.js.map +1 -1
- package/dist/runtime/__tests__/bridge.test.js +143 -1
- package/dist/runtime/__tests__/bridge.test.js.map +1 -1
- package/dist/runtime/bridge.d.ts +21 -0
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js +54 -4
- package/dist/runtime/bridge.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +1904 -230
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/generate-release-body.test.js +90 -1
- package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
- package/dist/scripts/__tests__/hook-derived-watcher.test.js +110 -2
- package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
- package/dist/scripts/__tests__/postinstall.test.js +7 -93
- package/dist/scripts/__tests__/postinstall.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/__tests__/run-test-files.test.d.ts +2 -0
- package/dist/scripts/__tests__/run-test-files.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/run-test-files.test.js +62 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -0
- package/dist/scripts/__tests__/smoke-packed-install.test.js +13 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-agents.test.d.ts +2 -0
- package/dist/scripts/__tests__/verify-native-agents.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/verify-native-agents.test.js +166 -0
- package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -0
- package/dist/scripts/codex-execution-surface.d.ts +16 -0
- package/dist/scripts/codex-execution-surface.d.ts.map +1 -0
- package/dist/scripts/codex-execution-surface.js +42 -0
- package/dist/scripts/codex-execution-surface.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +418 -76
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts +8 -0
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +133 -19
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/generate-release-body.d.ts +1 -0
- package/dist/scripts/generate-release-body.d.ts.map +1 -1
- package/dist/scripts/generate-release-body.js +32 -3
- package/dist/scripts/generate-release-body.js.map +1 -1
- package/dist/scripts/hook-derived-watcher.js +46 -7
- package/dist/scripts/hook-derived-watcher.js.map +1 -1
- package/dist/scripts/notify-fallback-watcher.js +59 -9
- package/dist/scripts/notify-fallback-watcher.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.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +18 -1
- 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.js +36 -5
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall.d.ts +1 -5
- package/dist/scripts/postinstall.d.ts.map +1 -1
- package/dist/scripts/postinstall.js +3 -42
- package/dist/scripts/postinstall.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 +32 -2
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +3 -0
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +9 -1
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.d.ts +13 -0
- package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -0
- package/dist/scripts/sync-plugin-mirror.js +242 -0
- package/dist/scripts/sync-plugin-mirror.js.map +1 -0
- package/dist/scripts/verify-native-agents.d.ts +16 -0
- package/dist/scripts/verify-native-agents.d.ts.map +1 -0
- package/dist/scripts/verify-native-agents.js +188 -0
- package/dist/scripts/verify-native-agents.js.map +1 -0
- package/dist/session-history/search.d.ts.map +1 -1
- package/dist/session-history/search.js +7 -2
- package/dist/session-history/search.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/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/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 +18 -2
- 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 +677 -17
- 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 +301 -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 +34 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +191 -50
- 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 +83 -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/__tests__/agents-model-table.test.js +8 -0
- package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
- package/dist/utils/__tests__/paths.test.js +42 -9
- package/dist/utils/__tests__/paths.test.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/dist/utils/agents-model-table.d.ts.map +1 -1
- package/dist/utils/agents-model-table.js +2 -3
- package/dist/utils/agents-model-table.js.map +1 -1
- package/package.json +14 -7
- package/plugins/oh-my-codex/.app.json +3 -0
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +30 -0
- package/plugins/oh-my-codex/.mcp.json +44 -0
- package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +114 -0
- package/plugins/oh-my-codex/skills/analyze/SKILL.md +148 -0
- package/plugins/oh-my-codex/skills/ask-claude/SKILL.md +61 -0
- package/plugins/oh-my-codex/skills/ask-gemini/SKILL.md +61 -0
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +231 -0
- package/plugins/oh-my-codex/skills/autoresearch/SKILL.md +68 -0
- package/plugins/oh-my-codex/skills/cancel/SKILL.md +399 -0
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +290 -0
- package/plugins/oh-my-codex/skills/configure-notifications/SKILL.md +287 -0
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +464 -0
- package/plugins/oh-my-codex/skills/doctor/SKILL.md +239 -0
- package/plugins/oh-my-codex/skills/help/SKILL.md +202 -0
- package/plugins/oh-my-codex/skills/hud/SKILL.md +98 -0
- package/plugins/oh-my-codex/skills/note/SKILL.md +62 -0
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +135 -0
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +86 -0
- package/plugins/oh-my-codex/skills/plan/SKILL.md +276 -0
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +269 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +162 -0
- package/plugins/oh-my-codex/skills/security-review/SKILL.md +300 -0
- package/plugins/oh-my-codex/skills/skill/SKILL.md +835 -0
- package/plugins/oh-my-codex/skills/team/SKILL.md +510 -0
- package/plugins/oh-my-codex/skills/trace/SKILL.md +33 -0
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +143 -0
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +175 -0
- package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +153 -0
- package/plugins/oh-my-codex/skills/visual-verdict/SKILL.md +76 -0
- package/plugins/oh-my-codex/skills/wiki/SKILL.md +57 -0
- package/plugins/oh-my-codex/skills/worker/SKILL.md +106 -0
- package/prompts/critic.md +35 -83
- package/prompts/executor.md +32 -109
- package/prompts/explore-harness.md +1 -1
- package/prompts/explore.md +37 -90
- package/prompts/planner.md +28 -58
- package/prompts/researcher.md +46 -78
- package/prompts/verifier.md +23 -31
- package/skills/autopilot/SKILL.md +1 -4
- package/skills/deep-interview/SKILL.md +8 -5
- package/skills/doctor/SKILL.md +45 -17
- package/skills/help/SKILL.md +2 -2
- package/skills/omx-setup/SKILL.md +52 -9
- package/skills/plan/SKILL.md +1 -4
- package/skills/ralph/SKILL.md +3 -5
- package/skills/ralplan/SKILL.md +2 -6
- package/skills/team/SKILL.md +2 -5
- package/skills/ultraqa/SKILL.md +1 -4
- package/skills/ultrawork/SKILL.md +2 -3
- package/skills/visual-ralph/SKILL.md +153 -0
- package/skills/web-clone/SKILL.md +12 -354
- package/src/scripts/__tests__/codex-native-hook.test.ts +2306 -224
- package/src/scripts/__tests__/generate-release-body.test.ts +109 -0
- package/src/scripts/__tests__/hook-derived-watcher.test.ts +132 -2
- package/src/scripts/__tests__/postinstall.test.ts +7 -104
- package/src/scripts/__tests__/prompt-inventory.test.ts +64 -0
- package/src/scripts/__tests__/run-test-files.test.ts +72 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +15 -0
- package/src/scripts/__tests__/verify-native-agents.test.ts +204 -0
- package/src/scripts/codex-execution-surface.ts +73 -0
- package/src/scripts/codex-native-hook.ts +579 -82
- package/src/scripts/codex-native-pre-post.ts +157 -19
- package/src/scripts/generate-release-body.ts +34 -2
- package/src/scripts/hook-derived-watcher.ts +51 -8
- package/src/scripts/notify-fallback-watcher.ts +65 -9
- package/src/scripts/notify-hook/__tests__/team-worker-posttooluse.test.ts +180 -0
- package/src/scripts/notify-hook/managed-tmux.ts +22 -4
- 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.ts +36 -5
- package/src/scripts/postinstall.ts +4 -58
- package/src/scripts/prompt-inventory.ts +218 -0
- package/src/scripts/run-test-files.ts +41 -2
- package/src/scripts/smoke-packed-install.ts +10 -1
- package/src/scripts/sync-plugin-mirror.ts +360 -0
- package/src/scripts/verify-native-agents.ts +245 -0
- package/templates/AGENTS.md +26 -91
- package/templates/catalog-manifest.json +16 -1
|
@@ -6,8 +6,8 @@ import { join } from 'path';
|
|
|
6
6
|
import { tmpdir } from 'os';
|
|
7
7
|
import { existsSync } from 'fs';
|
|
8
8
|
import { HUD_TMUX_TEAM_HEIGHT_LINES } from '../../hud/constants.js';
|
|
9
|
-
import { initTeamState, createTask, readTeamConfig, saveTeamConfig, listMailboxMessages, listDispatchRequests, transitionDispatchRequest, updateWorkerHeartbeat, writeAtomic, readTask, readMonitorSnapshot, claimTask, transitionTaskStatus, readWorkerStatus, writeWorkerStatus, } from '../state.js';
|
|
10
|
-
import { monitorTeam, shutdownTeam, resumeTeam, startTeam, assignTask, sendWorkerMessage, applyCreatedInteractiveSessionToConfig, resolveWorkerLaunchArgsFromEnv, shouldPrekillInteractiveShutdownProcessTrees, waitForWorkerStartupEvidence, waitForClaudeStartupEvidence, } from '../runtime.js';
|
|
9
|
+
import { initTeamState, createTask, writeWorkerInbox, readTeamConfig, saveTeamConfig, listMailboxMessages, listDispatchRequests, transitionDispatchRequest, updateWorkerHeartbeat, writeAtomic, readTask, readMonitorSnapshot, claimTask, transitionTaskStatus, readWorkerStatus, writeWorkerStatus, } from '../state.js';
|
|
10
|
+
import { monitorTeam, shutdownTeam, resumeTeam, startTeam, assignTask, sendWorkerMessage, applyCreatedInteractiveSessionToConfig, resolveWorkerLaunchArgsFromEnv, shouldPrekillInteractiveShutdownProcessTrees, waitForWorkerStartupEvidence, waitForClaudeStartupEvidence, cleanupTeamWorkerLaunchOrphanedMcpProcesses, settleStartupAttemptResults, } from '../runtime.js';
|
|
11
11
|
import { resolveAgentReasoningEffort, resolveTeamLowComplexityDefaultModel } from '../model-contract.js';
|
|
12
12
|
import { readTeamEvents } from '../state/events.js';
|
|
13
13
|
import { sanitizeTeamName } from '../tmux-session.js';
|
|
@@ -56,6 +56,21 @@ async function readTeamDeliveryLog(cwd) {
|
|
|
56
56
|
.filter(Boolean)
|
|
57
57
|
.map((line) => JSON.parse(line));
|
|
58
58
|
}
|
|
59
|
+
async function markPendingInboxDispatchesDelivered(teamName, cwd, opts = {}) {
|
|
60
|
+
const requests = await listDispatchRequests(teamName, cwd, { kind: 'inbox' }).catch(() => []);
|
|
61
|
+
for (const request of requests) {
|
|
62
|
+
if (request.status !== 'pending')
|
|
63
|
+
continue;
|
|
64
|
+
if (opts.toWorker && request.to_worker !== opts.toWorker)
|
|
65
|
+
continue;
|
|
66
|
+
await opts.beforeDeliver?.();
|
|
67
|
+
const notified = await transitionDispatchRequest(teamName, request.request_id, 'pending', 'notified', { last_reason: opts.lastReason ?? 'test_delivered_receipt' }, cwd).catch(() => null);
|
|
68
|
+
if (!notified)
|
|
69
|
+
continue;
|
|
70
|
+
await transitionDispatchRequest(teamName, request.request_id, 'notified', 'delivered', { last_reason: opts.lastReason ?? 'test_delivered_receipt' }, cwd).catch(() => { });
|
|
71
|
+
await opts.afterDeliver?.();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
59
74
|
function withEmptyPath(fn) {
|
|
60
75
|
const prev = process.env.PATH;
|
|
61
76
|
process.env.PATH = '';
|
|
@@ -517,6 +532,30 @@ describe('runtime', () => {
|
|
|
517
532
|
await rm(cwd, { recursive: true, force: true });
|
|
518
533
|
}
|
|
519
534
|
});
|
|
535
|
+
it('cleanupTeamWorkerLaunchOrphanedMcpProcesses keeps ps and cleanup failures non-fatal', async () => {
|
|
536
|
+
const warnings = [];
|
|
537
|
+
let calls = 0;
|
|
538
|
+
await cleanupTeamWorkerLaunchOrphanedMcpProcesses({
|
|
539
|
+
cleanup: async () => {
|
|
540
|
+
calls += 1;
|
|
541
|
+
throw new Error('ps unavailable');
|
|
542
|
+
},
|
|
543
|
+
writeWarning: (message) => warnings.push(message),
|
|
544
|
+
});
|
|
545
|
+
await cleanupTeamWorkerLaunchOrphanedMcpProcesses({
|
|
546
|
+
cleanup: async () => ({
|
|
547
|
+
dryRun: false,
|
|
548
|
+
candidates: [],
|
|
549
|
+
terminatedCount: 0,
|
|
550
|
+
forceKilledCount: 0,
|
|
551
|
+
failedPids: [1234],
|
|
552
|
+
}),
|
|
553
|
+
writeWarning: (message) => warnings.push(message),
|
|
554
|
+
});
|
|
555
|
+
assert.equal(calls, 1);
|
|
556
|
+
assert.match(warnings.join('\n'), /ps unavailable.*continuing worker launch/);
|
|
557
|
+
assert.match(warnings.join('\n'), /Failed to reap 1 orphaned OMX MCP process/);
|
|
558
|
+
});
|
|
520
559
|
it('waitForWorkerStartupEvidence treats blocked worker status as settled progress even without a claimed task id', async () => {
|
|
521
560
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-codex-blocked-startup-'));
|
|
522
561
|
try {
|
|
@@ -785,10 +824,6 @@ sleep 5
|
|
|
785
824
|
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = prevLaunchMode;
|
|
786
825
|
else
|
|
787
826
|
delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
788
|
-
if (typeof prevWorkerCli === 'string')
|
|
789
|
-
process.env.OMX_TEAM_WORKER_CLI = prevWorkerCli;
|
|
790
|
-
else
|
|
791
|
-
delete process.env.OMX_TEAM_WORKER_CLI;
|
|
792
827
|
await rm(cwd, { recursive: true, force: true });
|
|
793
828
|
}
|
|
794
829
|
});
|
|
@@ -804,6 +839,7 @@ sleep 5
|
|
|
804
839
|
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = prevLaunchMode;
|
|
805
840
|
else
|
|
806
841
|
delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
842
|
+
delete process.env.OMX_TEAM_WORKER_CLI;
|
|
807
843
|
await rm(cwd, { recursive: true, force: true });
|
|
808
844
|
}
|
|
809
845
|
});
|
|
@@ -932,7 +968,7 @@ esac
|
|
|
932
968
|
delete process.env.WSL_DISTRO_NAME;
|
|
933
969
|
delete process.env.WSL_INTEROP;
|
|
934
970
|
Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
|
|
935
|
-
runtime = await withoutTeamWorkerEnv(() => startTeam('team-win32-no-env', 'native windows current-client detection', 'executor', 1, [{ subject: 's', description: 'd', owner: 'worker-1' }], cwd));
|
|
971
|
+
const runtime = await withoutTeamWorkerEnv(() => startTeam('team-win32-no-env', 'native windows current-client detection', 'executor', 1, [{ subject: 's', description: 'd', owner: 'worker-1' }], cwd));
|
|
936
972
|
teamNameForCleanup = runtime.teamName;
|
|
937
973
|
assert.equal(runtime.config.tmux_session, 'leader:0');
|
|
938
974
|
assert.equal(runtime.config.leader_pane_id, '%1');
|
|
@@ -943,7 +979,6 @@ esac
|
|
|
943
979
|
if (teamNameForCleanup) {
|
|
944
980
|
await shutdownTeam(teamNameForCleanup, cwd, { force: true });
|
|
945
981
|
}
|
|
946
|
-
runtime = null;
|
|
947
982
|
});
|
|
948
983
|
}
|
|
949
984
|
finally {
|
|
@@ -1017,6 +1052,115 @@ esac
|
|
|
1017
1052
|
await rm(cwd, { recursive: true, force: true });
|
|
1018
1053
|
}
|
|
1019
1054
|
});
|
|
1055
|
+
it('startTeam runs worker MCP orphan cleanup before interactive tmux worker spawn', async () => {
|
|
1056
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-interactive-mcp-cleanup-'));
|
|
1057
|
+
const prevTmux = process.env.TMUX;
|
|
1058
|
+
const prevTmuxPane = process.env.TMUX_PANE;
|
|
1059
|
+
const prevLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
1060
|
+
const prevWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
|
|
1061
|
+
const prevSkipReadyWait = process.env.OMX_TEAM_SKIP_READY_WAIT;
|
|
1062
|
+
let runtime = null;
|
|
1063
|
+
try {
|
|
1064
|
+
await withMockTmuxFixture({
|
|
1065
|
+
dirPrefix: 'omx-runtime-interactive-mcp-cleanup-bin-',
|
|
1066
|
+
tmuxScript: (tmuxLogPath) => `#!/bin/sh
|
|
1067
|
+
set -eu
|
|
1068
|
+
printf '%s\n' "$*" >> "${tmuxLogPath}"
|
|
1069
|
+
case "\${1:-}" in
|
|
1070
|
+
-V)
|
|
1071
|
+
echo "tmux 3.4"
|
|
1072
|
+
exit 0
|
|
1073
|
+
;;
|
|
1074
|
+
display-message)
|
|
1075
|
+
case "$*" in
|
|
1076
|
+
*"#{window_width}"*) echo "120" ;;
|
|
1077
|
+
*) echo "leader:0 %1" ;;
|
|
1078
|
+
esac
|
|
1079
|
+
exit 0
|
|
1080
|
+
;;
|
|
1081
|
+
list-panes)
|
|
1082
|
+
case "$*" in
|
|
1083
|
+
*"pane_current_command"*) printf "%%1\tnode\t'codex'\n" ;;
|
|
1084
|
+
*"#{pane_dead} #{pane_pid}"*) echo "1 999999" ;;
|
|
1085
|
+
*"-t %2"*"#{pane_pid}"*) echo "2222" ;;
|
|
1086
|
+
*"#{pane_pid}"*) echo "1111" ;;
|
|
1087
|
+
*) exit 0 ;;
|
|
1088
|
+
esac
|
|
1089
|
+
exit 0
|
|
1090
|
+
;;
|
|
1091
|
+
split-window)
|
|
1092
|
+
case "$*" in
|
|
1093
|
+
*" -h "*)
|
|
1094
|
+
mkdir -p "${cwd}/.omx/state/team/team-interactive-cleanup/workers/worker-1"
|
|
1095
|
+
cat > "${cwd}/.omx/state/team/team-interactive-cleanup/workers/worker-1/status.json" <<'EOF'
|
|
1096
|
+
{
|
|
1097
|
+
"state": "working",
|
|
1098
|
+
"current_task_id": "1",
|
|
1099
|
+
"updated_at": "2026-04-23T00:00:00.000Z"
|
|
1100
|
+
}
|
|
1101
|
+
EOF
|
|
1102
|
+
echo "%2"
|
|
1103
|
+
;;
|
|
1104
|
+
*) echo "%3" ;;
|
|
1105
|
+
esac
|
|
1106
|
+
exit 0
|
|
1107
|
+
;;
|
|
1108
|
+
set-hook|run-shell|select-layout|set-window-option|select-pane|send-keys|kill-pane|kill-session)
|
|
1109
|
+
exit 0
|
|
1110
|
+
;;
|
|
1111
|
+
*)
|
|
1112
|
+
exit 0
|
|
1113
|
+
;;
|
|
1114
|
+
esac
|
|
1115
|
+
`,
|
|
1116
|
+
binaries: [{ name: 'codex', content: '#!/bin/sh\nexit 0\n' }],
|
|
1117
|
+
}, async ({ tmuxLogPath }) => {
|
|
1118
|
+
delete process.env.TMUX;
|
|
1119
|
+
process.env.TMUX_PANE = '%1';
|
|
1120
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'interactive';
|
|
1121
|
+
process.env.OMX_TEAM_WORKER_CLI = 'codex';
|
|
1122
|
+
process.env.OMX_TEAM_SKIP_READY_WAIT = '1';
|
|
1123
|
+
const events = [];
|
|
1124
|
+
runtime = await withoutTeamWorkerEnv(() => startTeam('team-interactive-cleanup', 'interactive cleanup before worker spawn', 'executor', 1, [{ subject: 's', description: 'd', owner: 'worker-1' }], cwd, {
|
|
1125
|
+
cleanupLaunchOrphanedMcpProcesses: async () => {
|
|
1126
|
+
events.push('cleanup');
|
|
1127
|
+
return { dryRun: false, candidates: [], terminatedCount: 0, forceKilledCount: 0, failedPids: [] };
|
|
1128
|
+
},
|
|
1129
|
+
}));
|
|
1130
|
+
const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
|
|
1131
|
+
assert.match(tmuxLog, /split-window/);
|
|
1132
|
+
assert.deepEqual(events, ['cleanup']);
|
|
1133
|
+
assert.equal(runtime.config.workers[0]?.pane_id, '%2');
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
finally {
|
|
1137
|
+
const runtimeToShutdown = runtime;
|
|
1138
|
+
if (runtimeToShutdown) {
|
|
1139
|
+
await shutdownTeam(runtimeToShutdown.teamName, cwd, { force: true }).catch(() => { });
|
|
1140
|
+
}
|
|
1141
|
+
if (typeof prevTmux === 'string')
|
|
1142
|
+
process.env.TMUX = prevTmux;
|
|
1143
|
+
else
|
|
1144
|
+
delete process.env.TMUX;
|
|
1145
|
+
if (typeof prevTmuxPane === 'string')
|
|
1146
|
+
process.env.TMUX_PANE = prevTmuxPane;
|
|
1147
|
+
else
|
|
1148
|
+
delete process.env.TMUX_PANE;
|
|
1149
|
+
if (typeof prevLaunchMode === 'string')
|
|
1150
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = prevLaunchMode;
|
|
1151
|
+
else
|
|
1152
|
+
delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
1153
|
+
if (typeof prevWorkerCli === 'string')
|
|
1154
|
+
process.env.OMX_TEAM_WORKER_CLI = prevWorkerCli;
|
|
1155
|
+
else
|
|
1156
|
+
delete process.env.OMX_TEAM_WORKER_CLI;
|
|
1157
|
+
if (typeof prevSkipReadyWait === 'string')
|
|
1158
|
+
process.env.OMX_TEAM_SKIP_READY_WAIT = prevSkipReadyWait;
|
|
1159
|
+
else
|
|
1160
|
+
delete process.env.OMX_TEAM_SKIP_READY_WAIT;
|
|
1161
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1162
|
+
}
|
|
1163
|
+
});
|
|
1020
1164
|
it('startTeam captures interactive worker pid from the resolved pane id', async () => {
|
|
1021
1165
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-pane-pid-'));
|
|
1022
1166
|
const prevTmux = process.env.TMUX;
|
|
@@ -1141,11 +1285,11 @@ esac
|
|
|
1141
1285
|
await rm(cwd, { recursive: true, force: true });
|
|
1142
1286
|
}
|
|
1143
1287
|
});
|
|
1144
|
-
it('startTeam saves interactive pane ids before readiness
|
|
1288
|
+
it('startTeam saves interactive pane ids before concurrent readiness attempts', async () => {
|
|
1145
1289
|
const source = await readFile(join(process.cwd(), 'src', 'team', 'runtime.ts'), 'utf-8');
|
|
1146
1290
|
const applyMatch = source.match(/applyCreatedInteractiveSessionToConfig\(\s*config,\s*createdSession,\s*workerPaneIds\s*\);/m);
|
|
1147
1291
|
const saveMatch = source.match(/await saveTeamConfig\(config, leaderCwd\);/m);
|
|
1148
|
-
const readyMatch = source.match(/
|
|
1292
|
+
const readyMatch = source.match(/waitForWorkerReadyAsync\(/m);
|
|
1149
1293
|
const applyIndex = applyMatch?.index ?? -1;
|
|
1150
1294
|
const saveIndex = saveMatch?.index ?? -1;
|
|
1151
1295
|
const readyIndex = readyMatch?.index ?? -1;
|
|
@@ -1155,6 +1299,147 @@ esac
|
|
|
1155
1299
|
assert.equal(applyIndex < saveIndex, true);
|
|
1156
1300
|
assert.equal(saveIndex < readyIndex, true);
|
|
1157
1301
|
});
|
|
1302
|
+
it('startTeam starts worker-2 readiness before delayed worker-1 readiness settles', async () => {
|
|
1303
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-parallel-ready-'));
|
|
1304
|
+
const previousTmux = process.env.TMUX;
|
|
1305
|
+
const previousTmuxPane = process.env.TMUX_PANE;
|
|
1306
|
+
const previousLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
1307
|
+
const previousWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
|
|
1308
|
+
const previousReadyTimeout = process.env.OMX_TEAM_READY_TIMEOUT_MS;
|
|
1309
|
+
const previousStartupEvidenceTimeout = process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
|
|
1310
|
+
const previousStartupDispatchRetries = process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
|
|
1311
|
+
let receiptDeliverer = null;
|
|
1312
|
+
let runtimeTeamName = null;
|
|
1313
|
+
try {
|
|
1314
|
+
await withMockTmuxFixture({
|
|
1315
|
+
dirPrefix: 'omx-runtime-parallel-ready-bin-',
|
|
1316
|
+
tmuxScript: () => `#!/bin/sh
|
|
1317
|
+
set -eu
|
|
1318
|
+
order_file="${cwd}/ready-order.log"
|
|
1319
|
+
case "$1" in
|
|
1320
|
+
-V)
|
|
1321
|
+
echo "tmux 3.4"
|
|
1322
|
+
exit 0
|
|
1323
|
+
;;
|
|
1324
|
+
display-message)
|
|
1325
|
+
case "$*" in
|
|
1326
|
+
*"#{window_width}"*) echo "120" ;;
|
|
1327
|
+
*) echo "leader:0 %1" ;;
|
|
1328
|
+
esac
|
|
1329
|
+
exit 0
|
|
1330
|
+
;;
|
|
1331
|
+
list-panes)
|
|
1332
|
+
case "$*" in
|
|
1333
|
+
*"pane_current_command"*) printf "%%1\tnode\t'codex'\n" ;;
|
|
1334
|
+
*"#{pane_dead} #{pane_pid}"*) echo "0 4242" ;;
|
|
1335
|
+
*"-t %2"*"#{pane_pid}"*) echo "4242" ;;
|
|
1336
|
+
*"-t %3"*"#{pane_pid}"*) echo "4343" ;;
|
|
1337
|
+
*"#{pane_pid}"*) echo "4141" ;;
|
|
1338
|
+
*) exit 0 ;;
|
|
1339
|
+
esac
|
|
1340
|
+
exit 0
|
|
1341
|
+
;;
|
|
1342
|
+
capture-pane)
|
|
1343
|
+
case "$*" in
|
|
1344
|
+
*"-t %2"*)
|
|
1345
|
+
printf '%s\n' w1-ready-start >> "$order_file"
|
|
1346
|
+
sleep 0.4
|
|
1347
|
+
printf '%s\n' w1-ready-done >> "$order_file"
|
|
1348
|
+
printf 'OpenAI Codex\nmodel: test\n› \n'
|
|
1349
|
+
;;
|
|
1350
|
+
*"-t %3"*)
|
|
1351
|
+
printf '%s\n' w2-ready-start >> "$order_file"
|
|
1352
|
+
printf 'OpenAI Codex\nmodel: test\n› \n'
|
|
1353
|
+
;;
|
|
1354
|
+
*)
|
|
1355
|
+
printf 'OpenAI Codex\nmodel: test\n› \n'
|
|
1356
|
+
;;
|
|
1357
|
+
esac
|
|
1358
|
+
exit 0
|
|
1359
|
+
;;
|
|
1360
|
+
split-window)
|
|
1361
|
+
count_file="${cwd}/split-window-count"
|
|
1362
|
+
count=0
|
|
1363
|
+
if [ -f "$count_file" ]; then count=$(cat "$count_file"); fi
|
|
1364
|
+
count=$((count + 1))
|
|
1365
|
+
printf '%s' "$count" > "$count_file"
|
|
1366
|
+
case "$count" in
|
|
1367
|
+
1) echo "%2" ;;
|
|
1368
|
+
2) echo "%3" ;;
|
|
1369
|
+
*) echo "%4" ;;
|
|
1370
|
+
esac
|
|
1371
|
+
exit 0
|
|
1372
|
+
;;
|
|
1373
|
+
set-hook|run-shell|select-layout|set-window-option|select-pane|send-keys|kill-pane|kill-session|resize-pane)
|
|
1374
|
+
exit 0
|
|
1375
|
+
;;
|
|
1376
|
+
*)
|
|
1377
|
+
exit 0
|
|
1378
|
+
;;
|
|
1379
|
+
esac
|
|
1380
|
+
`,
|
|
1381
|
+
binaries: [{ name: 'codex', content: '#!/usr/bin/env node\nprocess.stdin.resume();\n' }],
|
|
1382
|
+
}, async () => {
|
|
1383
|
+
delete process.env.TMUX;
|
|
1384
|
+
process.env.TMUX_PANE = '%1';
|
|
1385
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'interactive';
|
|
1386
|
+
process.env.OMX_TEAM_WORKER_CLI = 'codex';
|
|
1387
|
+
process.env.OMX_TEAM_READY_TIMEOUT_MS = '2000';
|
|
1388
|
+
process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS = '50';
|
|
1389
|
+
process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = '1';
|
|
1390
|
+
receiptDeliverer = setInterval(() => {
|
|
1391
|
+
void (async () => {
|
|
1392
|
+
await markPendingInboxDispatchesDelivered('team-parallel-ready', cwd);
|
|
1393
|
+
})();
|
|
1394
|
+
}, 20);
|
|
1395
|
+
const runtime = await withoutTeamWorkerEnv(() => startTeam('team-parallel-ready', 'worker-2 readiness should not wait for worker-1 readiness settle', 'executor', 2, [
|
|
1396
|
+
{ subject: 'w1', description: 'worker one', owner: 'worker-1' },
|
|
1397
|
+
{ subject: 'w2', description: 'worker two', owner: 'worker-2' },
|
|
1398
|
+
], cwd));
|
|
1399
|
+
runtimeTeamName = runtime.teamName;
|
|
1400
|
+
const order = (await readFile(join(cwd, 'ready-order.log'), 'utf-8')).trim().split('\n');
|
|
1401
|
+
assert.ok(order.includes('w1-ready-start'));
|
|
1402
|
+
assert.ok(order.includes('w2-ready-start'));
|
|
1403
|
+
assert.ok(order.includes('w1-ready-done'));
|
|
1404
|
+
assert.equal(order.indexOf('w2-ready-start') < order.indexOf('w1-ready-done'), true, `expected worker-2 readiness attempt before worker-1 readiness settled, got ${order.join(',')}`);
|
|
1405
|
+
});
|
|
1406
|
+
}
|
|
1407
|
+
finally {
|
|
1408
|
+
if (receiptDeliverer)
|
|
1409
|
+
clearInterval(receiptDeliverer);
|
|
1410
|
+
if (runtimeTeamName)
|
|
1411
|
+
await shutdownTeam(runtimeTeamName, cwd, { force: true }).catch(() => { });
|
|
1412
|
+
if (typeof previousTmux === 'string')
|
|
1413
|
+
process.env.TMUX = previousTmux;
|
|
1414
|
+
else
|
|
1415
|
+
delete process.env.TMUX;
|
|
1416
|
+
if (typeof previousTmuxPane === 'string')
|
|
1417
|
+
process.env.TMUX_PANE = previousTmuxPane;
|
|
1418
|
+
else
|
|
1419
|
+
delete process.env.TMUX_PANE;
|
|
1420
|
+
if (typeof previousLaunchMode === 'string')
|
|
1421
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = previousLaunchMode;
|
|
1422
|
+
else
|
|
1423
|
+
delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
1424
|
+
if (typeof previousWorkerCli === 'string')
|
|
1425
|
+
process.env.OMX_TEAM_WORKER_CLI = previousWorkerCli;
|
|
1426
|
+
else
|
|
1427
|
+
delete process.env.OMX_TEAM_WORKER_CLI;
|
|
1428
|
+
if (typeof previousReadyTimeout === 'string')
|
|
1429
|
+
process.env.OMX_TEAM_READY_TIMEOUT_MS = previousReadyTimeout;
|
|
1430
|
+
else
|
|
1431
|
+
delete process.env.OMX_TEAM_READY_TIMEOUT_MS;
|
|
1432
|
+
if (typeof previousStartupEvidenceTimeout === 'string')
|
|
1433
|
+
process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS = previousStartupEvidenceTimeout;
|
|
1434
|
+
else
|
|
1435
|
+
delete process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
|
|
1436
|
+
if (typeof previousStartupDispatchRetries === 'string')
|
|
1437
|
+
process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = previousStartupDispatchRetries;
|
|
1438
|
+
else
|
|
1439
|
+
delete process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
|
|
1440
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1158
1443
|
it('startTeam records recoverable startup issues per worker instead of failing launch early when panes stay alive', async () => {
|
|
1159
1444
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-no-startup-evidence-'));
|
|
1160
1445
|
const previousTmux = process.env.TMUX;
|
|
@@ -1324,6 +1609,164 @@ process.on('SIGTERM', () => process.exit(0));
|
|
|
1324
1609
|
await rm(cwd, { recursive: true, force: true });
|
|
1325
1610
|
}
|
|
1326
1611
|
});
|
|
1612
|
+
it('startTeam attempts worker-2 before rejecting lowest-index unrecoverable startup failure', async () => {
|
|
1613
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-parallel-dead-pane-'));
|
|
1614
|
+
const previousTmux = process.env.TMUX;
|
|
1615
|
+
const previousTmuxPane = process.env.TMUX_PANE;
|
|
1616
|
+
const previousLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
1617
|
+
const previousWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
|
|
1618
|
+
const previousReadyTimeout = process.env.OMX_TEAM_READY_TIMEOUT_MS;
|
|
1619
|
+
const previousStartupEvidenceTimeout = process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
|
|
1620
|
+
const previousStartupDispatchRetries = process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
|
|
1621
|
+
let receiptFailer = null;
|
|
1622
|
+
try {
|
|
1623
|
+
await withMockTmuxFixture({
|
|
1624
|
+
dirPrefix: 'omx-runtime-parallel-dead-pane-bin-',
|
|
1625
|
+
tmuxScript: () => `#!/bin/sh
|
|
1626
|
+
set -eu
|
|
1627
|
+
order_file="${cwd}/dead-pane-order.log"
|
|
1628
|
+
case "$1" in
|
|
1629
|
+
-V)
|
|
1630
|
+
echo "tmux 3.4"
|
|
1631
|
+
exit 0
|
|
1632
|
+
;;
|
|
1633
|
+
display-message)
|
|
1634
|
+
case "$*" in
|
|
1635
|
+
*"#{window_width}"*) echo "120" ;;
|
|
1636
|
+
*) echo "leader:0 %1" ;;
|
|
1637
|
+
esac
|
|
1638
|
+
exit 0
|
|
1639
|
+
;;
|
|
1640
|
+
list-panes)
|
|
1641
|
+
case "$*" in
|
|
1642
|
+
*"pane_current_command"*) printf "%%1\tnode\t'codex'\n" ;;
|
|
1643
|
+
*"-t %2"*"#{pane_dead} #{pane_pid}"*) echo "1 4242" ;;
|
|
1644
|
+
*"-t %3"*"#{pane_dead} #{pane_pid}"*) echo "0 4343" ;;
|
|
1645
|
+
*"#{pane_dead} #{pane_pid}"*) echo "0 4141" ;;
|
|
1646
|
+
*"-t %2"*"#{pane_pid}"*) echo "4242" ;;
|
|
1647
|
+
*"-t %3"*"#{pane_pid}"*) echo "4343" ;;
|
|
1648
|
+
*"#{pane_pid}"*) echo "4141" ;;
|
|
1649
|
+
*) exit 0 ;;
|
|
1650
|
+
esac
|
|
1651
|
+
exit 0
|
|
1652
|
+
;;
|
|
1653
|
+
capture-pane)
|
|
1654
|
+
case "$*" in
|
|
1655
|
+
*"-t %2"*) printf '%s\n' w1-ready-start >> "$order_file" ;;
|
|
1656
|
+
*"-t %3"*) printf '%s\n' w2-ready-start >> "$order_file"; printf 'OpenAI Codex\nmodel: test\n› \n' ;;
|
|
1657
|
+
*) printf 'OpenAI Codex\nmodel: test\n› \n' ;;
|
|
1658
|
+
esac
|
|
1659
|
+
exit 0
|
|
1660
|
+
;;
|
|
1661
|
+
split-window)
|
|
1662
|
+
count_file="${cwd}/split-window-count"
|
|
1663
|
+
count=0
|
|
1664
|
+
if [ -f "$count_file" ]; then count=$(cat "$count_file"); fi
|
|
1665
|
+
count=$((count + 1))
|
|
1666
|
+
printf '%s' "$count" > "$count_file"
|
|
1667
|
+
case "$count" in
|
|
1668
|
+
1) echo "%2" ;;
|
|
1669
|
+
2) echo "%3" ;;
|
|
1670
|
+
*) echo "%4" ;;
|
|
1671
|
+
esac
|
|
1672
|
+
exit 0
|
|
1673
|
+
;;
|
|
1674
|
+
set-hook|run-shell|select-layout|set-window-option|select-pane|send-keys|kill-pane|kill-session|resize-pane)
|
|
1675
|
+
exit 0
|
|
1676
|
+
;;
|
|
1677
|
+
*)
|
|
1678
|
+
exit 0
|
|
1679
|
+
;;
|
|
1680
|
+
esac
|
|
1681
|
+
`,
|
|
1682
|
+
binaries: [{ name: 'codex', content: '#!/usr/bin/env node\nprocess.stdin.resume();\n' }],
|
|
1683
|
+
}, async () => {
|
|
1684
|
+
delete process.env.TMUX;
|
|
1685
|
+
process.env.TMUX_PANE = '%1';
|
|
1686
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'interactive';
|
|
1687
|
+
process.env.OMX_TEAM_WORKER_CLI = 'codex';
|
|
1688
|
+
process.env.OMX_TEAM_READY_TIMEOUT_MS = '300';
|
|
1689
|
+
process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS = '50';
|
|
1690
|
+
process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = '1';
|
|
1691
|
+
receiptFailer = setInterval(() => {
|
|
1692
|
+
void (async () => {
|
|
1693
|
+
const requests = await listDispatchRequests('team-parallel-dead-pane', cwd, { kind: 'inbox' }).catch(() => []);
|
|
1694
|
+
for (const request of requests) {
|
|
1695
|
+
if (request.status !== 'pending')
|
|
1696
|
+
continue;
|
|
1697
|
+
await transitionDispatchRequest('team-parallel-dead-pane', request.request_id, 'pending', 'failed', { last_reason: 'test_failed_receipt' }, cwd).catch(() => { });
|
|
1698
|
+
}
|
|
1699
|
+
})();
|
|
1700
|
+
}, 20);
|
|
1701
|
+
await assert.rejects(() => withoutTeamWorkerEnv(() => startTeam('team-parallel-dead-pane', 'worker-2 should be attempted despite worker-1 fatal readiness failure', 'executor', 2, [
|
|
1702
|
+
{ subject: 'w1', description: 'worker one', owner: 'worker-1' },
|
|
1703
|
+
{ subject: 'w2', description: 'worker two', owner: 'worker-2' },
|
|
1704
|
+
], cwd)), /Worker worker-1 did not become ready/);
|
|
1705
|
+
const order = (await readFile(join(cwd, 'dead-pane-order.log'), 'utf-8')).trim().split('\n');
|
|
1706
|
+
assert.ok(order.includes('w1-ready-start'));
|
|
1707
|
+
assert.ok(order.includes('w2-ready-start'));
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
finally {
|
|
1711
|
+
if (receiptFailer)
|
|
1712
|
+
clearInterval(receiptFailer);
|
|
1713
|
+
if (typeof previousTmux === 'string')
|
|
1714
|
+
process.env.TMUX = previousTmux;
|
|
1715
|
+
else
|
|
1716
|
+
delete process.env.TMUX;
|
|
1717
|
+
if (typeof previousTmuxPane === 'string')
|
|
1718
|
+
process.env.TMUX_PANE = previousTmuxPane;
|
|
1719
|
+
else
|
|
1720
|
+
delete process.env.TMUX_PANE;
|
|
1721
|
+
if (typeof previousLaunchMode === 'string')
|
|
1722
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = previousLaunchMode;
|
|
1723
|
+
else
|
|
1724
|
+
delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
1725
|
+
if (typeof previousWorkerCli === 'string')
|
|
1726
|
+
process.env.OMX_TEAM_WORKER_CLI = previousWorkerCli;
|
|
1727
|
+
else
|
|
1728
|
+
delete process.env.OMX_TEAM_WORKER_CLI;
|
|
1729
|
+
if (typeof previousReadyTimeout === 'string')
|
|
1730
|
+
process.env.OMX_TEAM_READY_TIMEOUT_MS = previousReadyTimeout;
|
|
1731
|
+
else
|
|
1732
|
+
delete process.env.OMX_TEAM_READY_TIMEOUT_MS;
|
|
1733
|
+
if (typeof previousStartupEvidenceTimeout === 'string')
|
|
1734
|
+
process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS = previousStartupEvidenceTimeout;
|
|
1735
|
+
else
|
|
1736
|
+
delete process.env.OMX_TEAM_STARTUP_EVIDENCE_TIMEOUT_MS;
|
|
1737
|
+
if (typeof previousStartupDispatchRetries === 'string')
|
|
1738
|
+
process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES = previousStartupDispatchRetries;
|
|
1739
|
+
else
|
|
1740
|
+
delete process.env.OMX_TEAM_STARTUP_DISPATCH_RETRIES;
|
|
1741
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1742
|
+
}
|
|
1743
|
+
});
|
|
1744
|
+
it('settleStartupAttemptResults waits for sibling startup attempt to settle after worker startup throw', async () => {
|
|
1745
|
+
let worker2Settled = false;
|
|
1746
|
+
const startupAttemptResults = await settleStartupAttemptResults([
|
|
1747
|
+
{
|
|
1748
|
+
workerIndex: 1,
|
|
1749
|
+
workerName: 'worker-1',
|
|
1750
|
+
attempt: Promise.reject(new Error('test_startup_attempt_throw:worker-1')),
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
workerIndex: 2,
|
|
1754
|
+
workerName: 'worker-2',
|
|
1755
|
+
attempt: new Promise((resolve) => {
|
|
1756
|
+
setTimeout(() => {
|
|
1757
|
+
worker2Settled = true;
|
|
1758
|
+
resolve({ ok: true, workerIndex: 2, workerName: 'worker-2' });
|
|
1759
|
+
}, 100);
|
|
1760
|
+
}),
|
|
1761
|
+
},
|
|
1762
|
+
]);
|
|
1763
|
+
assert.equal(worker2Settled, true, 'worker-2 startup attempt should settle before results return');
|
|
1764
|
+
const firstStartupError = startupAttemptResults
|
|
1765
|
+
.filter((result) => !result.ok)
|
|
1766
|
+
.sort((a, b) => a.workerIndex - b.workerIndex)[0];
|
|
1767
|
+
assert.equal(firstStartupError?.workerName, 'worker-1');
|
|
1768
|
+
assert.match(String(firstStartupError?.error), /test_startup_attempt_throw:worker-1/);
|
|
1769
|
+
});
|
|
1327
1770
|
it('startTeam still fails startup when the worker pane is dead/unrecoverable', async () => {
|
|
1328
1771
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-dead-startup-pane-'));
|
|
1329
1772
|
const previousTmux = process.env.TMUX;
|
|
@@ -1651,6 +2094,78 @@ process.on('SIGTERM', () => process.exit(0));
|
|
|
1651
2094
|
await rm(repo, { recursive: true, force: true });
|
|
1652
2095
|
}
|
|
1653
2096
|
});
|
|
2097
|
+
it('startTeam runs worker MCP orphan cleanup before prompt worker spawn', async () => {
|
|
2098
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-prompt-mcp-cleanup-'));
|
|
2099
|
+
const binDir = join(cwd, 'bin');
|
|
2100
|
+
const fakeCodexPath = join(binDir, 'codex');
|
|
2101
|
+
const capturePath = join(cwd, 'prompt-cleanup-order.jsonl');
|
|
2102
|
+
await mkdir(binDir, { recursive: true });
|
|
2103
|
+
await writeFakePromptWorkerBinary(fakeCodexPath, `const capturePath = process.env.OMX_PROMPT_CLEANUP_CAPTURE_PATH;
|
|
2104
|
+
if (capturePath) require('fs').appendFileSync(capturePath, 'spawn' + String.fromCharCode(10));
|
|
2105
|
+
setTimeout(() => {}, 5000);`);
|
|
2106
|
+
const prevPath = process.env.PATH;
|
|
2107
|
+
const prevTmux = process.env.TMUX;
|
|
2108
|
+
const prevLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
2109
|
+
const prevWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
|
|
2110
|
+
const prevLaunchArgs = process.env.OMX_TEAM_WORKER_LAUNCH_ARGS;
|
|
2111
|
+
const prevCapture = process.env.OMX_PROMPT_CLEANUP_CAPTURE_PATH;
|
|
2112
|
+
const prevAllowNonTty = process.env.OMX_TEST_ALLOW_NONTTY_CODEX_PROMPT;
|
|
2113
|
+
let runtime = null;
|
|
2114
|
+
try {
|
|
2115
|
+
process.env.PATH = `${binDir}:${prevPath ?? ''}`;
|
|
2116
|
+
delete process.env.TMUX;
|
|
2117
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'prompt';
|
|
2118
|
+
process.env.OMX_TEAM_WORKER_CLI = 'codex';
|
|
2119
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_ARGS = `--config ${JSON.stringify(`model_instructions_file=\"${join(cwd, 'AGENTS.md')}\"`)}`;
|
|
2120
|
+
process.env.OMX_PROMPT_CLEANUP_CAPTURE_PATH = capturePath;
|
|
2121
|
+
process.env.OMX_TEST_ALLOW_NONTTY_CODEX_PROMPT = '1';
|
|
2122
|
+
const started = await withoutTeamWorkerEnv(() => startTeam('team-prompt-cleanup', 'prompt cleanup before worker spawn', 'executor', 1, [{ subject: 's', description: 'd', owner: 'worker-1' }], cwd, {
|
|
2123
|
+
cleanupLaunchOrphanedMcpProcesses: async () => {
|
|
2124
|
+
await writeFile(capturePath, 'cleanup\n', 'utf-8');
|
|
2125
|
+
return { dryRun: false, candidates: [], terminatedCount: 0, forceKilledCount: 0, failedPids: [] };
|
|
2126
|
+
},
|
|
2127
|
+
}));
|
|
2128
|
+
runtime = started;
|
|
2129
|
+
const order = await waitForFileText(capturePath, (content) => /spawn/.test(content));
|
|
2130
|
+
assert.equal(order, 'cleanup\nspawn\n');
|
|
2131
|
+
await shutdownTeam(runtime.teamName, cwd, { force: true });
|
|
2132
|
+
runtime = null;
|
|
2133
|
+
}
|
|
2134
|
+
finally {
|
|
2135
|
+
if (runtime) {
|
|
2136
|
+
await shutdownTeam(runtime.teamName, cwd, { force: true }).catch(() => { });
|
|
2137
|
+
}
|
|
2138
|
+
if (typeof prevPath === 'string')
|
|
2139
|
+
process.env.PATH = prevPath;
|
|
2140
|
+
else
|
|
2141
|
+
delete process.env.PATH;
|
|
2142
|
+
if (typeof prevTmux === 'string')
|
|
2143
|
+
process.env.TMUX = prevTmux;
|
|
2144
|
+
else
|
|
2145
|
+
delete process.env.TMUX;
|
|
2146
|
+
if (typeof prevLaunchMode === 'string')
|
|
2147
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = prevLaunchMode;
|
|
2148
|
+
else
|
|
2149
|
+
delete process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
2150
|
+
if (typeof prevWorkerCli === 'string')
|
|
2151
|
+
process.env.OMX_TEAM_WORKER_CLI = prevWorkerCli;
|
|
2152
|
+
else
|
|
2153
|
+
delete process.env.OMX_TEAM_WORKER_CLI;
|
|
2154
|
+
if (typeof prevLaunchArgs === 'string')
|
|
2155
|
+
process.env.OMX_TEAM_WORKER_LAUNCH_ARGS = prevLaunchArgs;
|
|
2156
|
+
else
|
|
2157
|
+
delete process.env.OMX_TEAM_WORKER_LAUNCH_ARGS;
|
|
2158
|
+
if (typeof prevCapture === 'string')
|
|
2159
|
+
process.env.OMX_PROMPT_CLEANUP_CAPTURE_PATH = prevCapture;
|
|
2160
|
+
else
|
|
2161
|
+
delete process.env.OMX_PROMPT_CLEANUP_CAPTURE_PATH;
|
|
2162
|
+
if (typeof prevAllowNonTty === 'string')
|
|
2163
|
+
process.env.OMX_TEST_ALLOW_NONTTY_CODEX_PROMPT = prevAllowNonTty;
|
|
2164
|
+
else
|
|
2165
|
+
delete process.env.OMX_TEST_ALLOW_NONTTY_CODEX_PROMPT;
|
|
2166
|
+
await rm(cwd, { recursive: true, force: true });
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
1654
2169
|
it('startTeam launches gemini workers with startup prompt and no default model passthrough', async () => {
|
|
1655
2170
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-gemini-'));
|
|
1656
2171
|
const binDir = join(cwd, 'bin');
|
|
@@ -1801,11 +2316,13 @@ process.on('SIGTERM', () => process.exit(0));
|
|
|
1801
2316
|
const prevLaunchMode = process.env.OMX_TEAM_WORKER_LAUNCH_MODE;
|
|
1802
2317
|
const prevWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
|
|
1803
2318
|
const prevCaptureDir = process.env.OMX_ARGV_CAPTURE_DIR;
|
|
2319
|
+
const prevStandardModel = process.env.OMX_DEFAULT_STANDARD_MODEL;
|
|
1804
2320
|
process.env.PATH = `${binDir}:${prevPath ?? ''}`;
|
|
1805
2321
|
delete process.env.TMUX;
|
|
1806
2322
|
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'prompt';
|
|
1807
2323
|
process.env.OMX_TEAM_WORKER_CLI = 'codex';
|
|
1808
2324
|
process.env.OMX_ARGV_CAPTURE_DIR = captureDir;
|
|
2325
|
+
delete process.env.OMX_DEFAULT_STANDARD_MODEL;
|
|
1809
2326
|
let runtime = null;
|
|
1810
2327
|
try {
|
|
1811
2328
|
runtime = await withMockPromptModeCodexAllowed(() => withoutTeamWorkerEnv(() => startTeam('team-role-routing', 'heuristic routing handoff', 'executor', 2, [
|
|
@@ -1829,8 +2346,8 @@ process.on('SIGTERM', () => process.exit(0));
|
|
|
1829
2346
|
assert.doesNotMatch(worker1Instructions, /exact gpt-5\.4-mini model/);
|
|
1830
2347
|
assert.match(worker2Instructions, /You are operating as the \*\*writer\*\* role/);
|
|
1831
2348
|
assert.match(worker2Instructions, /You are Writer\./);
|
|
1832
|
-
assert.
|
|
1833
|
-
assert.match(worker2Instructions, /
|
|
2349
|
+
assert.doesNotMatch(worker2Instructions, /exact gpt-5\.4-mini model/);
|
|
2350
|
+
assert.match(worker2Instructions, /resolved_model: gpt-5\.5/);
|
|
1834
2351
|
let worker1Args = null;
|
|
1835
2352
|
let worker2Args = null;
|
|
1836
2353
|
for (let attempt = 0; attempt < 50; attempt += 1) {
|
|
@@ -1852,7 +2369,7 @@ process.on('SIGTERM', () => process.exit(0));
|
|
|
1852
2369
|
assert.match(worker1Joined, /--model gpt-5\.5/);
|
|
1853
2370
|
assert.match(worker2Joined, /model_reasoning_effort="high"/);
|
|
1854
2371
|
assert.match(worker2Joined, /model_instructions_file=.*worker-2\/AGENTS\.md/);
|
|
1855
|
-
assert.match(worker2Joined, /--model gpt-5\.
|
|
2372
|
+
assert.match(worker2Joined, /--model gpt-5\.5/);
|
|
1856
2373
|
await shutdownTeam(runtime.teamName, cwd, { force: true });
|
|
1857
2374
|
runtime = null;
|
|
1858
2375
|
}
|
|
@@ -1880,6 +2397,10 @@ process.on('SIGTERM', () => process.exit(0));
|
|
|
1880
2397
|
process.env.OMX_ARGV_CAPTURE_DIR = prevCaptureDir;
|
|
1881
2398
|
else
|
|
1882
2399
|
delete process.env.OMX_ARGV_CAPTURE_DIR;
|
|
2400
|
+
if (typeof prevStandardModel === 'string')
|
|
2401
|
+
process.env.OMX_DEFAULT_STANDARD_MODEL = prevStandardModel;
|
|
2402
|
+
else
|
|
2403
|
+
delete process.env.OMX_DEFAULT_STANDARD_MODEL;
|
|
1883
2404
|
await rm(cwd, { recursive: true, force: true });
|
|
1884
2405
|
}
|
|
1885
2406
|
});
|
|
@@ -1909,11 +2430,13 @@ process.on('SIGTERM', () => process.exit(0));
|
|
|
1909
2430
|
const prevWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
|
|
1910
2431
|
const prevCaptureDir = process.env.OMX_ARGV_CAPTURE_DIR;
|
|
1911
2432
|
const prevLaunchArgs = process.env.OMX_TEAM_WORKER_LAUNCH_ARGS;
|
|
2433
|
+
const prevStandardModel = process.env.OMX_DEFAULT_STANDARD_MODEL;
|
|
1912
2434
|
process.env.PATH = `${binDir}:${prevPath ?? ''}`;
|
|
1913
2435
|
delete process.env.TMUX;
|
|
1914
2436
|
process.env.OMX_TEAM_WORKER_LAUNCH_MODE = 'prompt';
|
|
1915
2437
|
process.env.OMX_TEAM_WORKER_CLI = 'codex';
|
|
1916
2438
|
process.env.OMX_ARGV_CAPTURE_DIR = captureDir;
|
|
2439
|
+
delete process.env.OMX_DEFAULT_STANDARD_MODEL;
|
|
1917
2440
|
process.env.OMX_TEAM_WORKER_LAUNCH_ARGS = '--model gpt-5.4-mini-tuned';
|
|
1918
2441
|
let runtime = null;
|
|
1919
2442
|
try {
|
|
@@ -1965,6 +2488,10 @@ process.on('SIGTERM', () => process.exit(0));
|
|
|
1965
2488
|
process.env.OMX_ARGV_CAPTURE_DIR = prevCaptureDir;
|
|
1966
2489
|
else
|
|
1967
2490
|
delete process.env.OMX_ARGV_CAPTURE_DIR;
|
|
2491
|
+
if (typeof prevStandardModel === 'string')
|
|
2492
|
+
process.env.OMX_DEFAULT_STANDARD_MODEL = prevStandardModel;
|
|
2493
|
+
else
|
|
2494
|
+
delete process.env.OMX_DEFAULT_STANDARD_MODEL;
|
|
1968
2495
|
if (typeof prevLaunchArgs === 'string')
|
|
1969
2496
|
process.env.OMX_TEAM_WORKER_LAUNCH_ARGS = prevLaunchArgs;
|
|
1970
2497
|
else
|
|
@@ -4046,8 +4573,19 @@ esac
|
|
|
4046
4573
|
config.workers[0].pid = sleeperPid;
|
|
4047
4574
|
config.workers[0].pane_id = null;
|
|
4048
4575
|
await writeFile(configPath, JSON.stringify(config, null, 2));
|
|
4576
|
+
const manifestPath = join(cwd, '.omx', 'state', 'team', 'team-prompt-resume', 'manifest.v2.json');
|
|
4577
|
+
const manifest = JSON.parse(await readFile(manifestPath, 'utf-8'));
|
|
4578
|
+
manifest.policy.worker_launch_mode = 'prompt';
|
|
4579
|
+
manifest.tmux_session = 'prompt-team-prompt-resume';
|
|
4580
|
+
manifest.leader_pane_id = null;
|
|
4581
|
+
manifest.hud_pane_id = null;
|
|
4582
|
+
manifest.workers[0].pid = sleeperPid;
|
|
4583
|
+
manifest.workers[0].pane_id = null;
|
|
4584
|
+
await writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
4049
4585
|
const runtime = await resumeTeam('team-prompt-resume', cwd);
|
|
4050
4586
|
assert.equal(runtime, null);
|
|
4587
|
+
const events = await readTeamEvents('team-prompt-resume', cwd);
|
|
4588
|
+
assert.ok(events.some((event) => event.reason === `prompt_resume_unavailable:missing_handle:worker-1:${sleeperPid}`), 'resumeTeam should persist an explicit missing-handle diagnostic event');
|
|
4051
4589
|
}
|
|
4052
4590
|
finally {
|
|
4053
4591
|
if (sleeperPid > 0) {
|
|
@@ -4148,6 +4686,119 @@ esac
|
|
|
4148
4686
|
await rm(cwd, { recursive: true, force: true });
|
|
4149
4687
|
}
|
|
4150
4688
|
});
|
|
4689
|
+
it('startTeam persists synthesized delegation plans for broad tasks', async () => {
|
|
4690
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
|
|
4691
|
+
const binDir = join(cwd, 'bin');
|
|
4692
|
+
const fakeCodexPath = join(binDir, 'codex');
|
|
4693
|
+
await mkdir(binDir, { recursive: true });
|
|
4694
|
+
await writeFakePromptWorkerBinary(fakeCodexPath, `setTimeout(() => {}, 5000);`);
|
|
4695
|
+
let runtime = null;
|
|
4696
|
+
try {
|
|
4697
|
+
runtime = await withPromptModeCodexEnv(binDir, {}, () => withoutTeamWorkerEnv(() => startTeam('team-delegation-persist', 'delegation persistence test', 'executor', 1, [{ subject: 'Investigate runtime assignment', description: 'Search runtime and debug assignTask behavior' }], cwd)));
|
|
4698
|
+
const task = await readTask('team-delegation-persist', '1', cwd);
|
|
4699
|
+
assert.equal(task?.delegation?.mode, 'auto');
|
|
4700
|
+
assert.equal(task?.delegation?.child_model, 'gpt-5.4-mini');
|
|
4701
|
+
assert.equal(task?.delegation?.required_parallel_probe, true);
|
|
4702
|
+
}
|
|
4703
|
+
finally {
|
|
4704
|
+
if (runtime) {
|
|
4705
|
+
await shutdownTeam(runtime.teamName, cwd, { force: true }).catch(() => { });
|
|
4706
|
+
}
|
|
4707
|
+
await rm(cwd, { recursive: true, force: true });
|
|
4708
|
+
}
|
|
4709
|
+
});
|
|
4710
|
+
it('startTeam remaps repo-aware DAG dependencies after concrete task IDs are created', async () => {
|
|
4711
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
|
|
4712
|
+
const binDir = join(cwd, 'bin');
|
|
4713
|
+
const fakeCodexPath = join(binDir, 'codex');
|
|
4714
|
+
await mkdir(binDir, { recursive: true });
|
|
4715
|
+
await writeFakePromptWorkerBinary(fakeCodexPath, `setTimeout(() => {}, 5000);`);
|
|
4716
|
+
let runtime = null;
|
|
4717
|
+
try {
|
|
4718
|
+
runtime = await withPromptModeCodexEnv(binDir, {}, () => withoutTeamWorkerEnv(() => startTeam('team-dag-remap', 'repo-aware DAG remap test', 'executor', 2, [
|
|
4719
|
+
{
|
|
4720
|
+
subject: 'Implement runtime',
|
|
4721
|
+
description: 'Change runtime',
|
|
4722
|
+
owner: 'worker-1',
|
|
4723
|
+
role: 'executor',
|
|
4724
|
+
symbolic_id: 'impl',
|
|
4725
|
+
symbolic_depends_on: [],
|
|
4726
|
+
lane: 'implementation',
|
|
4727
|
+
filePaths: ['src/team/runtime.ts'],
|
|
4728
|
+
allocation_reason: 'balances current load',
|
|
4729
|
+
},
|
|
4730
|
+
{
|
|
4731
|
+
subject: 'Verify runtime',
|
|
4732
|
+
description: 'Test runtime',
|
|
4733
|
+
owner: 'worker-2',
|
|
4734
|
+
role: 'test-engineer',
|
|
4735
|
+
symbolic_id: 'verify',
|
|
4736
|
+
symbolic_depends_on: ['impl'],
|
|
4737
|
+
lane: 'verification',
|
|
4738
|
+
allocation_reason: 'keeps blocked work on a lighter lane',
|
|
4739
|
+
},
|
|
4740
|
+
], cwd, {
|
|
4741
|
+
decompositionMetadata: {
|
|
4742
|
+
decomposition_source: 'dag_sidecar',
|
|
4743
|
+
worker_count_requested: 2,
|
|
4744
|
+
worker_count_effective: 2,
|
|
4745
|
+
worker_count_source: 'plan-suggested',
|
|
4746
|
+
ready_lane_count: 1,
|
|
4747
|
+
useful_lane_count: 2,
|
|
4748
|
+
allocation_reasons: {
|
|
4749
|
+
impl: 'balances current load',
|
|
4750
|
+
verify: 'keeps blocked work on a lighter lane',
|
|
4751
|
+
},
|
|
4752
|
+
node_dependencies: {
|
|
4753
|
+
impl: [],
|
|
4754
|
+
verify: ['impl'],
|
|
4755
|
+
},
|
|
4756
|
+
},
|
|
4757
|
+
})));
|
|
4758
|
+
const first = await readTask('team-dag-remap', '1', cwd);
|
|
4759
|
+
const second = await readTask('team-dag-remap', '2', cwd);
|
|
4760
|
+
assert.deepEqual(first?.depends_on, []);
|
|
4761
|
+
assert.deepEqual(first?.blocked_by, undefined);
|
|
4762
|
+
assert.deepEqual(second?.depends_on, ['1']);
|
|
4763
|
+
assert.deepEqual(second?.blocked_by, ['1']);
|
|
4764
|
+
const report = JSON.parse(await readFile(join(cwd, '.omx', 'state', 'team', 'team-dag-remap', 'decomposition-report.json'), 'utf-8'));
|
|
4765
|
+
assert.deepEqual(report.node_id_to_task_id, { impl: '1', verify: '2' });
|
|
4766
|
+
assert.deepEqual(report.task_hints?.['2']?.depends_on, ['1']);
|
|
4767
|
+
assert.deepEqual(report.task_hints?.['2']?.symbolic_depends_on, ['impl']);
|
|
4768
|
+
const inbox = await readFile(join(cwd, '.omx', 'state', 'team', 'team-dag-remap', 'workers', 'worker-2', 'inbox.md'), 'utf-8');
|
|
4769
|
+
assert.match(inbox, /Blocked by: 1/);
|
|
4770
|
+
assert.doesNotMatch(inbox, /Blocked by: impl/);
|
|
4771
|
+
assert.doesNotMatch(inbox, /Depends on: impl/);
|
|
4772
|
+
}
|
|
4773
|
+
finally {
|
|
4774
|
+
if (runtime) {
|
|
4775
|
+
await shutdownTeam(runtime.teamName, cwd, { force: true }).catch(() => { });
|
|
4776
|
+
}
|
|
4777
|
+
await rm(cwd, { recursive: true, force: true });
|
|
4778
|
+
}
|
|
4779
|
+
});
|
|
4780
|
+
it('assignTask synthesizes delegation before follow-up dispatch rollback', async () => {
|
|
4781
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-'));
|
|
4782
|
+
try {
|
|
4783
|
+
await initTeamState('team-assign-delegation', 'assignment delegation test', 'executor', 1, cwd);
|
|
4784
|
+
const config = await readTeamConfig('team-assign-delegation', cwd);
|
|
4785
|
+
assert.ok(config);
|
|
4786
|
+
config.worker_launch_mode = 'prompt';
|
|
4787
|
+
await saveTeamConfig(config, cwd);
|
|
4788
|
+
const task = await createTask('team-assign-delegation', { subject: 'Investigate follow-up assignment', description: 'Search repo and debug follow-up assignment behavior', status: 'pending' }, cwd);
|
|
4789
|
+
await writeWorkerInbox('team-assign-delegation', 'worker-1', 'existing inbox', cwd);
|
|
4790
|
+
await assert.rejects(() => assignTask('team-assign-delegation', 'worker-1', task.id, cwd), /worker_notify_failed/);
|
|
4791
|
+
const reread = await readTask('team-assign-delegation', task.id, cwd);
|
|
4792
|
+
assert.equal(reread?.delegation?.mode, 'auto');
|
|
4793
|
+
assert.equal(reread?.delegation?.child_model, 'gpt-5.4-mini');
|
|
4794
|
+
const inbox = await readFile(join(cwd, '.omx', 'state', 'team', 'team-assign-delegation', 'workers', 'worker-1', 'inbox.md'), 'utf-8');
|
|
4795
|
+
assert.match(inbox, /Assignment Cancelled/);
|
|
4796
|
+
assert.match(inbox, /worker_notify_failed/);
|
|
4797
|
+
}
|
|
4798
|
+
finally {
|
|
4799
|
+
await rm(cwd, { recursive: true, force: true });
|
|
4800
|
+
}
|
|
4801
|
+
});
|
|
4151
4802
|
it('monitorTeam does not re-notify already-notified mailbox messages (issue #116)', async () => {
|
|
4152
4803
|
// Regression: deliverPendingMailboxMessages used to re-notify every 15 s via shouldRetry.
|
|
4153
4804
|
// After the fix it must NOT re-notify messages that already have notified_at set.
|
|
@@ -4498,7 +5149,7 @@ esac
|
|
|
4498
5149
|
await rm(cwd, { recursive: true, force: true });
|
|
4499
5150
|
}
|
|
4500
5151
|
});
|
|
4501
|
-
it('sendWorkerMessage transport_direct
|
|
5152
|
+
it('sendWorkerMessage transport_direct fails fast for leader-fixed when leader_pane_id missing', async () => {
|
|
4502
5153
|
const cwd = await mkdtemp(join(tmpdir(), 'omx-runtime-leader-direct-'));
|
|
4503
5154
|
try {
|
|
4504
5155
|
await initTeamState('team-leader-direct', 'leader direct transport test', 'executor', 1, cwd);
|
|
@@ -4512,14 +5163,23 @@ esac
|
|
|
4512
5163
|
const manifest = JSON.parse(await readFile(manifestPath, 'utf-8'));
|
|
4513
5164
|
manifest.policy = { ...(manifest.policy || {}), dispatch_mode: 'transport_direct' };
|
|
4514
5165
|
await writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
4515
|
-
await sendWorkerMessage('team-leader-direct', 'worker-1', 'leader-fixed', 'hello leader direct', cwd);
|
|
5166
|
+
await assert.rejects(sendWorkerMessage('team-leader-direct', 'worker-1', 'leader-fixed', 'hello leader direct', cwd), /mailbox_notify_failed:leader_pane_missing_transport_direct_failed/);
|
|
4516
5167
|
const mailbox = await listMailboxMessages('team-leader-direct', 'leader-fixed', cwd);
|
|
4517
5168
|
assert.ok(mailbox.length >= 1, `expected at least 1 mailbox message, got ${mailbox.length}`);
|
|
4518
5169
|
const requests = await listDispatchRequests('team-leader-direct', cwd, { kind: 'mailbox', to_worker: 'leader-fixed' });
|
|
4519
5170
|
assert.ok(requests.length >= 1, `expected at least 1 leader-fixed dispatch request, got ${requests.length}`);
|
|
4520
5171
|
const latest = requests[requests.length - 1];
|
|
4521
|
-
assert.equal(latest?.status, '
|
|
4522
|
-
assert.equal(latest?.last_reason, '
|
|
5172
|
+
assert.equal(latest?.status, 'failed');
|
|
5173
|
+
assert.equal(latest?.last_reason, 'leader_pane_missing_transport_direct_failed');
|
|
5174
|
+
assert.ok(latest?.failed_at, 'missing leader pane should fail fast with failed_at evidence');
|
|
5175
|
+
const deliveryLog = await readTeamDeliveryLog(cwd);
|
|
5176
|
+
const runtimeEntries = deliveryLog.filter((entry) => entry.event === 'dispatch_result'
|
|
5177
|
+
&& entry.source === 'team.runtime'
|
|
5178
|
+
&& entry.to_worker === 'leader-fixed'
|
|
5179
|
+
&& entry.transport === 'mailbox'
|
|
5180
|
+
&& entry.result === 'failed'
|
|
5181
|
+
&& entry.reason === 'leader_pane_missing_transport_direct_failed');
|
|
5182
|
+
assert.equal(runtimeEntries.length, 1, 'leader direct missing-pane failure should emit exactly one runtime dispatch_result entry');
|
|
4523
5183
|
}
|
|
4524
5184
|
finally {
|
|
4525
5185
|
await rm(cwd, { recursive: true, force: true });
|