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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from "child_process";
|
|
2
2
|
import { closeSync, existsSync, openSync, readFileSync, readSync } from "fs";
|
|
3
|
-
import { appendFile, mkdir, readFile, readdir, writeFile } from "fs/promises";
|
|
3
|
+
import { appendFile, mkdir, readFile, readdir, stat, writeFile } from "fs/promises";
|
|
4
4
|
import { extname, join, relative, resolve } from "path";
|
|
5
5
|
import { pathToFileURL } from "url";
|
|
6
6
|
import { readModeState, readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
|
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
} from "../hooks/extensibility/events.js";
|
|
70
70
|
import type { HookEventEnvelope } from "../hooks/extensibility/types.js";
|
|
71
71
|
import { dispatchHookEventRuntime } from "../hooks/extensibility/runtime.js";
|
|
72
|
+
import { getNotificationConfig, getVerbosity } from "../notifications/config.js";
|
|
72
73
|
import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
|
|
73
74
|
import {
|
|
74
75
|
onPreCompact as buildWikiPreCompactContext,
|
|
@@ -78,6 +79,11 @@ import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDec
|
|
|
78
79
|
import { readRunState } from "../runtime/run-state.js";
|
|
79
80
|
import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
|
|
80
81
|
import { getRunContinuationSnapshot, shouldContinueRun } from "../runtime/run-loop.js";
|
|
82
|
+
import {
|
|
83
|
+
parseUltragoalSteeringDirective,
|
|
84
|
+
steerUltragoal,
|
|
85
|
+
type UltragoalSteeringProposal,
|
|
86
|
+
} from "../ultragoal/artifacts.js";
|
|
81
87
|
import { triagePrompt } from "../hooks/triage-heuristic.js";
|
|
82
88
|
import { readTriageConfig } from "../hooks/triage-config.js";
|
|
83
89
|
import {
|
|
@@ -128,6 +134,7 @@ const TEAM_STOP_BLOCKING_TASK_STATUSES = new Set(["pending", "in_progress", "blo
|
|
|
128
134
|
const TEAM_WORKER_TERMINAL_RUN_STATES = new Set(["done", "complete", "completed", "failed", "stopped", "cancelled"]);
|
|
129
135
|
const NATIVE_STOP_STATE_FILE = "native-stop-state.json";
|
|
130
136
|
const ORDINARY_STOP_NO_PROGRESS_DEFAULT_MAX_REPEATS = 8;
|
|
137
|
+
const RALPH_ORPHANED_STARTING_STALE_MS = 15 * 60_000;
|
|
131
138
|
const ORDINARY_STOP_NO_PROGRESS_DEFAULT_IDLE_MS = 10 * 60_000;
|
|
132
139
|
const ORDINARY_STOP_NO_PROGRESS_MAX_MESSAGE_LENGTH = 240;
|
|
133
140
|
const STABLE_FINAL_RECOMMENDATION_PATTERNS = [
|
|
@@ -304,6 +311,13 @@ async function isNativeSubagentHook(
|
|
|
304
311
|
return candidateIds.some((id) => summary.allSubagentThreadIds.includes(id));
|
|
305
312
|
}
|
|
306
313
|
|
|
314
|
+
function shouldSuppressSubagentLifecycleHookDispatch(): boolean {
|
|
315
|
+
const config = getNotificationConfig();
|
|
316
|
+
if (config?.includeChildAgents === true) return false;
|
|
317
|
+
const verbosity = getVerbosity(config);
|
|
318
|
+
return verbosity !== "agent" && verbosity !== "verbose";
|
|
319
|
+
}
|
|
320
|
+
|
|
307
321
|
async function recordIgnoredNativeSubagentSessionStart(
|
|
308
322
|
cwd: string,
|
|
309
323
|
canonicalSessionId: string,
|
|
@@ -418,6 +432,104 @@ function readPromptText(payload: CodexHookPayload): string {
|
|
|
418
432
|
return "";
|
|
419
433
|
}
|
|
420
434
|
|
|
435
|
+
|
|
436
|
+
function extractBalancedJsonObject(text: string, startIndex: number): string | null {
|
|
437
|
+
let depth = 0;
|
|
438
|
+
let inString = false;
|
|
439
|
+
let escaped = false;
|
|
440
|
+
for (let index = startIndex; index < text.length; index++) {
|
|
441
|
+
const char = text[index];
|
|
442
|
+
if (inString) {
|
|
443
|
+
if (escaped) escaped = false;
|
|
444
|
+
else if (char === "\\") escaped = true;
|
|
445
|
+
else if (char === '"') inString = false;
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
if (char === '"') {
|
|
449
|
+
inString = true;
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (char === "{") depth += 1;
|
|
453
|
+
else if (char === "}") {
|
|
454
|
+
depth -= 1;
|
|
455
|
+
if (depth === 0) return text.slice(startIndex, index + 1);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function normalizePromptSteeringProposal(raw: unknown, prompt: string): UltragoalSteeringProposal | null {
|
|
462
|
+
const candidate = safeObject(raw);
|
|
463
|
+
const nested = candidate.omx_ultragoal_steer ?? candidate.ultragoal_steer ?? candidate.steering ?? candidate;
|
|
464
|
+
const proposal = parseUltragoalSteeringDirective(JSON.stringify(nested));
|
|
465
|
+
if (!proposal) return null;
|
|
466
|
+
if (proposal.source !== "user_prompt_submit") return null;
|
|
467
|
+
const normalized = prompt.trim().toLowerCase();
|
|
468
|
+
return {
|
|
469
|
+
...proposal,
|
|
470
|
+
directiveText: proposal.directiveText ?? safeContextSnippet(prompt, 600),
|
|
471
|
+
promptSignature: proposal.promptSignature ?? promptSignature(normalized),
|
|
472
|
+
idempotencyKey: proposal.idempotencyKey ?? `user_prompt_submit:${promptSignature(normalized)}`,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function parseUserPromptUltragoalSteeringDirective(prompt: string): UltragoalSteeringProposal | null {
|
|
477
|
+
const trimmed = prompt.trim();
|
|
478
|
+
if (!trimmed) return null;
|
|
479
|
+
const fenced = trimmed.match(/```(?:omx-ultragoal-steer|ultragoal-steer)\s*([\s\S]*?)```/i);
|
|
480
|
+
if (fenced?.[1]) {
|
|
481
|
+
try {
|
|
482
|
+
return normalizePromptSteeringProposal(JSON.parse(fenced[1]), prompt);
|
|
483
|
+
} catch {
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const label = trimmed.match(/(?:^|\n)\s*(?:OMX_ULTRAGOAL_STEER|omx\.ultragoal\.steer|omx ultragoal steer)\s*:\s*{/i);
|
|
489
|
+
if (label?.index !== undefined) {
|
|
490
|
+
const brace = trimmed.indexOf("{", label.index);
|
|
491
|
+
const json = brace >= 0 ? extractBalancedJsonObject(trimmed, brace) : null;
|
|
492
|
+
if (json) {
|
|
493
|
+
try {
|
|
494
|
+
return normalizePromptSteeringProposal(JSON.parse(json), prompt);
|
|
495
|
+
} catch {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (trimmed.startsWith("{")) {
|
|
502
|
+
try {
|
|
503
|
+
const parsed = JSON.parse(trimmed);
|
|
504
|
+
const object = safeObject(parsed);
|
|
505
|
+
if ("omx_ultragoal_steer" in object || "ultragoal_steer" in object) {
|
|
506
|
+
return normalizePromptSteeringProposal(parsed, prompt);
|
|
507
|
+
}
|
|
508
|
+
} catch {
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
async function applyUserPromptUltragoalSteering(cwd: string, prompt: string): Promise<string | null> {
|
|
516
|
+
const proposal = parseUserPromptUltragoalSteeringDirective(prompt);
|
|
517
|
+
if (!proposal) return null;
|
|
518
|
+
try {
|
|
519
|
+
const result = await steerUltragoal(cwd, proposal);
|
|
520
|
+
const status = result.deduped ? "deduped" : result.accepted ? "accepted" : "rejected";
|
|
521
|
+
const reasons = result.rejectedReasons.length > 0 ? ` rejectedReasons=${result.rejectedReasons.join("; ")}` : "";
|
|
522
|
+
return [
|
|
523
|
+
`OMX native UserPromptSubmit applied bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${status}.`,
|
|
524
|
+
`mutation=${result.audit.kind}; source=${result.audit.source}; targets=${result.audit.targetGoalIds.join(",") || "none"}; idempotencyKey=${result.audit.idempotencyKey ?? "none"}.${reasons}`,
|
|
525
|
+
"Only explicit structured steering directives are parsed; normal prose is ignored and cannot mutate .omx/ultragoal.",
|
|
526
|
+
].join(" ");
|
|
527
|
+
} catch (error) {
|
|
528
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
529
|
+
return `OMX native UserPromptSubmit rejected bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${message}`;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
421
533
|
function sanitizePayloadForHookContext(
|
|
422
534
|
payload: CodexHookPayload,
|
|
423
535
|
hookEventName: CodexHookEventName,
|
|
@@ -513,6 +625,52 @@ function isRalphStartingPhase(state: Record<string, unknown>): boolean {
|
|
|
513
625
|
return safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase() === "starting";
|
|
514
626
|
}
|
|
515
627
|
|
|
628
|
+
|
|
629
|
+
function parseTimestampMs(value: unknown): number | null {
|
|
630
|
+
const text = safeString(value).trim();
|
|
631
|
+
if (!text) return null;
|
|
632
|
+
const ms = Date.parse(text);
|
|
633
|
+
return Number.isFinite(ms) ? ms : null;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function numericValue(value: unknown): number | null {
|
|
637
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
638
|
+
if (typeof value === "string" && value.trim()) {
|
|
639
|
+
const parsed = Number(value);
|
|
640
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
641
|
+
}
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function hasRalphOwnerHint(state: Record<string, unknown>): boolean {
|
|
646
|
+
return [
|
|
647
|
+
state.owner_omx_session_id,
|
|
648
|
+
state.owner_codex_session_id,
|
|
649
|
+
state.owner_codex_thread_id,
|
|
650
|
+
state.thread_id,
|
|
651
|
+
state.tmux_pane_id,
|
|
652
|
+
state.task_slug,
|
|
653
|
+
].some((value) => safeString(value).trim() !== "");
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
async function isStaleOrphanedRalphStartingState(
|
|
657
|
+
state: Record<string, unknown>,
|
|
658
|
+
path: string,
|
|
659
|
+
nowMs = Date.now(),
|
|
660
|
+
): Promise<boolean> {
|
|
661
|
+
if (!isRalphStartingPhase(state)) return false;
|
|
662
|
+
if (numericValue(state.iteration) !== 0) return false;
|
|
663
|
+
if (hasRalphOwnerHint(state)) return false;
|
|
664
|
+
|
|
665
|
+
const timestampMs = parseTimestampMs(state.updated_at)
|
|
666
|
+
?? parseTimestampMs(state.started_at)
|
|
667
|
+
?? parseTimestampMs(state.created_at)
|
|
668
|
+
?? await stat(path).then((info) => info.mtimeMs, () => null);
|
|
669
|
+
if (timestampMs === null) return false;
|
|
670
|
+
|
|
671
|
+
return nowMs - timestampMs > RALPH_ORPHANED_STARTING_STALE_MS;
|
|
672
|
+
}
|
|
673
|
+
|
|
516
674
|
function hasValue(values: string[], value: string): boolean {
|
|
517
675
|
return value !== "" && values.some((candidate) => candidate === value);
|
|
518
676
|
}
|
|
@@ -597,6 +755,99 @@ async function hasConsistentRalphSkillActivation(stateDir: string, sessionId: st
|
|
|
597
755
|
return true;
|
|
598
756
|
}
|
|
599
757
|
|
|
758
|
+
function isShadowableRalphStartingSeed(state: Record<string, unknown>): boolean {
|
|
759
|
+
if (state.active !== true) return false;
|
|
760
|
+
if (!isRalphStartingPhase(state)) return false;
|
|
761
|
+
if (state.completion_audit || state.completionAudit) return false;
|
|
762
|
+
const iteration = numericValue(state.iteration);
|
|
763
|
+
return iteration === null || iteration <= 0;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
function hasPassingCompletedRalphAudit(state: Record<string, unknown> | null, cwd: string): boolean {
|
|
767
|
+
if (!state) return false;
|
|
768
|
+
if (state.mode && safeString(state.mode) !== "ralph") return false;
|
|
769
|
+
if (!isRalphCompletePhase(state.current_phase ?? state.currentPhase)) return false;
|
|
770
|
+
if (state.active === true) return false;
|
|
771
|
+
return evaluateRalphCompletionAuditEvidence(state, cwd).complete === true;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function shouldRetireShadowedRalphStartingSeed(
|
|
775
|
+
seedState: Record<string, unknown>,
|
|
776
|
+
completedState: Record<string, unknown> | null,
|
|
777
|
+
cwd: string,
|
|
778
|
+
ownerContext?: {
|
|
779
|
+
completedSessionId?: string;
|
|
780
|
+
payloadSessionId?: string;
|
|
781
|
+
threadId?: string;
|
|
782
|
+
currentNativeSessionId?: string;
|
|
783
|
+
tmuxPaneId?: string;
|
|
784
|
+
},
|
|
785
|
+
): boolean {
|
|
786
|
+
if (!isShadowableRalphStartingSeed(seedState)) return false;
|
|
787
|
+
if (!hasPassingCompletedRalphAudit(completedState, cwd)) return false;
|
|
788
|
+
if (!completedState) return false;
|
|
789
|
+
|
|
790
|
+
const completedSessionId = safeString(ownerContext?.completedSessionId ?? completedState.session_id).trim();
|
|
791
|
+
if (
|
|
792
|
+
completedSessionId
|
|
793
|
+
&& !activeRalphStateMatchesStopOwner(completedState, {
|
|
794
|
+
sessionId: completedSessionId,
|
|
795
|
+
payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
|
|
796
|
+
threadId: safeString(ownerContext?.threadId).trim(),
|
|
797
|
+
currentNativeSessionId: safeString(ownerContext?.currentNativeSessionId).trim(),
|
|
798
|
+
tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
|
|
799
|
+
})
|
|
800
|
+
) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const seedThreadId = safeString(seedState.owner_codex_thread_id ?? seedState.thread_id).trim();
|
|
805
|
+
const completedThreadId = safeString(completedState?.owner_codex_thread_id ?? completedState?.thread_id).trim();
|
|
806
|
+
const stopThreadId = safeString(ownerContext?.threadId).trim();
|
|
807
|
+
if (seedThreadId && completedThreadId && seedThreadId !== completedThreadId) return false;
|
|
808
|
+
if (seedThreadId && stopThreadId && seedThreadId !== stopThreadId) return false;
|
|
809
|
+
if (completedThreadId && stopThreadId && completedThreadId !== stopThreadId) return false;
|
|
810
|
+
|
|
811
|
+
const seedPaneId = safeString(seedState.tmux_pane_id).trim();
|
|
812
|
+
const completedPaneId = safeString(completedState?.tmux_pane_id).trim();
|
|
813
|
+
const stopPaneId = safeString(ownerContext?.tmuxPaneId).trim();
|
|
814
|
+
if (seedPaneId && completedPaneId && seedPaneId !== completedPaneId) return false;
|
|
815
|
+
if (seedPaneId && stopPaneId && seedPaneId !== stopPaneId) return false;
|
|
816
|
+
if (completedPaneId && stopPaneId && completedPaneId !== stopPaneId) return false;
|
|
817
|
+
|
|
818
|
+
const seedStartedAt = parseTimestampMs(seedState.started_at ?? seedState.startedAt);
|
|
819
|
+
const completedAt = parseTimestampMs(completedState?.completed_at ?? completedState?.completedAt);
|
|
820
|
+
if (completedAt === null) return false;
|
|
821
|
+
if (seedStartedAt !== null && seedStartedAt > completedAt) return false;
|
|
822
|
+
|
|
823
|
+
return true;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
async function retireShadowedRalphStartingSeed(
|
|
827
|
+
path: string,
|
|
828
|
+
seedState: Record<string, unknown>,
|
|
829
|
+
completedSessionId: string,
|
|
830
|
+
completedPath: string,
|
|
831
|
+
completedState: Record<string, unknown>,
|
|
832
|
+
): Promise<void> {
|
|
833
|
+
const nowIso = new Date().toISOString();
|
|
834
|
+
const completedAt = safeString(completedState.completed_at ?? completedState.completedAt).trim() || nowIso;
|
|
835
|
+
const next: Record<string, unknown> = {
|
|
836
|
+
...seedState,
|
|
837
|
+
active: false,
|
|
838
|
+
current_phase: "complete",
|
|
839
|
+
completed_at: completedAt,
|
|
840
|
+
stop_reason: "shadowed_by_completed_canonical_ralph",
|
|
841
|
+
shadowed_by_completed_canonical_ralph: {
|
|
842
|
+
session_id: completedSessionId,
|
|
843
|
+
state_path: completedPath,
|
|
844
|
+
completed_at: completedAt,
|
|
845
|
+
reconciled_at: nowIso,
|
|
846
|
+
},
|
|
847
|
+
};
|
|
848
|
+
await writeFile(path, JSON.stringify(next, null, 2));
|
|
849
|
+
}
|
|
850
|
+
|
|
600
851
|
|
|
601
852
|
async function readRalphCompletionAuditBlockState(
|
|
602
853
|
cwd: string,
|
|
@@ -653,13 +904,12 @@ async function reopenRalphCompletionAuditBlock(block: RalphCompletionAuditBlockS
|
|
|
653
904
|
const nowIso = new Date().toISOString();
|
|
654
905
|
const next: Record<string, unknown> = {
|
|
655
906
|
...block.state,
|
|
656
|
-
active:
|
|
657
|
-
current_phase: "
|
|
907
|
+
active: false,
|
|
908
|
+
current_phase: "complete",
|
|
658
909
|
completion_audit_gate: "blocked",
|
|
659
910
|
completion_audit_missing_reason: block.reason,
|
|
660
911
|
completion_audit_blocked_at: nowIso,
|
|
661
912
|
};
|
|
662
|
-
delete next.completed_at;
|
|
663
913
|
await writeFile(block.path, JSON.stringify(next, null, 2));
|
|
664
914
|
}
|
|
665
915
|
|
|
@@ -686,6 +936,12 @@ async function readActiveRalphState(
|
|
|
686
936
|
safeString(preferredSessionId).trim(),
|
|
687
937
|
currentOmxSessionId,
|
|
688
938
|
].filter(Boolean))];
|
|
939
|
+
const completedCanonicalPath = currentOmxSessionId
|
|
940
|
+
? getStateFilePath("ralph-state.json", cwd, currentOmxSessionId)
|
|
941
|
+
: "";
|
|
942
|
+
const completedCanonicalState = completedCanonicalPath
|
|
943
|
+
? await readJsonIfExists(completedCanonicalPath)
|
|
944
|
+
: null;
|
|
689
945
|
|
|
690
946
|
// Ralph Stop stays authoritative-scope-only once the Stop payload is session-bound.
|
|
691
947
|
// That is intentionally stricter than generic state MCP reads: do not scan sibling
|
|
@@ -699,12 +955,37 @@ async function readActiveRalphState(
|
|
|
699
955
|
}
|
|
700
956
|
const sessionScopedPath = getStateFilePath("ralph-state.json", cwd, sessionId);
|
|
701
957
|
const sessionScoped = await readJsonIfExists(sessionScopedPath);
|
|
702
|
-
if (
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
958
|
+
if (sessionScoped?.active === true) {
|
|
959
|
+
if (
|
|
960
|
+
currentOmxSessionId
|
|
961
|
+
&& sessionId !== currentOmxSessionId
|
|
962
|
+
&& completedCanonicalState
|
|
963
|
+
&& shouldRetireShadowedRalphStartingSeed(sessionScoped, completedCanonicalState, cwd, {
|
|
964
|
+
completedSessionId: currentOmxSessionId,
|
|
965
|
+
payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
|
|
966
|
+
threadId: safeString(ownerContext?.threadId).trim(),
|
|
967
|
+
currentNativeSessionId,
|
|
968
|
+
tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
|
|
969
|
+
})
|
|
970
|
+
) {
|
|
971
|
+
await retireShadowedRalphStartingSeed(
|
|
972
|
+
sessionScopedPath,
|
|
973
|
+
sessionScoped,
|
|
974
|
+
currentOmxSessionId,
|
|
975
|
+
completedCanonicalPath,
|
|
976
|
+
completedCanonicalState,
|
|
977
|
+
);
|
|
978
|
+
continue;
|
|
979
|
+
}
|
|
980
|
+
if (await isStaleOrphanedRalphStartingState(sessionScoped, sessionScopedPath)) {
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
if (
|
|
984
|
+
isRalphStartingPhase(sessionScoped)
|
|
985
|
+
&& !(await isVisibleRalphActiveForSession(stateDir, sessionId))
|
|
986
|
+
) {
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
708
989
|
}
|
|
709
990
|
if (
|
|
710
991
|
sessionScoped?.active === true
|
|
@@ -1433,7 +1714,7 @@ function buildAdditionalContextMessage(
|
|
|
1433
1714
|
? "Ultrawork protocol: ground the task before editing, define pass/fail acceptance criteria, keep shared-file work local, and use direct-tool plus background evidence lanes only for truly independent work. Direct ultrawork provides lightweight verification only; Ralph owns persistence and the full verified-completion promise."
|
|
1434
1715
|
: null;
|
|
1435
1716
|
const ultragoalPromptActivationNote = match.skill === "ultragoal"
|
|
1436
|
-
? "Ultragoal protocol: use `omx ultragoal create-goals` / `complete-goals` / `checkpoint` for `.omx/ultragoal` artifacts, then use Codex goal model tools only from the active agent handoff (`get_goal`, `create_goal`, `update_goal`) and never overwrite a different active Codex goal."
|
|
1717
|
+
? "Ultragoal protocol: use `omx ultragoal create-goals` / `complete-goals` / `checkpoint` for `.omx/ultragoal` artifacts, then use Codex goal model tools only from the active agent handoff (`get_goal`, `create_goal`, `update_goal`) and never overwrite a different active Codex goal. Ultragoal does not call `/goal clear`; for multiple sequential ultragoal runs in one Codex session/thread, manually clear the completed Codex goal in the UI before creating the next aggregate goal."
|
|
1437
1718
|
: null;
|
|
1438
1719
|
const combinedTransitionMessage = (() => {
|
|
1439
1720
|
if (!skillState?.transition_message) return null;
|
|
@@ -1696,14 +1977,20 @@ async function buildModeBasedStopOutput(
|
|
|
1696
1977
|
cwd: string,
|
|
1697
1978
|
sessionId?: string,
|
|
1698
1979
|
): Promise<Record<string, unknown> | null> {
|
|
1980
|
+
if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, mode)) {
|
|
1981
|
+
return null;
|
|
1982
|
+
}
|
|
1699
1983
|
const state = await readModeStateForActiveDecision(mode, sessionId?.trim() || undefined, cwd);
|
|
1700
1984
|
if (!state || !shouldContinueRun(state)) return null;
|
|
1701
1985
|
const phase = formatPhase(state.current_phase);
|
|
1986
|
+
const systemMessage = mode === "autopilot" && phase.toLowerCase().replace(/_/g, "-") === "code-review"
|
|
1987
|
+
? "OMX autopilot is still active (phase: code-review). Run the required $code-review step before completing or clearing Autopilot state."
|
|
1988
|
+
: `OMX ${mode} is still active (phase: ${phase}).`;
|
|
1702
1989
|
return {
|
|
1703
1990
|
decision: "block",
|
|
1704
1991
|
reason: `OMX ${mode} is still active (phase: ${phase}); continue the task and gather fresh verification evidence before stopping.`,
|
|
1705
1992
|
stopReason: `${mode}_${phase}`,
|
|
1706
|
-
systemMessage
|
|
1993
|
+
systemMessage,
|
|
1707
1994
|
};
|
|
1708
1995
|
}
|
|
1709
1996
|
|
|
@@ -1715,6 +2002,28 @@ export function looksLikeGoalCompletionPrompt(text: string): boolean {
|
|
|
1715
2002
|
|| /(?:^|[.!?]\s+)(?:the\s+)?goal\s+(?:is\s+|now\s+|has\s+been\s+)?(?:complete|completed|finished|closed)(?:\s*(?:[.!?]|$)|\s*[:;]\s*\S|\s*[—–-]\s*\S)/i.test(text);
|
|
1716
2003
|
}
|
|
1717
2004
|
|
|
2005
|
+
function reportsAutoresearchGoalObjectiveMismatch(text: string): boolean {
|
|
2006
|
+
return /\bautoresearch[-\s]goal\b/i.test(text)
|
|
2007
|
+
&& /\b(?:complete|completion|reconciliation)\b/i.test(text)
|
|
2008
|
+
&& /objective mismatch/i.test(text);
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
function reportsBlockedPerformanceGoalObjectiveMismatch(state: unknown): boolean {
|
|
2012
|
+
const performanceState = safeObject(state);
|
|
2013
|
+
const lastValidation = safeObject(performanceState.lastValidation);
|
|
2014
|
+
if (safeString(performanceState.workflow) !== "performance-goal") return false;
|
|
2015
|
+
if (safeString(performanceState.status) !== "blocked") return false;
|
|
2016
|
+
if (safeString(lastValidation.status) !== "blocked") return false;
|
|
2017
|
+
|
|
2018
|
+
const evidence = [
|
|
2019
|
+
safeString(lastValidation.evidence),
|
|
2020
|
+
safeString(lastValidation.message),
|
|
2021
|
+
safeString(performanceState.evidence),
|
|
2022
|
+
safeString(performanceState.message),
|
|
2023
|
+
].join(" ");
|
|
2024
|
+
return /objective mismatch/i.test(evidence);
|
|
2025
|
+
}
|
|
2026
|
+
|
|
1718
2027
|
async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Promise<{ workflow: string; command: string; remediation?: string } | null> {
|
|
1719
2028
|
const ultragoal = await readJsonIfExists(join(cwd, ".omx", "ultragoal", "goals.json"));
|
|
1720
2029
|
const aggregateCompletion = safeObject(ultragoal?.aggregateCompletion);
|
|
@@ -1732,7 +2041,7 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Pro
|
|
|
1732
2041
|
`If get_goal returns a completed task-scoped objective for the same aggregate ultragoal plan, checkpoint ${goalId} with evidence naming ${goalId} plus .omx/ultragoal/goals.json or ledger.jsonl and pass final quality-gate JSON; OMX will reconcile the completed planned scope without mutating Codex goal state.`,
|
|
1733
2042
|
`If get_goal instead returns a different completed legacy objective and complete checkpointing fails, do not repeat --status complete in this thread.`,
|
|
1734
2043
|
`Record the non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<different completed get_goal JSON or path>' --evidence '<completed legacy Codex goal blocks create_goal in this thread>'.`,
|
|
1735
|
-
"Then continue
|
|
2044
|
+
"Then continue only from a Codex goal context with no active/completed conflicting goal in the same repo/worktree and create the intended goal there.",
|
|
1736
2045
|
].join(" "),
|
|
1737
2046
|
};
|
|
1738
2047
|
}
|
|
@@ -1742,6 +2051,9 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Pro
|
|
|
1742
2051
|
if (!entry.isDirectory()) continue;
|
|
1743
2052
|
const state = await readJsonIfExists(join(performanceRoot, entry.name, "state.json"));
|
|
1744
2053
|
const status = safeString(state?.status);
|
|
2054
|
+
if (reportsBlockedPerformanceGoalObjectiveMismatch(state)) {
|
|
2055
|
+
continue;
|
|
2056
|
+
}
|
|
1745
2057
|
if (state?.workflow === "performance-goal" && status && status !== "complete") {
|
|
1746
2058
|
return {
|
|
1747
2059
|
workflow: "performance-goal",
|
|
@@ -1758,10 +2070,19 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Pro
|
|
|
1758
2070
|
const completion = await readJsonIfExists(join(autoresearchRoot, entry.name, "completion.json"));
|
|
1759
2071
|
const completionVerdict = safeString(completion?.verdict);
|
|
1760
2072
|
const completionPassed = completion?.passed === true || completionVerdict === "pass";
|
|
1761
|
-
if (
|
|
2073
|
+
if (
|
|
2074
|
+
mission?.workflow === "autoresearch-goal"
|
|
2075
|
+
&& status
|
|
2076
|
+
&& status !== "complete"
|
|
2077
|
+
&& completionPassed
|
|
2078
|
+
) {
|
|
1762
2079
|
return {
|
|
1763
2080
|
workflow: "autoresearch-goal",
|
|
1764
2081
|
command: `omx autoresearch-goal complete --slug ${safeString(mission.slug) || entry.name} --codex-goal-json '<get_goal JSON or path>'`,
|
|
2082
|
+
remediation: [
|
|
2083
|
+
"If that command fails with a Codex goal objective mismatch after a refreshed get_goal snapshot, do not repeat the same complete command blindly in this thread.",
|
|
2084
|
+
"Either retry with a correct refreshed snapshot or record an explicit blocked verdict for this autoresearch-goal and continue from the explicit blocker path.",
|
|
2085
|
+
].join(" "),
|
|
1765
2086
|
};
|
|
1766
2087
|
}
|
|
1767
2088
|
}
|
|
@@ -1789,6 +2110,9 @@ async function buildGoalWorkflowReconciliationStopOutput(
|
|
|
1789
2110
|
if (!looksLikeGoalCompletionPrompt(lastAssistantMessage)) return null;
|
|
1790
2111
|
const requirement = await findActiveGoalWorkflowReconciliationRequirement(cwd);
|
|
1791
2112
|
if (!requirement) return null;
|
|
2113
|
+
if (requirement.workflow === "autoresearch-goal" && reportsAutoresearchGoalObjectiveMismatch(lastAssistantMessage)) {
|
|
2114
|
+
return null;
|
|
2115
|
+
}
|
|
1792
2116
|
const systemMessage =
|
|
1793
2117
|
[
|
|
1794
2118
|
`OMX ${requirement.workflow} requires get_goal snapshot reconciliation before completion; call get_goal and pass --codex-goal-json to ${requirement.command}.`,
|
|
@@ -1914,7 +2238,7 @@ function readPayloadSessionId(payload: CodexHookPayload): string {
|
|
|
1914
2238
|
}
|
|
1915
2239
|
|
|
1916
2240
|
function readPayloadThreadId(payload: CodexHookPayload): string {
|
|
1917
|
-
return safeString(payload.thread_id ?? payload.threadId).trim();
|
|
2241
|
+
return safeString(payload.owner_codex_thread_id ?? payload.thread_id ?? payload.threadId).trim();
|
|
1918
2242
|
}
|
|
1919
2243
|
|
|
1920
2244
|
function readPayloadTurnId(payload: CodexHookPayload): string {
|
|
@@ -2017,6 +2341,14 @@ async function readBlockingSkillForStop(
|
|
|
2017
2341
|
const modeSnapshot = getRunContinuationSnapshot(modeState);
|
|
2018
2342
|
if (modeSnapshot?.terminal === true) continue;
|
|
2019
2343
|
|
|
2344
|
+
if (await shouldIgnoreSessionSkillBlockerForCanonicalInactiveRoot(
|
|
2345
|
+
cwd,
|
|
2346
|
+
stateDir,
|
|
2347
|
+
skill,
|
|
2348
|
+
sessionId,
|
|
2349
|
+
threadId,
|
|
2350
|
+
)) continue;
|
|
2351
|
+
|
|
2020
2352
|
const phase = formatPhase(
|
|
2021
2353
|
modeState.current_phase,
|
|
2022
2354
|
formatPhase(
|
|
@@ -2068,6 +2400,58 @@ function isTerminalOrInactiveModeState(state: Record<string, unknown> | null): b
|
|
|
2068
2400
|
return phase !== "" && TERMINAL_MODE_PHASES.has(phase);
|
|
2069
2401
|
}
|
|
2070
2402
|
|
|
2403
|
+
function rootSkillStateHasNoActiveSkillForStopContext(
|
|
2404
|
+
rootState: SkillActiveStateLike | null,
|
|
2405
|
+
skill: string,
|
|
2406
|
+
sessionId: string,
|
|
2407
|
+
threadId: string,
|
|
2408
|
+
): boolean {
|
|
2409
|
+
if (!rootState) return false;
|
|
2410
|
+
return !listActiveSkills(rootState).some((entry) => (
|
|
2411
|
+
entry.skill === skill
|
|
2412
|
+
&& matchesSkillStopContext(entry, rootState, sessionId, threadId)
|
|
2413
|
+
));
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
function rootModeStateIsCanonicalForStopContext(
|
|
2417
|
+
state: Record<string, unknown>,
|
|
2418
|
+
cwd: string,
|
|
2419
|
+
sessionId: string,
|
|
2420
|
+
threadId: string,
|
|
2421
|
+
): boolean {
|
|
2422
|
+
if (!modeStateMatchesSkillStopContext(state, cwd, sessionId)) return false;
|
|
2423
|
+
|
|
2424
|
+
const stateSessionId = safeString(
|
|
2425
|
+
state.owner_omx_session_id
|
|
2426
|
+
?? state.session_id
|
|
2427
|
+
?? state.codex_session_id
|
|
2428
|
+
?? state.owner_codex_session_id,
|
|
2429
|
+
).trim();
|
|
2430
|
+
if (sessionId && stateSessionId !== sessionId) return false;
|
|
2431
|
+
|
|
2432
|
+
const stateThreadId = safeString(state.owner_codex_thread_id ?? state.thread_id).trim();
|
|
2433
|
+
if (threadId && stateThreadId && stateThreadId !== threadId) return false;
|
|
2434
|
+
|
|
2435
|
+
return true;
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
async function shouldIgnoreSessionSkillBlockerForCanonicalInactiveRoot(
|
|
2439
|
+
cwd: string,
|
|
2440
|
+
stateDir: string,
|
|
2441
|
+
skill: string,
|
|
2442
|
+
sessionId: string,
|
|
2443
|
+
threadId: string,
|
|
2444
|
+
): Promise<boolean> {
|
|
2445
|
+
const rootModeState = await readJsonIfExists(join(stateDir, `${skill}-state.json`));
|
|
2446
|
+
if (!rootModeState) return false;
|
|
2447
|
+
if (!rootModeStateIsCanonicalForStopContext(rootModeState, cwd, sessionId, threadId)) return false;
|
|
2448
|
+
if (!isTerminalOrInactiveModeState(rootModeState)) return false;
|
|
2449
|
+
|
|
2450
|
+
const { rootPath } = getSkillActiveStatePathsForStateDir(stateDir);
|
|
2451
|
+
const rootSkillState = await readSkillActiveState(rootPath);
|
|
2452
|
+
return rootSkillStateHasNoActiveSkillForStopContext(rootSkillState, skill, sessionId, threadId);
|
|
2453
|
+
}
|
|
2454
|
+
|
|
2071
2455
|
async function readSessionScopedModeStateForRootSkill(
|
|
2072
2456
|
cwd: string,
|
|
2073
2457
|
stateDir: string,
|
|
@@ -2788,7 +3172,7 @@ async function buildStopHookOutput(
|
|
|
2788
3172
|
`OMX Ralph completion audit is missing required evidence (${ralphCompletionAuditBlock.reason}; state: ${blockingPath}).`,
|
|
2789
3173
|
"Continue verification and do not report complete yet.",
|
|
2790
3174
|
"Record machine-readable completion evidence before stopping:",
|
|
2791
|
-
|
|
3175
|
+
'- either set "completion_audit" on the Ralph state object, for example: omx state write --input \'{"mode":"ralph","active":false,"current_phase":"complete","completion_audit":{"passed":true,"prompt_to_artifact_checklist":["..."],"verification_evidence":["..."]}}\' --json',
|
|
2792
3176
|
"- or set completion_audit_path / completion_audit_evidence_path to a repo-relative JSON file with those same fields.",
|
|
2793
3177
|
"Markdown artifacts and flat top-level checklist/evidence fields are not accepted by the Ralph Stop gate.",
|
|
2794
3178
|
].join(" ");
|
|
@@ -3085,6 +3469,7 @@ export async function dispatchCodexNativeHook(
|
|
|
3085
3469
|
let skillState: SkillActiveState | null = null;
|
|
3086
3470
|
let triageAdditionalContext: string | null = null;
|
|
3087
3471
|
let goalWorkflowAdditionalContext: string | null = null;
|
|
3472
|
+
let ultragoalSteeringAdditionalContext: string | null = null;
|
|
3088
3473
|
|
|
3089
3474
|
const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
|
|
3090
3475
|
const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
|
|
@@ -3093,11 +3478,13 @@ export async function dispatchCodexNativeHook(
|
|
|
3093
3478
|
let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
3094
3479
|
let resolvedNativeSessionId = nativeSessionId;
|
|
3095
3480
|
let skipCanonicalSessionStartContext = false;
|
|
3481
|
+
let isSubagentSessionStart = false;
|
|
3096
3482
|
|
|
3097
3483
|
if (hookEventName === "SessionStart" && nativeSessionId) {
|
|
3098
3484
|
const transcriptPath = safeString(payload.transcript_path ?? payload.transcriptPath).trim();
|
|
3099
3485
|
const subagentSessionStart = readNativeSubagentSessionStartMetadata(transcriptPath);
|
|
3100
3486
|
if (subagentSessionStart && canonicalSessionId) {
|
|
3487
|
+
isSubagentSessionStart = true;
|
|
3101
3488
|
const belongsToCanonicalSession = await nativeSubagentSessionStartBelongsToCanonicalSession(
|
|
3102
3489
|
cwd,
|
|
3103
3490
|
canonicalSessionId,
|
|
@@ -3166,10 +3553,16 @@ export async function dispatchCodexNativeHook(
|
|
|
3166
3553
|
.map((candidateSessionId) => isNativeSubagentHook(cwd, candidateSessionId, nativeSessionId, threadId)),
|
|
3167
3554
|
)).some(Boolean)
|
|
3168
3555
|
: false;
|
|
3556
|
+
const suppressNoisySubagentLifecycleDispatch =
|
|
3557
|
+
(isSubagentSessionStart || isSubagentStop)
|
|
3558
|
+
&& shouldSuppressSubagentLifecycleHookDispatch();
|
|
3169
3559
|
|
|
3170
3560
|
if (hookEventName === "UserPromptSubmit") {
|
|
3171
3561
|
const prompt = readPromptText(payload);
|
|
3172
3562
|
goalWorkflowAdditionalContext = await buildGoalWorkflowReconciliationPromptWarning(cwd, prompt).catch(() => null);
|
|
3563
|
+
ultragoalSteeringAdditionalContext = prompt && !isSubagentPromptSubmit
|
|
3564
|
+
? await applyUserPromptUltragoalSteering(cwd, prompt).catch((error) => `OMX native UserPromptSubmit rejected bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${error instanceof Error ? error.message : String(error)}`)
|
|
3565
|
+
: null;
|
|
3173
3566
|
if (prompt && !isSubagentPromptSubmit) {
|
|
3174
3567
|
skillState = buildNativeOutsideTmuxTeamPromptBlockState(
|
|
3175
3568
|
prompt,
|
|
@@ -3261,7 +3654,7 @@ export async function dispatchCodexNativeHook(
|
|
|
3261
3654
|
await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => {});
|
|
3262
3655
|
}
|
|
3263
3656
|
|
|
3264
|
-
if (omxEventName && !skipCanonicalSessionStartContext) {
|
|
3657
|
+
if (omxEventName && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
|
|
3265
3658
|
const baseContext = buildBaseContext(cwd, payload, hookEventName!, canonicalSessionId);
|
|
3266
3659
|
if (resolvedNativeSessionId) {
|
|
3267
3660
|
baseContext.native_session_id = resolvedNativeSessionId;
|
|
@@ -3302,7 +3695,12 @@ export async function dispatchCodexNativeHook(
|
|
|
3302
3695
|
})
|
|
3303
3696
|
: isSubagentPromptSubmit
|
|
3304
3697
|
? null
|
|
3305
|
-
:
|
|
3698
|
+
: [
|
|
3699
|
+
buildAdditionalContextMessage(readPromptText(payload), skillState, cwd, payload),
|
|
3700
|
+
ultragoalSteeringAdditionalContext,
|
|
3701
|
+
goalWorkflowAdditionalContext,
|
|
3702
|
+
triageAdditionalContext,
|
|
3703
|
+
].filter((entry): entry is string => Boolean(entry)).join("\n\n") || null;
|
|
3306
3704
|
if (additionalContext) {
|
|
3307
3705
|
outputJson = {
|
|
3308
3706
|
hookSpecificOutput: {
|