oh-my-codex 0.17.3 → 0.18.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/Cargo.lock +13 -5
- package/Cargo.toml +2 -1
- package/README.md +44 -19
- package/crates/omx-api/Cargo.toml +19 -0
- package/crates/omx-api/src/lib.rs +2997 -0
- package/crates/omx-api/src/main.rs +10 -0
- package/crates/omx-api/tests/cli.rs +558 -0
- package/crates/omx-explore/src/main.rs +4 -0
- package/crates/omx-sparkshell/src/codex_bridge.rs +437 -123
- package/crates/omx-sparkshell/src/exec.rs +127 -1
- package/crates/omx-sparkshell/src/main.rs +829 -30
- package/crates/omx-sparkshell/src/prompt.rs +25 -3
- package/crates/omx-sparkshell/src/redaction.rs +241 -0
- package/crates/omx-sparkshell/tests/execution.rs +702 -237
- package/dist/cli/__tests__/api.test.d.ts +2 -0
- package/dist/cli/__tests__/api.test.d.ts.map +1 -0
- package/dist/cli/__tests__/api.test.js +175 -0
- package/dist/cli/__tests__/api.test.js.map +1 -0
- package/dist/cli/__tests__/ask.test.js +72 -5
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-goal.test.js +14 -1
- package/dist/cli/__tests__/autoresearch-goal.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +15 -7
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +76 -3
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +23 -0
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +171 -5
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/install-docs-contract.test.d.ts +2 -0
- package/dist/cli/__tests__/install-docs-contract.test.d.ts.map +1 -0
- package/dist/cli/__tests__/install-docs-contract.test.js +55 -0
- package/dist/cli/__tests__/install-docs-contract.test.js.map +1 -0
- package/dist/cli/__tests__/launch-fallback.test.js +191 -0
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +4 -3
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +27 -41
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +232 -35
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +25 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-packaging.test.js +1 -0
- package/dist/cli/__tests__/sparkshell-packaging.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +227 -4
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +72 -1
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/version-sync-contract.test.js +4 -0
- package/dist/cli/__tests__/version-sync-contract.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/api.d.ts +26 -0
- package/dist/cli/api.d.ts.map +1 -0
- package/dist/cli/api.js +153 -0
- package/dist/cli/api.js.map +1 -0
- package/dist/cli/codex-feature-probe.d.ts +5 -0
- package/dist/cli/codex-feature-probe.d.ts.map +1 -1
- package/dist/cli/codex-feature-probe.js +13 -7
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/doctor.d.ts +7 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +119 -10
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.d.ts +2 -0
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +43 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +12 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +460 -87
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/native-assets.d.ts +2 -1
- package/dist/cli/native-assets.d.ts.map +1 -1
- package/dist/cli/native-assets.js +1 -0
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +2 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +15 -1
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +71 -11
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.d.ts +7 -1
- package/dist/cli/sparkshell.d.ts.map +1 -1
- package/dist/cli/sparkshell.js +31 -4
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +184 -10
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/update.d.ts +2 -0
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +14 -3
- package/dist/cli/update.js.map +1 -1
- package/dist/compat/__tests__/doctor-contract.test.js +3 -0
- package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
- package/dist/config/__tests__/codex-feature-flags.test.js +11 -1
- package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +19 -8
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/commit-lore-guard.test.d.ts +2 -0
- package/dist/config/__tests__/commit-lore-guard.test.d.ts.map +1 -0
- package/dist/config/__tests__/commit-lore-guard.test.js +20 -0
- package/dist/config/__tests__/commit-lore-guard.test.js.map +1 -0
- package/dist/config/codex-feature-flags.d.ts +4 -0
- package/dist/config/codex-feature-flags.d.ts.map +1 -1
- package/dist/config/codex-feature-flags.js +4 -0
- package/dist/config/codex-feature-flags.js.map +1 -1
- package/dist/config/codex-hooks.js +6 -6
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/commit-lore-guard.d.ts +1 -0
- package/dist/config/commit-lore-guard.d.ts.map +1 -1
- package/dist/config/commit-lore-guard.js +29 -3
- package/dist/config/commit-lore-guard.js.map +1 -1
- package/dist/config/generator.d.ts +3 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +114 -10
- package/dist/config/generator.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +1 -0
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +5 -1
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +10 -6
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/best-practice-research-skill.test.d.ts +2 -0
- package/dist/hooks/__tests__/best-practice-research-skill.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/best-practice-research-skill.test.js +27 -0
- package/dist/hooks/__tests__/best-practice-research-skill.test.js.map +1 -0
- package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js +13 -11
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +4 -3
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +15 -3
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +6 -0
- 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 +33 -0
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +4 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js +26 -3
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js +29 -14
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +8 -3
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +1 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +3 -2
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +14 -8
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +4 -4
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/resource-leak-watch.test.d.ts +2 -0
- package/dist/hud/__tests__/resource-leak-watch.test.d.ts.map +1 -0
- package/dist/hud/__tests__/resource-leak-watch.test.js +28 -0
- package/dist/hud/__tests__/resource-leak-watch.test.js.map +1 -0
- package/dist/hud/__tests__/tmux.test.js +23 -18
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/index.d.ts +1 -1
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +10 -4
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +9 -8
- package/dist/hud/tmux.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +75 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +3 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +71 -2
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/notifications/__tests__/http-client-resource.test.d.ts +2 -0
- package/dist/notifications/__tests__/http-client-resource.test.d.ts.map +1 -0
- package/dist/notifications/__tests__/http-client-resource.test.js +41 -0
- package/dist/notifications/__tests__/http-client-resource.test.js.map +1 -0
- package/dist/notifications/__tests__/verbosity.test.js +20 -0
- package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
- package/dist/notifications/config.d.ts.map +1 -1
- package/dist/notifications/config.js +6 -3
- package/dist/notifications/config.js.map +1 -1
- package/dist/notifications/http-client.d.ts.map +1 -1
- package/dist/notifications/http-client.js +78 -27
- package/dist/notifications/http-client.js.map +1 -1
- package/dist/notifications/types.d.ts +2 -0
- package/dist/notifications/types.d.ts.map +1 -1
- package/dist/openclaw/__tests__/dispatcher.test.js +49 -1
- package/dist/openclaw/__tests__/dispatcher.test.js.map +1 -1
- package/dist/openclaw/dispatcher.d.ts +7 -4
- package/dist/openclaw/dispatcher.d.ts.map +1 -1
- package/dist/openclaw/dispatcher.js +32 -69
- package/dist/openclaw/dispatcher.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +65 -3
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +50 -5
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/index.d.ts +8 -2
- package/dist/pipeline/index.d.ts.map +1 -1
- package/dist/pipeline/index.js +5 -2
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts +5 -4
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +56 -15
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/stages/code-review.d.ts +2 -2
- package/dist/pipeline/stages/code-review.d.ts.map +1 -1
- package/dist/pipeline/stages/code-review.js +5 -3
- package/dist/pipeline/stages/code-review.js.map +1 -1
- package/dist/pipeline/stages/deep-interview.d.ts +15 -0
- package/dist/pipeline/stages/deep-interview.d.ts.map +1 -0
- package/dist/pipeline/stages/deep-interview.js +32 -0
- package/dist/pipeline/stages/deep-interview.js.map +1 -0
- package/dist/pipeline/stages/ralph-verify.d.ts +5 -5
- package/dist/pipeline/stages/ralph-verify.d.ts.map +1 -1
- package/dist/pipeline/stages/ralph-verify.js +2 -2
- package/dist/pipeline/stages/ralph-verify.js.map +1 -1
- package/dist/pipeline/stages/ultragoal.d.ts +19 -0
- package/dist/pipeline/stages/ultragoal.d.ts.map +1 -0
- package/dist/pipeline/stages/ultragoal.js +38 -0
- package/dist/pipeline/stages/ultragoal.js.map +1 -0
- package/dist/pipeline/stages/ultraqa.d.ts +30 -0
- package/dist/pipeline/stages/ultraqa.d.ts.map +1 -0
- package/dist/pipeline/stages/ultraqa.js +46 -0
- package/dist/pipeline/stages/ultraqa.js.map +1 -0
- package/dist/pipeline/types.d.ts +8 -6
- package/dist/pipeline/types.d.ts.map +1 -1
- package/dist/pipeline/types.js +2 -2
- package/dist/scripts/__tests__/codex-native-hook.test.js +1488 -117
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.js +183 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +27 -2
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-agents.test.js +16 -1
- package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
- package/dist/scripts/build-api.d.ts +2 -0
- package/dist/scripts/build-api.d.ts.map +1 -0
- package/dist/scripts/build-api.js +44 -0
- package/dist/scripts/build-api.js.map +1 -0
- package/dist/scripts/cleanup-explore-harness.js +1 -0
- package/dist/scripts/cleanup-explore-harness.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +364 -16
- 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 +98 -25
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/notify-dispatcher.js +88 -0
- package/dist/scripts/notify-dispatcher.js.map +1 -1
- package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
- package/dist/scripts/notify-hook/process-runner.js +39 -17
- 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 +36 -14
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +26 -11
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +2 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +45 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +27 -14
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/run-provider-advisor.js +9 -3
- package/dist/scripts/run-provider-advisor.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +4 -1
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +101 -1
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js +2 -2
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/verify-native-agents.js +2 -2
- package/dist/scripts/verify-native-agents.js.map +1 -1
- package/dist/sidecar/__tests__/resource-leak-watch.test.d.ts +2 -0
- package/dist/sidecar/__tests__/resource-leak-watch.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/resource-leak-watch.test.js +38 -0
- package/dist/sidecar/__tests__/resource-leak-watch.test.js.map +1 -0
- package/dist/sidecar/index.d.ts +1 -1
- package/dist/sidecar/index.d.ts.map +1 -1
- package/dist/sidecar/index.js +29 -12
- package/dist/sidecar/index.js.map +1 -1
- package/dist/state/__tests__/operations-ralph-phase.test.js +88 -1
- package/dist/state/__tests__/operations-ralph-phase.test.js.map +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +11 -0
- package/dist/state/operations.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +2 -2
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +207 -22
- package/dist/team/__tests__/tmux-session.test.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 +73 -28
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +714 -10
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +57 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/__tests__/steering-fixtures.d.ts +68 -0
- package/dist/ultragoal/__tests__/steering-fixtures.d.ts.map +1 -0
- package/dist/ultragoal/__tests__/steering-fixtures.js +259 -0
- package/dist/ultragoal/__tests__/steering-fixtures.js.map +1 -0
- package/dist/ultragoal/__tests__/steering-fixtures.test.d.ts +2 -0
- package/dist/ultragoal/__tests__/steering-fixtures.test.d.ts.map +1 -0
- package/dist/ultragoal/__tests__/steering-fixtures.test.js +65 -0
- package/dist/ultragoal/__tests__/steering-fixtures.test.js.map +1 -0
- package/dist/ultragoal/artifacts.d.ts +97 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +811 -256
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/utils/__tests__/sleep-resource.test.d.ts +2 -0
- package/dist/utils/__tests__/sleep-resource.test.d.ts.map +1 -0
- package/dist/utils/__tests__/sleep-resource.test.js +39 -0
- package/dist/utils/__tests__/sleep-resource.test.js.map +1 -0
- package/dist/utils/sleep.d.ts.map +1 -1
- package/dist/utils/sleep.js +17 -6
- package/dist/utils/sleep.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +85 -10
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js +1 -0
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
- package/package.json +5 -3
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +4 -3
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +56 -0
- package/plugins/oh-my-codex/hooks/hooks.json +77 -0
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +77 -47
- package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +83 -0
- package/plugins/oh-my-codex/skills/cancel/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +9 -8
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +22 -11
- package/plugins/oh-my-codex/skills/plan/SKILL.md +8 -8
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +7 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -5
- package/plugins/oh-my-codex/skills/team/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +38 -4
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +1 -1
- package/prompts/planner.md +1 -1
- package/prompts/researcher.md +15 -10
- package/skills/autopilot/SKILL.md +77 -47
- package/skills/best-practice-research/SKILL.md +83 -0
- package/skills/cancel/SKILL.md +2 -2
- package/skills/deep-interview/SKILL.md +9 -8
- package/skills/omx-setup/SKILL.md +1 -1
- package/skills/pipeline/SKILL.md +22 -11
- package/skills/plan/SKILL.md +8 -8
- package/skills/ralph/SKILL.md +7 -0
- package/skills/ralplan/SKILL.md +5 -5
- package/skills/team/SKILL.md +1 -1
- package/skills/ultragoal/SKILL.md +38 -4
- package/skills/ultrawork/SKILL.md +1 -1
- package/src/scripts/__tests__/codex-native-hook.test.ts +1758 -166
- package/src/scripts/__tests__/notify-dispatcher.test.ts +223 -1
- package/src/scripts/__tests__/smoke-packed-install.test.ts +39 -2
- package/src/scripts/__tests__/verify-native-agents.test.ts +21 -1
- package/src/scripts/build-api.ts +48 -0
- package/src/scripts/cleanup-explore-harness.ts +1 -0
- package/src/scripts/codex-native-hook.ts +416 -18
- package/src/scripts/codex-native-pre-post.ts +119 -25
- package/src/scripts/notify-dispatcher.ts +97 -0
- package/src/scripts/notify-hook/process-runner.ts +40 -16
- package/src/scripts/notify-hook/team-dispatch.ts +36 -13
- package/src/scripts/notify-hook/team-leader-nudge.ts +25 -11
- package/src/scripts/notify-hook/team-tmux-guard.ts +49 -0
- package/src/scripts/notify-hook/team-worker-stop.ts +24 -13
- package/src/scripts/run-provider-advisor.ts +11 -3
- package/src/scripts/smoke-packed-install.ts +107 -0
- package/src/scripts/sync-plugin-mirror.ts +3 -3
- package/src/scripts/verify-native-agents.ts +2 -2
- package/templates/catalog-manifest.json +7 -0
|
@@ -2,7 +2,11 @@ import {
|
|
|
2
2
|
buildDocumentRefreshAdvisoryOutput,
|
|
3
3
|
evaluateStagedDocumentRefresh,
|
|
4
4
|
} from "../document-refresh/enforcer.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
OMX_LORE_COMMIT_GUARD_ENV,
|
|
7
|
+
isLoreCommitGuardEnabled,
|
|
8
|
+
readConfiguredLoreCommitGuardValue,
|
|
9
|
+
} from "../config/commit-lore-guard.js";
|
|
6
10
|
import { resolveCodexExecutionSurface } from "./codex-execution-surface.js";
|
|
7
11
|
|
|
8
12
|
type CodexHookPayload = Record<string, unknown>;
|
|
@@ -103,8 +107,8 @@ export function normalizePostToolUsePayload(
|
|
|
103
107
|
const exitCode = safeInteger(parsedToolResponse?.exit_code)
|
|
104
108
|
?? safeInteger(parsedToolResponse?.exitCode)
|
|
105
109
|
?? null;
|
|
106
|
-
const
|
|
107
|
-
const stdoutText = safeString(parsedToolResponse?.stdout).trim() ||
|
|
110
|
+
const rawToolResponseText = safeString(rawToolResponse).trim();
|
|
111
|
+
const stdoutText = safeString(parsedToolResponse?.stdout).trim() || rawToolResponseText;
|
|
108
112
|
const stderrText = safeString(parsedToolResponse?.stderr).trim();
|
|
109
113
|
|
|
110
114
|
return {
|
|
@@ -149,30 +153,49 @@ type OmxParityCommand =
|
|
|
149
153
|
| "trace"
|
|
150
154
|
| "code-intel";
|
|
151
155
|
|
|
156
|
+
function joinNonEmptyText(parts: string[]): string {
|
|
157
|
+
return parts
|
|
158
|
+
.filter(Boolean)
|
|
159
|
+
.join("\n")
|
|
160
|
+
.trim();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function structuredMcpTransportText(normalized: NormalizedPostToolUsePayload): string {
|
|
164
|
+
return joinNonEmptyText([
|
|
165
|
+
safeString(normalized.parsedToolResponse?.error),
|
|
166
|
+
safeString(normalized.parsedToolResponse?.message),
|
|
167
|
+
safeString(normalized.parsedToolResponse?.details),
|
|
168
|
+
]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function hasMcpTransportContext(text: string): boolean {
|
|
172
|
+
return /\bmcp\b/i.test(text)
|
|
173
|
+
|| /\bomx-(?:state|memory|trace|code-intel)-server\b/i.test(text);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function hasMcpTransportFailurePattern(text: string): boolean {
|
|
177
|
+
return MCP_TRANSPORT_FAILURE_PATTERNS.some((pattern) => pattern.test(text));
|
|
178
|
+
}
|
|
179
|
+
|
|
152
180
|
export function detectMcpTransportFailure(
|
|
153
181
|
payload: CodexHookPayload,
|
|
154
182
|
): McpTransportFailureSignal | null {
|
|
155
183
|
const normalized = normalizePostToolUsePayload(payload);
|
|
156
184
|
if (normalized.isBash) return null;
|
|
157
|
-
|
|
185
|
+
|
|
186
|
+
const isMcpTool = isMcpLikeToolName(normalized.toolName);
|
|
187
|
+
const structuredText = structuredMcpTransportText(normalized);
|
|
188
|
+
const rawText = joinNonEmptyText([
|
|
158
189
|
normalized.stderrText,
|
|
159
190
|
normalized.stdoutText,
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
.filter(Boolean)
|
|
165
|
-
.join("\n")
|
|
166
|
-
.trim();
|
|
191
|
+
]);
|
|
192
|
+
const combined = isMcpTool
|
|
193
|
+
? joinNonEmptyText([rawText, structuredText])
|
|
194
|
+
: structuredText;
|
|
167
195
|
|
|
168
|
-
const mcpContextDetected = isMcpLikeToolName(normalized.toolName)
|
|
169
|
-
|| /\bmcp\b/i.test(combined)
|
|
170
|
-
|| /\bomx-(?:state|memory|trace|code-intel)-server\b/i.test(combined);
|
|
171
|
-
if (!mcpContextDetected) return null;
|
|
172
196
|
if (!combined) return null;
|
|
173
|
-
if (!
|
|
174
|
-
|
|
175
|
-
}
|
|
197
|
+
if (!isMcpTool && !hasMcpTransportContext(structuredText)) return null;
|
|
198
|
+
if (!hasMcpTransportFailurePattern(combined)) return null;
|
|
176
199
|
|
|
177
200
|
return {
|
|
178
201
|
toolName: normalized.toolName,
|
|
@@ -728,6 +751,17 @@ function buildEffectiveLoreCommitGuardEnv(parsed: GitCommitCommandParseResult):
|
|
|
728
751
|
for (const [name, value] of Object.entries(parsed.inlineEnvironment)) {
|
|
729
752
|
if (typeof value === "string") effectiveEnvironment[name] = value;
|
|
730
753
|
}
|
|
754
|
+
|
|
755
|
+
if (
|
|
756
|
+
!parsed.environmentStartsClean
|
|
757
|
+
&& !parsed.unsetEnvironmentNames.includes(OMX_LORE_COMMIT_GUARD_ENV)
|
|
758
|
+
&& typeof effectiveEnvironment[OMX_LORE_COMMIT_GUARD_ENV] !== "string"
|
|
759
|
+
) {
|
|
760
|
+
const configuredValue = readConfiguredLoreCommitGuardValue(effectiveEnvironment);
|
|
761
|
+
if (typeof configuredValue === "string") {
|
|
762
|
+
effectiveEnvironment[OMX_LORE_COMMIT_GUARD_ENV] = configuredValue;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
731
765
|
return effectiveEnvironment;
|
|
732
766
|
}
|
|
733
767
|
|
|
@@ -976,15 +1010,75 @@ function buildSloppyFallbackPreToolUseOutput(commandText: string): Record<string
|
|
|
976
1010
|
};
|
|
977
1011
|
}
|
|
978
1012
|
|
|
1013
|
+
function removeHereDocBodies(command: string): string {
|
|
1014
|
+
const lines = command.split(/\r?\n/);
|
|
1015
|
+
const retained: string[] = [];
|
|
1016
|
+
let pendingDelimiter: string | null = null;
|
|
1017
|
+
|
|
1018
|
+
for (const line of lines) {
|
|
1019
|
+
if (pendingDelimiter) {
|
|
1020
|
+
if (line.trim() === pendingDelimiter) {
|
|
1021
|
+
pendingDelimiter = null;
|
|
1022
|
+
}
|
|
1023
|
+
continue;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
retained.push(line);
|
|
1027
|
+
const match = /<<-?\s*(?:"([^"]+)"|'([^']+)'|([A-Za-z0-9_.-]+))/.exec(line);
|
|
1028
|
+
if (match) pendingDelimiter = match[1] || match[2] || match[3] || null;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
return retained.join("\n");
|
|
1032
|
+
}
|
|
1033
|
+
|
|
979
1034
|
function commandInvokesOmxQuestion(command: string): boolean {
|
|
980
|
-
const tokens =
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1035
|
+
const tokens = tokenizeShellCommandWithBoundaries(removeHereDocBodies(command))
|
|
1036
|
+
?.map((token) => ({ ...token, value: token.value.toLowerCase() }))
|
|
1037
|
+
?? [];
|
|
1038
|
+
|
|
1039
|
+
for (let commandStart = 0; commandStart < tokens.length; commandStart = nextCommandStart(tokens, commandStart)) {
|
|
1040
|
+
const commandEnd = nextCommandStart(tokens, commandStart);
|
|
1041
|
+
let index = commandStart;
|
|
1042
|
+
|
|
1043
|
+
while (index < commandEnd && isInlineShellEnvAssignment(tokens[index]?.value ?? "")) {
|
|
1044
|
+
index += 1;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
while (index < commandEnd && isEnvExecutableToken(tokens[index]?.value ?? "")) {
|
|
1048
|
+
index += 1;
|
|
1049
|
+
while (index < commandEnd) {
|
|
1050
|
+
const token = tokens[index]?.value ?? "";
|
|
1051
|
+
if (token === "--") {
|
|
1052
|
+
index += 1;
|
|
1053
|
+
break;
|
|
1054
|
+
}
|
|
1055
|
+
if (isInlineShellEnvAssignment(token)) {
|
|
1056
|
+
index += 1;
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
if (token === "-i" || token === "--ignore-environment" || token.startsWith("--unset=")) {
|
|
1060
|
+
index += 1;
|
|
1061
|
+
continue;
|
|
1062
|
+
}
|
|
1063
|
+
if (token.startsWith("-")) {
|
|
1064
|
+
index += envOptionConsumesNextValue(token) ? 2 : 1;
|
|
1065
|
+
continue;
|
|
1066
|
+
}
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
const rawToken = tokens[index]?.value || "";
|
|
1072
|
+
const token = rawToken.replace(/\\/g, "/").split("/").pop() || "";
|
|
1073
|
+
if ((token === "omx" || token === "omx.js") && tokens[index + 1]?.value === "question") return true;
|
|
1074
|
+
if (
|
|
1075
|
+
(token === "node" || token === "node.exe")
|
|
1076
|
+
&& /(?:^|\/)omx\.js$/.test(tokens[index + 1]?.value || "")
|
|
1077
|
+
&& tokens[index + 2]?.value === "question"
|
|
1078
|
+
) return true;
|
|
986
1079
|
}
|
|
987
|
-
|
|
1080
|
+
|
|
1081
|
+
return false;
|
|
988
1082
|
}
|
|
989
1083
|
|
|
990
1084
|
function isQuestionReturnPaneAssignment(token: string): boolean {
|
|
@@ -52,6 +52,21 @@ function resolveNotifyEntrypoint(command: readonly string[]): string | undefined
|
|
|
52
52
|
return command.slice(1).find((arg) => !arg.startsWith("-"));
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
function getPreviousNotifyWrapperValue(
|
|
56
|
+
command: readonly string[],
|
|
57
|
+
): string | undefined {
|
|
58
|
+
for (let index = 0; index < command.length; index += 1) {
|
|
59
|
+
const part = command[index];
|
|
60
|
+
if (part === "--previous-notify") {
|
|
61
|
+
return command[index + 1];
|
|
62
|
+
}
|
|
63
|
+
if (part.startsWith("--previous-notify=")) {
|
|
64
|
+
return part.slice("--previous-notify=".length);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
55
70
|
function isOmxManagedNotifyCommand(command: readonly string[] | null | undefined): boolean {
|
|
56
71
|
if (!command) return false;
|
|
57
72
|
const entrypoint = resolveNotifyEntrypoint(command);
|
|
@@ -62,12 +77,94 @@ function isOmxManagedNotifyCommand(command: readonly string[] | null | undefined
|
|
|
62
77
|
return /(?:^|[\\/])oh-my-codex(?:[\\/]|$)/.test(entrypoint);
|
|
63
78
|
}
|
|
64
79
|
|
|
80
|
+
function isOmxDispatcherMetadataCommand(command: readonly string[] | null | undefined): boolean {
|
|
81
|
+
if (!command) return false;
|
|
82
|
+
const entrypoint = resolveNotifyEntrypoint(command);
|
|
83
|
+
if (!entrypoint || !/(?:^|[\\/])notify-dispatcher\.js$/.test(entrypoint)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const metadataIndex = command.indexOf("--metadata");
|
|
87
|
+
const metadataPath = metadataIndex >= 0 ? command[metadataIndex + 1] : undefined;
|
|
88
|
+
return typeof metadataPath === "string" && /(?:^|[\\/])(?:\.omx[\\/])?notify-dispatch\.json$/.test(metadataPath);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function isOmxManagedPayloadText(value: string): boolean {
|
|
92
|
+
const containsManagedPackageNotify =
|
|
93
|
+
/(?:^|[\\/])notify-(?:hook|dispatcher)\.js(?:\s|$|["'])/.test(
|
|
94
|
+
value,
|
|
95
|
+
) && /(?:^|[\\/])oh-my-codex(?:[\\/]|$)/.test(value);
|
|
96
|
+
const containsDispatcherMetadataNotify =
|
|
97
|
+
/(?:^|[\\/])notify-dispatcher\.js(?:\s|$|["'])/.test(value) &&
|
|
98
|
+
/--metadata(?:\s|=)/.test(value) &&
|
|
99
|
+
/(?:^|[\\/])(?:\.omx[\\/])?notify-dispatch\.json(?:\s|$|["'])/.test(value);
|
|
100
|
+
return containsManagedPackageNotify || containsDispatcherMetadataNotify;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function parseJsonString(value: string): unknown | undefined {
|
|
104
|
+
const trimmed = value.trim();
|
|
105
|
+
if (!trimmed) return undefined;
|
|
106
|
+
const first = trimmed[0];
|
|
107
|
+
if (first !== "[" && first !== "{" && first !== '"') return undefined;
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(trimmed) as unknown;
|
|
110
|
+
} catch {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function containsOmxManagedNotifyPayload(value: unknown, depth = 0): boolean {
|
|
116
|
+
if (depth > 8 || value == null) return false;
|
|
117
|
+
if (typeof value === "string") {
|
|
118
|
+
const parsed = parseJsonString(value);
|
|
119
|
+
if (parsed !== undefined && parsed !== value) {
|
|
120
|
+
return containsOmxManagedNotifyPayload(parsed, depth + 1);
|
|
121
|
+
}
|
|
122
|
+
return isOmxManagedPayloadText(value);
|
|
123
|
+
}
|
|
124
|
+
if (Array.isArray(value)) {
|
|
125
|
+
if (value.every((item) => typeof item === "string")) {
|
|
126
|
+
const command = value as string[];
|
|
127
|
+
return (
|
|
128
|
+
isOmxManagedNotifyCommand(command) ||
|
|
129
|
+
isOmxDispatcherMetadataCommand(command) ||
|
|
130
|
+
isOmxManagedPreviousNotifyWrapper(command)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return value.some((item) => containsOmxManagedNotifyPayload(item, depth + 1));
|
|
134
|
+
}
|
|
135
|
+
if (typeof value === "object") {
|
|
136
|
+
const record = value as Record<string, unknown>;
|
|
137
|
+
return [
|
|
138
|
+
record.previousNotify,
|
|
139
|
+
record.previous_notify,
|
|
140
|
+
record.notify,
|
|
141
|
+
record.command,
|
|
142
|
+
record.argv,
|
|
143
|
+
record.args,
|
|
144
|
+
].some((item) => containsOmxManagedNotifyPayload(item, depth + 1));
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function isOmxManagedPreviousNotifyWrapper(
|
|
150
|
+
command: readonly string[] | null | undefined,
|
|
151
|
+
): boolean {
|
|
152
|
+
if (!command) return false;
|
|
153
|
+
if (!command.some((part) => part === "turn-ended")) return false;
|
|
154
|
+
const previousNotify = getPreviousNotifyWrapperValue(command);
|
|
155
|
+
if (!previousNotify) return false;
|
|
156
|
+
|
|
157
|
+
return containsOmxManagedNotifyPayload(previousNotify);
|
|
158
|
+
}
|
|
159
|
+
|
|
65
160
|
function isManagedPreviousNotify(
|
|
66
161
|
previousNotify: readonly string[] | null | undefined,
|
|
67
162
|
metadata: NotifyDispatcherMetadata | null,
|
|
68
163
|
): boolean {
|
|
69
164
|
return (
|
|
70
165
|
isOmxManagedNotifyCommand(previousNotify) ||
|
|
166
|
+
isOmxDispatcherMetadataCommand(previousNotify) ||
|
|
167
|
+
isOmxManagedPreviousNotifyWrapper(previousNotify) ||
|
|
71
168
|
sameCommand(previousNotify, metadata?.omxNotify) ||
|
|
72
169
|
sameCommand(previousNotify, metadata?.dispatcherNotify)
|
|
73
170
|
);
|
|
@@ -17,35 +17,59 @@ export function runProcess(command: string, args: string[], timeoutMs = 3000): P
|
|
|
17
17
|
let stdout = '';
|
|
18
18
|
let stderr = '';
|
|
19
19
|
let finished = false;
|
|
20
|
+
let sigkillTimer: ReturnType<typeof setTimeout> | undefined;
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
const cleanup = (clearPendingSigkill = true) => {
|
|
23
|
+
clearTimeout(timer);
|
|
24
|
+
if (clearPendingSigkill && sigkillTimer) {
|
|
25
|
+
clearTimeout(sigkillTimer);
|
|
26
|
+
sigkillTimer = undefined;
|
|
27
|
+
}
|
|
28
|
+
child.stdout.off('data', onStdout);
|
|
29
|
+
child.stderr.off('data', onStderr);
|
|
30
|
+
child.off('error', onError);
|
|
31
|
+
child.off('close', onClose);
|
|
32
|
+
};
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
const onStdout = (chunk: Buffer) => {
|
|
29
35
|
stdout += chunk.toString();
|
|
30
|
-
}
|
|
31
|
-
|
|
36
|
+
};
|
|
37
|
+
const onStderr = (chunk: Buffer) => {
|
|
32
38
|
stderr += chunk.toString();
|
|
33
|
-
}
|
|
34
|
-
|
|
39
|
+
};
|
|
40
|
+
const onError = (err: Error) => {
|
|
35
41
|
if (finished) return;
|
|
36
42
|
finished = true;
|
|
37
|
-
|
|
43
|
+
cleanup();
|
|
38
44
|
reject(err);
|
|
39
|
-
}
|
|
40
|
-
|
|
45
|
+
};
|
|
46
|
+
const onClose = (code: number | null) => {
|
|
41
47
|
if (finished) return;
|
|
42
48
|
finished = true;
|
|
43
|
-
|
|
49
|
+
cleanup();
|
|
44
50
|
if (code === 0) {
|
|
45
51
|
resolve({ stdout, stderr, code });
|
|
46
52
|
} else {
|
|
47
53
|
reject(new Error(stderr.trim() || `${command} exited ${code}`));
|
|
48
54
|
}
|
|
49
|
-
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const timer = setTimeout(() => {
|
|
58
|
+
if (finished) return;
|
|
59
|
+
finished = true;
|
|
60
|
+
child.kill('SIGTERM');
|
|
61
|
+
sigkillTimer = setTimeout(() => {
|
|
62
|
+
sigkillTimer = undefined;
|
|
63
|
+
child.kill('SIGKILL');
|
|
64
|
+
}, 250);
|
|
65
|
+
sigkillTimer.unref?.();
|
|
66
|
+
cleanup(false);
|
|
67
|
+
reject(new Error(`timeout after ${effectiveTimeoutMs}ms`));
|
|
68
|
+
}, effectiveTimeoutMs);
|
|
69
|
+
|
|
70
|
+
child.stdout.on('data', onStdout);
|
|
71
|
+
child.stderr.on('data', onStderr);
|
|
72
|
+
child.on('error', onError);
|
|
73
|
+
child.on('close', onClose);
|
|
50
74
|
});
|
|
51
75
|
}
|
|
@@ -726,12 +726,14 @@ function resolveWorkerCliForRequest(request, config) {
|
|
|
726
726
|
|
|
727
727
|
function capturedPaneContainsTrigger(captured, trigger) {
|
|
728
728
|
if (!captured || !trigger) return false;
|
|
729
|
-
|
|
729
|
+
const normalizeForDraftMatch = (value) => normalizeTmuxCapture(value).replace(/-\s+/g, '-');
|
|
730
|
+
return normalizeForDraftMatch(captured).includes(normalizeForDraftMatch(trigger));
|
|
730
731
|
}
|
|
731
732
|
|
|
732
733
|
function capturedPaneContainsTriggerNearTail(captured, trigger, nonEmptyTailLines = 24) {
|
|
733
734
|
if (!captured || !trigger) return false;
|
|
734
|
-
const
|
|
735
|
+
const normalizeForDraftMatch = (value) => normalizeTmuxCapture(value).replace(/-\s+/g, '-');
|
|
736
|
+
const normalizedTrigger = normalizeForDraftMatch(trigger);
|
|
735
737
|
if (!normalizedTrigger) return false;
|
|
736
738
|
const lines = safeString(captured)
|
|
737
739
|
.split('\n')
|
|
@@ -739,7 +741,13 @@ function capturedPaneContainsTriggerNearTail(captured, trigger, nonEmptyTailLine
|
|
|
739
741
|
.filter((line) => line.length > 0);
|
|
740
742
|
if (lines.length === 0) return false;
|
|
741
743
|
const tail = lines.slice(-Math.max(1, nonEmptyTailLines)).join(' ');
|
|
742
|
-
return
|
|
744
|
+
return normalizeForDraftMatch(tail).includes(normalizedTrigger);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
function buildJoinedCapturePaneArgv(paneTarget, tailLines = 80) {
|
|
748
|
+
// Join wrapped visual lines so long path-like trigger text split by tmux
|
|
749
|
+
// remains comparable with the original trigger.
|
|
750
|
+
return ['capture-pane', '-J', '-t', paneTarget, '-p', '-S', `-${tailLines}`];
|
|
743
751
|
}
|
|
744
752
|
|
|
745
753
|
const INJECT_VERIFY_DELAY_MS = 250;
|
|
@@ -791,7 +799,7 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
791
799
|
if (attemptCountAtStart >= 1) {
|
|
792
800
|
try {
|
|
793
801
|
// Narrow capture (8 lines) to scope check to input area, not scrollback output
|
|
794
|
-
const preCapture = await runProcess('tmux',
|
|
802
|
+
const preCapture = await runProcess('tmux', buildJoinedCapturePaneArgv(resolution.paneTarget, 8), 2000);
|
|
795
803
|
preCaptureHasTrigger = capturedPaneContainsTrigger(preCapture.stdout, request.trigger_message);
|
|
796
804
|
} catch {
|
|
797
805
|
preCaptureHasTrigger = false;
|
|
@@ -814,6 +822,7 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
814
822
|
prompt: request.trigger_message,
|
|
815
823
|
submitKeyPresses,
|
|
816
824
|
typePrompt: shouldTypePrompt,
|
|
825
|
+
queueFirstSubmit: leaderTargeted,
|
|
817
826
|
});
|
|
818
827
|
if (!sendResult.ok) {
|
|
819
828
|
return {
|
|
@@ -830,8 +839,8 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
830
839
|
// Post-injection verification: confirm the trigger text was consumed.
|
|
831
840
|
// Fixes #391: without this, dispatch marks 'notified' even when the worker
|
|
832
841
|
// pane is sitting on an unsent draft (C-m was not effectively applied).
|
|
833
|
-
const verifyNarrowArgv =
|
|
834
|
-
const verifyWideArgv =
|
|
842
|
+
const verifyNarrowArgv = buildJoinedCapturePaneArgv(resolution.paneTarget, 8);
|
|
843
|
+
const verifyWideArgv = buildJoinedCapturePaneArgv(resolution.paneTarget);
|
|
835
844
|
for (let round = 0; round < INJECT_VERIFY_ROUNDS; round++) {
|
|
836
845
|
await new Promise((r) => setTimeout(r, INJECT_VERIFY_DELAY_MS));
|
|
837
846
|
try {
|
|
@@ -842,6 +851,19 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
842
851
|
// full-scrollback false positives.
|
|
843
852
|
const narrowCap = await runProcess('tmux', verifyNarrowArgv, 2000);
|
|
844
853
|
const wideCap = await runProcess('tmux', verifyWideArgv, 2000);
|
|
854
|
+
const triggerInNarrow = capturedPaneContainsTrigger(narrowCap.stdout, request.trigger_message);
|
|
855
|
+
const triggerNearTail = capturedPaneContainsTriggerNearTail(wideCap.stdout, request.trigger_message);
|
|
856
|
+
if (triggerInNarrow || triggerNearTail) {
|
|
857
|
+
// Draft is still visible, so C-m has not actually submitted it yet.
|
|
858
|
+
// Do not let transient spinner/active-task text mask an unsent draft.
|
|
859
|
+
await sendPaneInput({
|
|
860
|
+
paneTarget: resolution.paneTarget,
|
|
861
|
+
prompt: request.trigger_message,
|
|
862
|
+
submitKeyPresses,
|
|
863
|
+
typePrompt: false,
|
|
864
|
+
}).catch(() => {});
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
845
867
|
// Worker is actively processing (mirrors sync path tmux-session.ts:1292-1294)
|
|
846
868
|
if (paneHasActiveTask(wideCap.stdout)) {
|
|
847
869
|
runtimeExec({ command: 'MarkDelivered', request_id: request.request_id }, stateDir, request.team_name);
|
|
@@ -855,15 +877,15 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
855
877
|
tmux_injection_attempted: true,
|
|
856
878
|
};
|
|
857
879
|
}
|
|
858
|
-
// Do not declare success while a
|
|
859
|
-
//
|
|
860
|
-
//
|
|
861
|
-
//
|
|
862
|
-
|
|
880
|
+
// Do not declare success while a pane is not input-ready. Otherwise a
|
|
881
|
+
// pre-ready send can be marked "confirmed" and later appear as a stuck
|
|
882
|
+
// unsent draft once the UI finishes loading. This includes leader-fixed:
|
|
883
|
+
// its Codex UI can show "tab to queue message" while busy, and marking
|
|
884
|
+
// delivered before queue/consumption confirmation loses the orchestration
|
|
885
|
+
// nudge until a human presses Tab manually.
|
|
886
|
+
if (!paneLooksReady(wideCap.stdout)) {
|
|
863
887
|
continue;
|
|
864
888
|
}
|
|
865
|
-
const triggerInNarrow = capturedPaneContainsTrigger(narrowCap.stdout, request.trigger_message);
|
|
866
|
-
const triggerNearTail = capturedPaneContainsTriggerNearTail(wideCap.stdout, request.trigger_message);
|
|
867
889
|
if (!triggerInNarrow && !triggerNearTail) {
|
|
868
890
|
runtimeExec({ command: 'MarkDelivered', request_id: request.request_id }, stateDir, request.team_name);
|
|
869
891
|
return {
|
|
@@ -885,6 +907,7 @@ async function injectDispatchRequest(request, config, cwd, stateDir) {
|
|
|
885
907
|
prompt: request.trigger_message,
|
|
886
908
|
submitKeyPresses,
|
|
887
909
|
typePrompt: false,
|
|
910
|
+
queueFirstSubmit: leaderTargeted,
|
|
888
911
|
}).catch(() => {});
|
|
889
912
|
}
|
|
890
913
|
|
|
@@ -11,14 +11,14 @@ import { asNumber, safeString, isTerminalPhase } from './utils.js';
|
|
|
11
11
|
import { readJsonIfExists, getScopedStateDirsForCurrentSession } from './state-io.js';
|
|
12
12
|
import { runProcess } from './process-runner.js';
|
|
13
13
|
import { logTmuxHookEvent } from './log.js';
|
|
14
|
-
import { evaluatePaneInjectionReadiness, sendPaneInput } from './team-tmux-guard.js';
|
|
14
|
+
import { evaluatePaneInjectionReadiness, queuePaneInput, sendPaneInput } from './team-tmux-guard.js';
|
|
15
15
|
import { resolvePaneTarget } from './tmux-injection.js';
|
|
16
16
|
import { listNotifyCanonicalActiveTeams } from './active-team.js';
|
|
17
17
|
import {
|
|
18
18
|
classifyLeaderActionState,
|
|
19
19
|
resolveLeaderNudgeIntent,
|
|
20
20
|
} from './orchestration-intent.js';
|
|
21
|
-
import { DEFAULT_MARKER } from '../tmux-hook-engine.js';
|
|
21
|
+
import { DEFAULT_MARKER, paneHasActiveTask } from '../tmux-hook-engine.js';
|
|
22
22
|
import { isLeaderRuntimeStale } from '../../team/leader-activity.js';
|
|
23
23
|
import { appendTeamDeliveryLog } from '../../team/delivery-log.js';
|
|
24
24
|
import { writeTeamLeaderAttention } from '../../team/state.js';
|
|
@@ -967,14 +967,27 @@ export async function maybeNudgeTeamLeader({
|
|
|
967
967
|
}
|
|
968
968
|
|
|
969
969
|
try {
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
970
|
+
const leaderHasActiveTask = paneHasActiveTask(paneGuard.paneCapture);
|
|
971
|
+
let deliveryMode = 'sent';
|
|
972
|
+
if (leaderHasActiveTask) {
|
|
973
|
+
const sendResult = await queuePaneInput({
|
|
974
|
+
paneTarget: tmuxTarget,
|
|
975
|
+
prompt: markedText,
|
|
976
|
+
});
|
|
977
|
+
if (!sendResult.ok) {
|
|
978
|
+
throw new Error(sendResult.error || sendResult.reason);
|
|
979
|
+
}
|
|
980
|
+
deliveryMode = 'queued';
|
|
981
|
+
} else {
|
|
982
|
+
const sendResult = await sendPaneInput({
|
|
983
|
+
paneTarget: tmuxTarget,
|
|
984
|
+
prompt: markedText,
|
|
985
|
+
submitKeyPresses: 2,
|
|
986
|
+
submitDelayMs: 100,
|
|
987
|
+
});
|
|
988
|
+
if (!sendResult.ok) {
|
|
989
|
+
throw new Error(sendResult.error || sendResult.reason);
|
|
990
|
+
}
|
|
978
991
|
}
|
|
979
992
|
nudgeState.last_nudged_by_team[teamName] = {
|
|
980
993
|
at: nowIso,
|
|
@@ -1005,6 +1018,7 @@ export async function maybeNudgeTeamLeader({
|
|
|
1005
1018
|
message_count: messages.length,
|
|
1006
1019
|
stalled_for_ms: undefined,
|
|
1007
1020
|
missing_signal_workers: progressSnapshot.missingSignalWorkers,
|
|
1021
|
+
delivery: deliveryMode,
|
|
1008
1022
|
});
|
|
1009
1023
|
} catch { /* ignore */ }
|
|
1010
1024
|
await appendTeamDeliveryLog(logsDir, {
|
|
@@ -1013,7 +1027,7 @@ export async function maybeNudgeTeamLeader({
|
|
|
1013
1027
|
team: teamName,
|
|
1014
1028
|
to_worker: 'leader-fixed',
|
|
1015
1029
|
transport: 'send-keys',
|
|
1016
|
-
result:
|
|
1030
|
+
result: deliveryMode,
|
|
1017
1031
|
reason: nudgeReason,
|
|
1018
1032
|
orchestration_intent: orchestrationIntent,
|
|
1019
1033
|
}).catch(() => {});
|
|
@@ -134,6 +134,7 @@ export async function sendPaneInput({
|
|
|
134
134
|
submitKeyPresses = 2,
|
|
135
135
|
submitDelayMs = 0,
|
|
136
136
|
typePrompt = true,
|
|
137
|
+
queueFirstSubmit = false,
|
|
137
138
|
}: any): Promise<any> {
|
|
138
139
|
const target = safeString(paneTarget).trim();
|
|
139
140
|
if (!target) {
|
|
@@ -163,6 +164,12 @@ export async function sendPaneInput({
|
|
|
163
164
|
if (typePrompt) {
|
|
164
165
|
await runProcess('tmux', argv.typeArgv, 3000);
|
|
165
166
|
}
|
|
167
|
+
if (queueFirstSubmit && argv.submitArgv.length > 0) {
|
|
168
|
+
await runProcess('tmux', ['send-keys', '-t', target, 'Tab'], 3000);
|
|
169
|
+
if (submitDelayMs > 0) {
|
|
170
|
+
await new Promise((resolve) => setTimeout(resolve, submitDelayMs));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
166
173
|
for (const submit of argv.submitArgv) {
|
|
167
174
|
if (submitDelayMs > 0) {
|
|
168
175
|
await new Promise((resolve) => setTimeout(resolve, submitDelayMs));
|
|
@@ -182,6 +189,48 @@ export async function sendPaneInput({
|
|
|
182
189
|
}
|
|
183
190
|
}
|
|
184
191
|
|
|
192
|
+
export async function queuePaneInput({
|
|
193
|
+
paneTarget,
|
|
194
|
+
prompt,
|
|
195
|
+
submitDelayMs = 80,
|
|
196
|
+
}: any): Promise<any> {
|
|
197
|
+
const sendResult = await sendPaneInput({
|
|
198
|
+
paneTarget,
|
|
199
|
+
prompt,
|
|
200
|
+
submitKeyPresses: 0,
|
|
201
|
+
});
|
|
202
|
+
if (!sendResult.ok) return sendResult;
|
|
203
|
+
|
|
204
|
+
const target = safeString(paneTarget).trim();
|
|
205
|
+
const submitArgv = [
|
|
206
|
+
['send-keys', '-t', target, 'Tab'],
|
|
207
|
+
['send-keys', '-t', target, 'C-m'],
|
|
208
|
+
];
|
|
209
|
+
try {
|
|
210
|
+
await runProcess('tmux', submitArgv[0], 3000);
|
|
211
|
+
if (submitDelayMs > 0) {
|
|
212
|
+
await new Promise((resolve) => setTimeout(resolve, submitDelayMs));
|
|
213
|
+
}
|
|
214
|
+
await runProcess('tmux', submitArgv[1], 3000);
|
|
215
|
+
return {
|
|
216
|
+
ok: true,
|
|
217
|
+
sent: true,
|
|
218
|
+
reason: 'queued',
|
|
219
|
+
paneTarget: target,
|
|
220
|
+
argv: { typeArgv: sendResult.argv?.typeArgv || null, submitArgv },
|
|
221
|
+
};
|
|
222
|
+
} catch (error) {
|
|
223
|
+
return {
|
|
224
|
+
ok: false,
|
|
225
|
+
sent: false,
|
|
226
|
+
reason: 'queue_failed',
|
|
227
|
+
paneTarget: target,
|
|
228
|
+
argv: { typeArgv: sendResult.argv?.typeArgv || null, submitArgv },
|
|
229
|
+
error: error instanceof Error ? error.message : safeString(error),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
185
234
|
export async function checkPaneReadyForTeamSendKeys(paneTarget: any): Promise<any> {
|
|
186
235
|
return evaluatePaneInjectionReadiness(paneTarget);
|
|
187
236
|
}
|