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";
|
|
@@ -20,12 +20,14 @@ import { maybeNudgeLeaderForAllowedWorkerStop } from "./notify-hook/team-worker-
|
|
|
20
20
|
import { resolveCodexExecutionSurface, } from "./codex-execution-surface.js";
|
|
21
21
|
import { buildNativeHookEvent, } from "../hooks/extensibility/events.js";
|
|
22
22
|
import { dispatchHookEventRuntime } from "../hooks/extensibility/runtime.js";
|
|
23
|
+
import { getNotificationConfig, getVerbosity } from "../notifications/config.js";
|
|
23
24
|
import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
|
|
24
25
|
import { onPreCompact as buildWikiPreCompactContext, onSessionStart as buildWikiSessionStartContext, } from "../wiki/lifecycle.js";
|
|
25
26
|
import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
|
|
26
27
|
import { readRunState } from "../runtime/run-state.js";
|
|
27
28
|
import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
|
|
28
29
|
import { getRunContinuationSnapshot, shouldContinueRun } from "../runtime/run-loop.js";
|
|
30
|
+
import { parseUltragoalSteeringDirective, steerUltragoal, } from "../ultragoal/artifacts.js";
|
|
29
31
|
import { triagePrompt } from "../hooks/triage-heuristic.js";
|
|
30
32
|
import { readTriageConfig } from "../hooks/triage-config.js";
|
|
31
33
|
import { readTriageState, writeTriageState, shouldSuppressFollowup, promptSignature, } from "../hooks/triage-state.js";
|
|
@@ -38,6 +40,7 @@ const TEAM_STOP_BLOCKING_TASK_STATUSES = new Set(["pending", "in_progress", "blo
|
|
|
38
40
|
const TEAM_WORKER_TERMINAL_RUN_STATES = new Set(["done", "complete", "completed", "failed", "stopped", "cancelled"]);
|
|
39
41
|
const NATIVE_STOP_STATE_FILE = "native-stop-state.json";
|
|
40
42
|
const ORDINARY_STOP_NO_PROGRESS_DEFAULT_MAX_REPEATS = 8;
|
|
43
|
+
const RALPH_ORPHANED_STARTING_STALE_MS = 15 * 60_000;
|
|
41
44
|
const ORDINARY_STOP_NO_PROGRESS_DEFAULT_IDLE_MS = 10 * 60_000;
|
|
42
45
|
const ORDINARY_STOP_NO_PROGRESS_MAX_MESSAGE_LENGTH = 240;
|
|
43
46
|
const STABLE_FINAL_RECOMMENDATION_PATTERNS = [
|
|
@@ -185,6 +188,13 @@ async function isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, th
|
|
|
185
188
|
return false;
|
|
186
189
|
return candidateIds.some((id) => summary.allSubagentThreadIds.includes(id));
|
|
187
190
|
}
|
|
191
|
+
function shouldSuppressSubagentLifecycleHookDispatch() {
|
|
192
|
+
const config = getNotificationConfig();
|
|
193
|
+
if (config?.includeChildAgents === true)
|
|
194
|
+
return false;
|
|
195
|
+
const verbosity = getVerbosity(config);
|
|
196
|
+
return verbosity !== "agent" && verbosity !== "verbose";
|
|
197
|
+
}
|
|
188
198
|
async function recordIgnoredNativeSubagentSessionStart(cwd, canonicalSessionId, childSessionId, metadata, transcriptPath) {
|
|
189
199
|
await appendToLog(cwd, {
|
|
190
200
|
event: "subagent_session_start_ignored",
|
|
@@ -285,6 +295,110 @@ function readPromptText(payload) {
|
|
|
285
295
|
}
|
|
286
296
|
return "";
|
|
287
297
|
}
|
|
298
|
+
function extractBalancedJsonObject(text, startIndex) {
|
|
299
|
+
let depth = 0;
|
|
300
|
+
let inString = false;
|
|
301
|
+
let escaped = false;
|
|
302
|
+
for (let index = startIndex; index < text.length; index++) {
|
|
303
|
+
const char = text[index];
|
|
304
|
+
if (inString) {
|
|
305
|
+
if (escaped)
|
|
306
|
+
escaped = false;
|
|
307
|
+
else if (char === "\\")
|
|
308
|
+
escaped = true;
|
|
309
|
+
else if (char === '"')
|
|
310
|
+
inString = false;
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (char === '"') {
|
|
314
|
+
inString = true;
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (char === "{")
|
|
318
|
+
depth += 1;
|
|
319
|
+
else if (char === "}") {
|
|
320
|
+
depth -= 1;
|
|
321
|
+
if (depth === 0)
|
|
322
|
+
return text.slice(startIndex, index + 1);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
function normalizePromptSteeringProposal(raw, prompt) {
|
|
328
|
+
const candidate = safeObject(raw);
|
|
329
|
+
const nested = candidate.omx_ultragoal_steer ?? candidate.ultragoal_steer ?? candidate.steering ?? candidate;
|
|
330
|
+
const proposal = parseUltragoalSteeringDirective(JSON.stringify(nested));
|
|
331
|
+
if (!proposal)
|
|
332
|
+
return null;
|
|
333
|
+
if (proposal.source !== "user_prompt_submit")
|
|
334
|
+
return null;
|
|
335
|
+
const normalized = prompt.trim().toLowerCase();
|
|
336
|
+
return {
|
|
337
|
+
...proposal,
|
|
338
|
+
directiveText: proposal.directiveText ?? safeContextSnippet(prompt, 600),
|
|
339
|
+
promptSignature: proposal.promptSignature ?? promptSignature(normalized),
|
|
340
|
+
idempotencyKey: proposal.idempotencyKey ?? `user_prompt_submit:${promptSignature(normalized)}`,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function parseUserPromptUltragoalSteeringDirective(prompt) {
|
|
344
|
+
const trimmed = prompt.trim();
|
|
345
|
+
if (!trimmed)
|
|
346
|
+
return null;
|
|
347
|
+
const fenced = trimmed.match(/```(?:omx-ultragoal-steer|ultragoal-steer)\s*([\s\S]*?)```/i);
|
|
348
|
+
if (fenced?.[1]) {
|
|
349
|
+
try {
|
|
350
|
+
return normalizePromptSteeringProposal(JSON.parse(fenced[1]), prompt);
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const label = trimmed.match(/(?:^|\n)\s*(?:OMX_ULTRAGOAL_STEER|omx\.ultragoal\.steer|omx ultragoal steer)\s*:\s*{/i);
|
|
357
|
+
if (label?.index !== undefined) {
|
|
358
|
+
const brace = trimmed.indexOf("{", label.index);
|
|
359
|
+
const json = brace >= 0 ? extractBalancedJsonObject(trimmed, brace) : null;
|
|
360
|
+
if (json) {
|
|
361
|
+
try {
|
|
362
|
+
return normalizePromptSteeringProposal(JSON.parse(json), prompt);
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (trimmed.startsWith("{")) {
|
|
370
|
+
try {
|
|
371
|
+
const parsed = JSON.parse(trimmed);
|
|
372
|
+
const object = safeObject(parsed);
|
|
373
|
+
if ("omx_ultragoal_steer" in object || "ultragoal_steer" in object) {
|
|
374
|
+
return normalizePromptSteeringProposal(parsed, prompt);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
async function applyUserPromptUltragoalSteering(cwd, prompt) {
|
|
384
|
+
const proposal = parseUserPromptUltragoalSteeringDirective(prompt);
|
|
385
|
+
if (!proposal)
|
|
386
|
+
return null;
|
|
387
|
+
try {
|
|
388
|
+
const result = await steerUltragoal(cwd, proposal);
|
|
389
|
+
const status = result.deduped ? "deduped" : result.accepted ? "accepted" : "rejected";
|
|
390
|
+
const reasons = result.rejectedReasons.length > 0 ? ` rejectedReasons=${result.rejectedReasons.join("; ")}` : "";
|
|
391
|
+
return [
|
|
392
|
+
`OMX native UserPromptSubmit applied bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${status}.`,
|
|
393
|
+
`mutation=${result.audit.kind}; source=${result.audit.source}; targets=${result.audit.targetGoalIds.join(",") || "none"}; idempotencyKey=${result.audit.idempotencyKey ?? "none"}.${reasons}`,
|
|
394
|
+
"Only explicit structured steering directives are parsed; normal prose is ignored and cannot mutate .omx/ultragoal.",
|
|
395
|
+
].join(" ");
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
399
|
+
return `OMX native UserPromptSubmit rejected bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${message}`;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
288
402
|
function sanitizePayloadForHookContext(payload, hookEventName, canonicalSessionId = "") {
|
|
289
403
|
const sanitized = { ...payload };
|
|
290
404
|
if (hookEventName === "UserPromptSubmit") {
|
|
@@ -344,6 +458,47 @@ async function readActiveAutoresearchState(cwd, sessionId) {
|
|
|
344
458
|
function isRalphStartingPhase(state) {
|
|
345
459
|
return safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase() === "starting";
|
|
346
460
|
}
|
|
461
|
+
function parseTimestampMs(value) {
|
|
462
|
+
const text = safeString(value).trim();
|
|
463
|
+
if (!text)
|
|
464
|
+
return null;
|
|
465
|
+
const ms = Date.parse(text);
|
|
466
|
+
return Number.isFinite(ms) ? ms : null;
|
|
467
|
+
}
|
|
468
|
+
function numericValue(value) {
|
|
469
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
470
|
+
return value;
|
|
471
|
+
if (typeof value === "string" && value.trim()) {
|
|
472
|
+
const parsed = Number(value);
|
|
473
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
474
|
+
}
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
function hasRalphOwnerHint(state) {
|
|
478
|
+
return [
|
|
479
|
+
state.owner_omx_session_id,
|
|
480
|
+
state.owner_codex_session_id,
|
|
481
|
+
state.owner_codex_thread_id,
|
|
482
|
+
state.thread_id,
|
|
483
|
+
state.tmux_pane_id,
|
|
484
|
+
state.task_slug,
|
|
485
|
+
].some((value) => safeString(value).trim() !== "");
|
|
486
|
+
}
|
|
487
|
+
async function isStaleOrphanedRalphStartingState(state, path, nowMs = Date.now()) {
|
|
488
|
+
if (!isRalphStartingPhase(state))
|
|
489
|
+
return false;
|
|
490
|
+
if (numericValue(state.iteration) !== 0)
|
|
491
|
+
return false;
|
|
492
|
+
if (hasRalphOwnerHint(state))
|
|
493
|
+
return false;
|
|
494
|
+
const timestampMs = parseTimestampMs(state.updated_at)
|
|
495
|
+
?? parseTimestampMs(state.started_at)
|
|
496
|
+
?? parseTimestampMs(state.created_at)
|
|
497
|
+
?? await stat(path).then((info) => info.mtimeMs, () => null);
|
|
498
|
+
if (timestampMs === null)
|
|
499
|
+
return false;
|
|
500
|
+
return nowMs - timestampMs > RALPH_ORPHANED_STARTING_STALE_MS;
|
|
501
|
+
}
|
|
347
502
|
function hasValue(values, value) {
|
|
348
503
|
return value !== "" && values.some((candidate) => candidate === value);
|
|
349
504
|
}
|
|
@@ -410,6 +565,89 @@ async function hasConsistentRalphSkillActivation(stateDir, sessionId) {
|
|
|
410
565
|
return false;
|
|
411
566
|
return true;
|
|
412
567
|
}
|
|
568
|
+
function isShadowableRalphStartingSeed(state) {
|
|
569
|
+
if (state.active !== true)
|
|
570
|
+
return false;
|
|
571
|
+
if (!isRalphStartingPhase(state))
|
|
572
|
+
return false;
|
|
573
|
+
if (state.completion_audit || state.completionAudit)
|
|
574
|
+
return false;
|
|
575
|
+
const iteration = numericValue(state.iteration);
|
|
576
|
+
return iteration === null || iteration <= 0;
|
|
577
|
+
}
|
|
578
|
+
function hasPassingCompletedRalphAudit(state, cwd) {
|
|
579
|
+
if (!state)
|
|
580
|
+
return false;
|
|
581
|
+
if (state.mode && safeString(state.mode) !== "ralph")
|
|
582
|
+
return false;
|
|
583
|
+
if (!isRalphCompletePhase(state.current_phase ?? state.currentPhase))
|
|
584
|
+
return false;
|
|
585
|
+
if (state.active === true)
|
|
586
|
+
return false;
|
|
587
|
+
return evaluateRalphCompletionAuditEvidence(state, cwd).complete === true;
|
|
588
|
+
}
|
|
589
|
+
function shouldRetireShadowedRalphStartingSeed(seedState, completedState, cwd, ownerContext) {
|
|
590
|
+
if (!isShadowableRalphStartingSeed(seedState))
|
|
591
|
+
return false;
|
|
592
|
+
if (!hasPassingCompletedRalphAudit(completedState, cwd))
|
|
593
|
+
return false;
|
|
594
|
+
if (!completedState)
|
|
595
|
+
return false;
|
|
596
|
+
const completedSessionId = safeString(ownerContext?.completedSessionId ?? completedState.session_id).trim();
|
|
597
|
+
if (completedSessionId
|
|
598
|
+
&& !activeRalphStateMatchesStopOwner(completedState, {
|
|
599
|
+
sessionId: completedSessionId,
|
|
600
|
+
payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
|
|
601
|
+
threadId: safeString(ownerContext?.threadId).trim(),
|
|
602
|
+
currentNativeSessionId: safeString(ownerContext?.currentNativeSessionId).trim(),
|
|
603
|
+
tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
|
|
604
|
+
})) {
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
const seedThreadId = safeString(seedState.owner_codex_thread_id ?? seedState.thread_id).trim();
|
|
608
|
+
const completedThreadId = safeString(completedState?.owner_codex_thread_id ?? completedState?.thread_id).trim();
|
|
609
|
+
const stopThreadId = safeString(ownerContext?.threadId).trim();
|
|
610
|
+
if (seedThreadId && completedThreadId && seedThreadId !== completedThreadId)
|
|
611
|
+
return false;
|
|
612
|
+
if (seedThreadId && stopThreadId && seedThreadId !== stopThreadId)
|
|
613
|
+
return false;
|
|
614
|
+
if (completedThreadId && stopThreadId && completedThreadId !== stopThreadId)
|
|
615
|
+
return false;
|
|
616
|
+
const seedPaneId = safeString(seedState.tmux_pane_id).trim();
|
|
617
|
+
const completedPaneId = safeString(completedState?.tmux_pane_id).trim();
|
|
618
|
+
const stopPaneId = safeString(ownerContext?.tmuxPaneId).trim();
|
|
619
|
+
if (seedPaneId && completedPaneId && seedPaneId !== completedPaneId)
|
|
620
|
+
return false;
|
|
621
|
+
if (seedPaneId && stopPaneId && seedPaneId !== stopPaneId)
|
|
622
|
+
return false;
|
|
623
|
+
if (completedPaneId && stopPaneId && completedPaneId !== stopPaneId)
|
|
624
|
+
return false;
|
|
625
|
+
const seedStartedAt = parseTimestampMs(seedState.started_at ?? seedState.startedAt);
|
|
626
|
+
const completedAt = parseTimestampMs(completedState?.completed_at ?? completedState?.completedAt);
|
|
627
|
+
if (completedAt === null)
|
|
628
|
+
return false;
|
|
629
|
+
if (seedStartedAt !== null && seedStartedAt > completedAt)
|
|
630
|
+
return false;
|
|
631
|
+
return true;
|
|
632
|
+
}
|
|
633
|
+
async function retireShadowedRalphStartingSeed(path, seedState, completedSessionId, completedPath, completedState) {
|
|
634
|
+
const nowIso = new Date().toISOString();
|
|
635
|
+
const completedAt = safeString(completedState.completed_at ?? completedState.completedAt).trim() || nowIso;
|
|
636
|
+
const next = {
|
|
637
|
+
...seedState,
|
|
638
|
+
active: false,
|
|
639
|
+
current_phase: "complete",
|
|
640
|
+
completed_at: completedAt,
|
|
641
|
+
stop_reason: "shadowed_by_completed_canonical_ralph",
|
|
642
|
+
shadowed_by_completed_canonical_ralph: {
|
|
643
|
+
session_id: completedSessionId,
|
|
644
|
+
state_path: completedPath,
|
|
645
|
+
completed_at: completedAt,
|
|
646
|
+
reconciled_at: nowIso,
|
|
647
|
+
},
|
|
648
|
+
};
|
|
649
|
+
await writeFile(path, JSON.stringify(next, null, 2));
|
|
650
|
+
}
|
|
413
651
|
async function readRalphCompletionAuditBlockState(cwd, stateDir, preferredSessionId, ownerContext) {
|
|
414
652
|
const [rawSessionInfo, usableSessionInfo] = await Promise.all([
|
|
415
653
|
readSessionState(cwd),
|
|
@@ -457,13 +695,12 @@ async function reopenRalphCompletionAuditBlock(block) {
|
|
|
457
695
|
const nowIso = new Date().toISOString();
|
|
458
696
|
const next = {
|
|
459
697
|
...block.state,
|
|
460
|
-
active:
|
|
461
|
-
current_phase: "
|
|
698
|
+
active: false,
|
|
699
|
+
current_phase: "complete",
|
|
462
700
|
completion_audit_gate: "blocked",
|
|
463
701
|
completion_audit_missing_reason: block.reason,
|
|
464
702
|
completion_audit_blocked_at: nowIso,
|
|
465
703
|
};
|
|
466
|
-
delete next.completed_at;
|
|
467
704
|
await writeFile(block.path, JSON.stringify(next, null, 2));
|
|
468
705
|
}
|
|
469
706
|
async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerContext) {
|
|
@@ -480,6 +717,12 @@ async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerCont
|
|
|
480
717
|
safeString(preferredSessionId).trim(),
|
|
481
718
|
currentOmxSessionId,
|
|
482
719
|
].filter(Boolean))];
|
|
720
|
+
const completedCanonicalPath = currentOmxSessionId
|
|
721
|
+
? getStateFilePath("ralph-state.json", cwd, currentOmxSessionId)
|
|
722
|
+
: "";
|
|
723
|
+
const completedCanonicalState = completedCanonicalPath
|
|
724
|
+
? await readJsonIfExists(completedCanonicalPath)
|
|
725
|
+
: null;
|
|
483
726
|
// Ralph Stop stays authoritative-scope-only once the Stop payload is session-bound.
|
|
484
727
|
// That is intentionally stricter than generic state MCP reads: do not scan sibling
|
|
485
728
|
// session scopes or fall back to root when a current/explicit session is in play.
|
|
@@ -492,10 +735,27 @@ async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerCont
|
|
|
492
735
|
}
|
|
493
736
|
const sessionScopedPath = getStateFilePath("ralph-state.json", cwd, sessionId);
|
|
494
737
|
const sessionScoped = await readJsonIfExists(sessionScopedPath);
|
|
495
|
-
if (sessionScoped?.active === true
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
738
|
+
if (sessionScoped?.active === true) {
|
|
739
|
+
if (currentOmxSessionId
|
|
740
|
+
&& sessionId !== currentOmxSessionId
|
|
741
|
+
&& completedCanonicalState
|
|
742
|
+
&& shouldRetireShadowedRalphStartingSeed(sessionScoped, completedCanonicalState, cwd, {
|
|
743
|
+
completedSessionId: currentOmxSessionId,
|
|
744
|
+
payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
|
|
745
|
+
threadId: safeString(ownerContext?.threadId).trim(),
|
|
746
|
+
currentNativeSessionId,
|
|
747
|
+
tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
|
|
748
|
+
})) {
|
|
749
|
+
await retireShadowedRalphStartingSeed(sessionScopedPath, sessionScoped, currentOmxSessionId, completedCanonicalPath, completedCanonicalState);
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
if (await isStaleOrphanedRalphStartingState(sessionScoped, sessionScopedPath)) {
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
if (isRalphStartingPhase(sessionScoped)
|
|
756
|
+
&& !(await isVisibleRalphActiveForSession(stateDir, sessionId))) {
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
499
759
|
}
|
|
500
760
|
if (sessionScoped?.active === true
|
|
501
761
|
&& shouldContinueRun(sessionScoped)
|
|
@@ -1129,7 +1389,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1129
1389
|
? "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."
|
|
1130
1390
|
: null;
|
|
1131
1391
|
const ultragoalPromptActivationNote = match.skill === "ultragoal"
|
|
1132
|
-
? "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."
|
|
1392
|
+
? "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."
|
|
1133
1393
|
: null;
|
|
1134
1394
|
const combinedTransitionMessage = (() => {
|
|
1135
1395
|
if (!skillState?.transition_message)
|
|
@@ -1341,15 +1601,21 @@ function isStopExempt(payload) {
|
|
|
1341
1601
|
|| value.includes("limit"));
|
|
1342
1602
|
}
|
|
1343
1603
|
async function buildModeBasedStopOutput(mode, cwd, sessionId) {
|
|
1604
|
+
if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, mode)) {
|
|
1605
|
+
return null;
|
|
1606
|
+
}
|
|
1344
1607
|
const state = await readModeStateForActiveDecision(mode, sessionId?.trim() || undefined, cwd);
|
|
1345
1608
|
if (!state || !shouldContinueRun(state))
|
|
1346
1609
|
return null;
|
|
1347
1610
|
const phase = formatPhase(state.current_phase);
|
|
1611
|
+
const systemMessage = mode === "autopilot" && phase.toLowerCase().replace(/_/g, "-") === "code-review"
|
|
1612
|
+
? "OMX autopilot is still active (phase: code-review). Run the required $code-review step before completing or clearing Autopilot state."
|
|
1613
|
+
: `OMX ${mode} is still active (phase: ${phase}).`;
|
|
1348
1614
|
return {
|
|
1349
1615
|
decision: "block",
|
|
1350
1616
|
reason: `OMX ${mode} is still active (phase: ${phase}); continue the task and gather fresh verification evidence before stopping.`,
|
|
1351
1617
|
stopReason: `${mode}_${phase}`,
|
|
1352
|
-
systemMessage
|
|
1618
|
+
systemMessage,
|
|
1353
1619
|
};
|
|
1354
1620
|
}
|
|
1355
1621
|
export function looksLikeGoalCompletionPrompt(text) {
|
|
@@ -1359,6 +1625,28 @@ export function looksLikeGoalCompletionPrompt(text) {
|
|
|
1359
1625
|
|| /\b(?:ultragoal|performance[-\s]goal|autoresearch[-\s]goal)\b.{0,80}\b(?:complete|checkpoint|finish|close|mark)\b/i.test(text)
|
|
1360
1626
|
|| /(?:^|[.!?]\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);
|
|
1361
1627
|
}
|
|
1628
|
+
function reportsAutoresearchGoalObjectiveMismatch(text) {
|
|
1629
|
+
return /\bautoresearch[-\s]goal\b/i.test(text)
|
|
1630
|
+
&& /\b(?:complete|completion|reconciliation)\b/i.test(text)
|
|
1631
|
+
&& /objective mismatch/i.test(text);
|
|
1632
|
+
}
|
|
1633
|
+
function reportsBlockedPerformanceGoalObjectiveMismatch(state) {
|
|
1634
|
+
const performanceState = safeObject(state);
|
|
1635
|
+
const lastValidation = safeObject(performanceState.lastValidation);
|
|
1636
|
+
if (safeString(performanceState.workflow) !== "performance-goal")
|
|
1637
|
+
return false;
|
|
1638
|
+
if (safeString(performanceState.status) !== "blocked")
|
|
1639
|
+
return false;
|
|
1640
|
+
if (safeString(lastValidation.status) !== "blocked")
|
|
1641
|
+
return false;
|
|
1642
|
+
const evidence = [
|
|
1643
|
+
safeString(lastValidation.evidence),
|
|
1644
|
+
safeString(lastValidation.message),
|
|
1645
|
+
safeString(performanceState.evidence),
|
|
1646
|
+
safeString(performanceState.message),
|
|
1647
|
+
].join(" ");
|
|
1648
|
+
return /objective mismatch/i.test(evidence);
|
|
1649
|
+
}
|
|
1362
1650
|
async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
1363
1651
|
const ultragoal = await readJsonIfExists(join(cwd, ".omx", "ultragoal", "goals.json"));
|
|
1364
1652
|
const aggregateCompletion = safeObject(ultragoal?.aggregateCompletion);
|
|
@@ -1376,7 +1664,7 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
|
1376
1664
|
`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.`,
|
|
1377
1665
|
`If get_goal instead returns a different completed legacy objective and complete checkpointing fails, do not repeat --status complete in this thread.`,
|
|
1378
1666
|
`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>'.`,
|
|
1379
|
-
"Then continue
|
|
1667
|
+
"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.",
|
|
1380
1668
|
].join(" "),
|
|
1381
1669
|
};
|
|
1382
1670
|
}
|
|
@@ -1386,6 +1674,9 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
|
1386
1674
|
continue;
|
|
1387
1675
|
const state = await readJsonIfExists(join(performanceRoot, entry.name, "state.json"));
|
|
1388
1676
|
const status = safeString(state?.status);
|
|
1677
|
+
if (reportsBlockedPerformanceGoalObjectiveMismatch(state)) {
|
|
1678
|
+
continue;
|
|
1679
|
+
}
|
|
1389
1680
|
if (state?.workflow === "performance-goal" && status && status !== "complete") {
|
|
1390
1681
|
return {
|
|
1391
1682
|
workflow: "performance-goal",
|
|
@@ -1402,10 +1693,17 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
|
1402
1693
|
const completion = await readJsonIfExists(join(autoresearchRoot, entry.name, "completion.json"));
|
|
1403
1694
|
const completionVerdict = safeString(completion?.verdict);
|
|
1404
1695
|
const completionPassed = completion?.passed === true || completionVerdict === "pass";
|
|
1405
|
-
if (mission?.workflow === "autoresearch-goal"
|
|
1696
|
+
if (mission?.workflow === "autoresearch-goal"
|
|
1697
|
+
&& status
|
|
1698
|
+
&& status !== "complete"
|
|
1699
|
+
&& completionPassed) {
|
|
1406
1700
|
return {
|
|
1407
1701
|
workflow: "autoresearch-goal",
|
|
1408
1702
|
command: `omx autoresearch-goal complete --slug ${safeString(mission.slug) || entry.name} --codex-goal-json '<get_goal JSON or path>'`,
|
|
1703
|
+
remediation: [
|
|
1704
|
+
"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.",
|
|
1705
|
+
"Either retry with a correct refreshed snapshot or record an explicit blocked verdict for this autoresearch-goal and continue from the explicit blocker path.",
|
|
1706
|
+
].join(" "),
|
|
1409
1707
|
};
|
|
1410
1708
|
}
|
|
1411
1709
|
}
|
|
@@ -1431,6 +1729,9 @@ async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
|
|
|
1431
1729
|
const requirement = await findActiveGoalWorkflowReconciliationRequirement(cwd);
|
|
1432
1730
|
if (!requirement)
|
|
1433
1731
|
return null;
|
|
1732
|
+
if (requirement.workflow === "autoresearch-goal" && reportsAutoresearchGoalObjectiveMismatch(lastAssistantMessage)) {
|
|
1733
|
+
return null;
|
|
1734
|
+
}
|
|
1434
1735
|
const systemMessage = [
|
|
1435
1736
|
`OMX ${requirement.workflow} requires get_goal snapshot reconciliation before completion; call get_goal and pass --codex-goal-json to ${requirement.command}.`,
|
|
1436
1737
|
requirement.remediation,
|
|
@@ -1533,7 +1834,7 @@ function readPayloadSessionId(payload) {
|
|
|
1533
1834
|
return safeString(payload.session_id ?? payload.sessionId).trim();
|
|
1534
1835
|
}
|
|
1535
1836
|
function readPayloadThreadId(payload) {
|
|
1536
|
-
return safeString(payload.thread_id ?? payload.threadId).trim();
|
|
1837
|
+
return safeString(payload.owner_codex_thread_id ?? payload.thread_id ?? payload.threadId).trim();
|
|
1537
1838
|
}
|
|
1538
1839
|
function readPayloadTurnId(payload) {
|
|
1539
1840
|
return safeString(payload.turn_id ?? payload.turnId).trim();
|
|
@@ -1608,6 +1909,8 @@ async function readBlockingSkillForStop(cwd, stateDir, sessionId, threadId, requ
|
|
|
1608
1909
|
const modeSnapshot = getRunContinuationSnapshot(modeState);
|
|
1609
1910
|
if (modeSnapshot?.terminal === true)
|
|
1610
1911
|
continue;
|
|
1912
|
+
if (await shouldIgnoreSessionSkillBlockerForCanonicalInactiveRoot(cwd, stateDir, skill, sessionId, threadId))
|
|
1913
|
+
continue;
|
|
1611
1914
|
const phase = formatPhase(modeState.current_phase, formatPhase(visibleEntries.find((entry) => entry.skill === skill)?.phase, "planning"));
|
|
1612
1915
|
if (TERMINAL_MODE_PHASES.has(phase.toLowerCase()) || phase === "completing") {
|
|
1613
1916
|
continue;
|
|
@@ -1648,6 +1951,38 @@ function isTerminalOrInactiveModeState(state) {
|
|
|
1648
1951
|
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
1649
1952
|
return phase !== "" && TERMINAL_MODE_PHASES.has(phase);
|
|
1650
1953
|
}
|
|
1954
|
+
function rootSkillStateHasNoActiveSkillForStopContext(rootState, skill, sessionId, threadId) {
|
|
1955
|
+
if (!rootState)
|
|
1956
|
+
return false;
|
|
1957
|
+
return !listActiveSkills(rootState).some((entry) => (entry.skill === skill
|
|
1958
|
+
&& matchesSkillStopContext(entry, rootState, sessionId, threadId)));
|
|
1959
|
+
}
|
|
1960
|
+
function rootModeStateIsCanonicalForStopContext(state, cwd, sessionId, threadId) {
|
|
1961
|
+
if (!modeStateMatchesSkillStopContext(state, cwd, sessionId))
|
|
1962
|
+
return false;
|
|
1963
|
+
const stateSessionId = safeString(state.owner_omx_session_id
|
|
1964
|
+
?? state.session_id
|
|
1965
|
+
?? state.codex_session_id
|
|
1966
|
+
?? state.owner_codex_session_id).trim();
|
|
1967
|
+
if (sessionId && stateSessionId !== sessionId)
|
|
1968
|
+
return false;
|
|
1969
|
+
const stateThreadId = safeString(state.owner_codex_thread_id ?? state.thread_id).trim();
|
|
1970
|
+
if (threadId && stateThreadId && stateThreadId !== threadId)
|
|
1971
|
+
return false;
|
|
1972
|
+
return true;
|
|
1973
|
+
}
|
|
1974
|
+
async function shouldIgnoreSessionSkillBlockerForCanonicalInactiveRoot(cwd, stateDir, skill, sessionId, threadId) {
|
|
1975
|
+
const rootModeState = await readJsonIfExists(join(stateDir, `${skill}-state.json`));
|
|
1976
|
+
if (!rootModeState)
|
|
1977
|
+
return false;
|
|
1978
|
+
if (!rootModeStateIsCanonicalForStopContext(rootModeState, cwd, sessionId, threadId))
|
|
1979
|
+
return false;
|
|
1980
|
+
if (!isTerminalOrInactiveModeState(rootModeState))
|
|
1981
|
+
return false;
|
|
1982
|
+
const { rootPath } = getSkillActiveStatePathsForStateDir(stateDir);
|
|
1983
|
+
const rootSkillState = await readSkillActiveState(rootPath);
|
|
1984
|
+
return rootSkillStateHasNoActiveSkillForStopContext(rootSkillState, skill, sessionId, threadId);
|
|
1985
|
+
}
|
|
1651
1986
|
async function readSessionScopedModeStateForRootSkill(cwd, stateDir, skill, sessionIds) {
|
|
1652
1987
|
for (const sessionId of sessionIds) {
|
|
1653
1988
|
const state = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
|
|
@@ -2173,7 +2508,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2173
2508
|
`OMX Ralph completion audit is missing required evidence (${ralphCompletionAuditBlock.reason}; state: ${blockingPath}).`,
|
|
2174
2509
|
"Continue verification and do not report complete yet.",
|
|
2175
2510
|
"Record machine-readable completion evidence before stopping:",
|
|
2176
|
-
|
|
2511
|
+
'- 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',
|
|
2177
2512
|
"- or set completion_audit_path / completion_audit_evidence_path to a repo-relative JSON file with those same fields.",
|
|
2178
2513
|
"Markdown artifacts and flat top-level checklist/evidence fields are not accepted by the Ralph Stop gate.",
|
|
2179
2514
|
].join(" ");
|
|
@@ -2312,6 +2647,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2312
2647
|
let skillState = null;
|
|
2313
2648
|
let triageAdditionalContext = null;
|
|
2314
2649
|
let goalWorkflowAdditionalContext = null;
|
|
2650
|
+
let ultragoalSteeringAdditionalContext = null;
|
|
2315
2651
|
const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
|
|
2316
2652
|
const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
|
|
2317
2653
|
const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
|
|
@@ -2319,10 +2655,12 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2319
2655
|
let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
2320
2656
|
let resolvedNativeSessionId = nativeSessionId;
|
|
2321
2657
|
let skipCanonicalSessionStartContext = false;
|
|
2658
|
+
let isSubagentSessionStart = false;
|
|
2322
2659
|
if (hookEventName === "SessionStart" && nativeSessionId) {
|
|
2323
2660
|
const transcriptPath = safeString(payload.transcript_path ?? payload.transcriptPath).trim();
|
|
2324
2661
|
const subagentSessionStart = readNativeSubagentSessionStartMetadata(transcriptPath);
|
|
2325
2662
|
if (subagentSessionStart && canonicalSessionId) {
|
|
2663
|
+
isSubagentSessionStart = true;
|
|
2326
2664
|
const belongsToCanonicalSession = await nativeSubagentSessionStartBelongsToCanonicalSession(cwd, canonicalSessionId, currentSessionState, subagentSessionStart);
|
|
2327
2665
|
if (belongsToCanonicalSession) {
|
|
2328
2666
|
resolvedNativeSessionId = nativeSessionId;
|
|
@@ -2370,9 +2708,14 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2370
2708
|
].filter(Boolean))]
|
|
2371
2709
|
.map((candidateSessionId) => isNativeSubagentHook(cwd, candidateSessionId, nativeSessionId, threadId)))).some(Boolean)
|
|
2372
2710
|
: false;
|
|
2711
|
+
const suppressNoisySubagentLifecycleDispatch = (isSubagentSessionStart || isSubagentStop)
|
|
2712
|
+
&& shouldSuppressSubagentLifecycleHookDispatch();
|
|
2373
2713
|
if (hookEventName === "UserPromptSubmit") {
|
|
2374
2714
|
const prompt = readPromptText(payload);
|
|
2375
2715
|
goalWorkflowAdditionalContext = await buildGoalWorkflowReconciliationPromptWarning(cwd, prompt).catch(() => null);
|
|
2716
|
+
ultragoalSteeringAdditionalContext = prompt && !isSubagentPromptSubmit
|
|
2717
|
+
? 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)}`)
|
|
2718
|
+
: null;
|
|
2376
2719
|
if (prompt && !isSubagentPromptSubmit) {
|
|
2377
2720
|
skillState = buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessionIdForState, threadId || undefined, turnId || undefined) ?? await recordSkillActivation({
|
|
2378
2721
|
stateDir,
|
|
@@ -2461,7 +2804,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2461
2804
|
const reconcileHudForPromptSubmitFn = options.reconcileHudForPromptSubmitFn ?? reconcileHudForPromptSubmit;
|
|
2462
2805
|
await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => { });
|
|
2463
2806
|
}
|
|
2464
|
-
if (omxEventName && !skipCanonicalSessionStartContext) {
|
|
2807
|
+
if (omxEventName && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
|
|
2465
2808
|
const baseContext = buildBaseContext(cwd, payload, hookEventName, canonicalSessionId);
|
|
2466
2809
|
if (resolvedNativeSessionId) {
|
|
2467
2810
|
baseContext.native_session_id = resolvedNativeSessionId;
|
|
@@ -2498,7 +2841,12 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2498
2841
|
})
|
|
2499
2842
|
: isSubagentPromptSubmit
|
|
2500
2843
|
? null
|
|
2501
|
-
:
|
|
2844
|
+
: [
|
|
2845
|
+
buildAdditionalContextMessage(readPromptText(payload), skillState, cwd, payload),
|
|
2846
|
+
ultragoalSteeringAdditionalContext,
|
|
2847
|
+
goalWorkflowAdditionalContext,
|
|
2848
|
+
triageAdditionalContext,
|
|
2849
|
+
].filter((entry) => Boolean(entry)).join("\n\n") || null;
|
|
2502
2850
|
if (additionalContext) {
|
|
2503
2851
|
outputJson = {
|
|
2504
2852
|
hookSpecificOutput: {
|