oh-my-codex 0.18.0 → 0.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +45 -19
- package/crates/omx-api/src/lib.rs +66 -9
- package/crates/omx-sparkshell/src/exec.rs +125 -3
- package/crates/omx-sparkshell/src/main.rs +126 -36
- package/crates/omx-sparkshell/tests/execution.rs +225 -1
- package/dist/agents/__tests__/definitions.test.js +14 -0
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +19 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +30 -0
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/native-config.d.ts +1 -0
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +4 -0
- package/dist/agents/native-config.js.map +1 -1
- package/dist/catalog/__tests__/generator.test.js +4 -0
- package/dist/catalog/__tests__/generator.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 +137 -8
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +203 -15
- 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 +163 -0
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +29 -43
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +94 -35
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +20 -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/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 +297 -17
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +9 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +465 -110
- package/dist/cli/index.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 +13 -3
- 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 +22 -11
- 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.d.ts +1 -0
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +8 -10
- 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 +17 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +124 -11
- package/dist/config/generator.js.map +1 -1
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +21 -0
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +4 -0
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +50 -3
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +27 -6
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.d.ts +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js +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 +173 -17
- package/dist/hooks/__tests__/keyword-detector.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__/prometheus-strict-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js +320 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +12 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts +2 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js +35 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js.map +1 -0
- 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 +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +36 -9
- 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 +14 -2
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +36 -8
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +122 -11
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/render.test.js +84 -0
- package/dist/hud/__tests__/render.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__/state.test.js +51 -1
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +69 -23
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/index.d.ts +2 -2
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +17 -6
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +6 -3
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +26 -0
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts +2 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +62 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.d.ts +10 -3
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +60 -11
- package/dist/hud/tmux.js.map +1 -1
- package/dist/hud/types.d.ts +22 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.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 +128 -4
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +460 -9
- 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 +85 -17
- 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/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +41 -6
- package/dist/pipeline/stages/ralplan.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/question/__tests__/ui.test.js +43 -10
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/ui.d.ts +12 -0
- package/dist/question/ui.d.ts.map +1 -1
- package/dist/question/ui.js +83 -46
- package/dist/question/ui.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +200 -10
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +23 -0
- package/dist/ralplan/consensus-gate.d.ts.map +1 -0
- package/dist/ralplan/consensus-gate.js +212 -0
- package/dist/ralplan/consensus-gate.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +25 -0
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +144 -8
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +1358 -79
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/docs-site-contract.test.d.ts +2 -0
- package/dist/scripts/__tests__/docs-site-contract.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/docs-site-contract.test.js +42 -0
- package/dist/scripts/__tests__/docs-site-contract.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js +115 -2
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/run-test-files.test.js +57 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +23 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-agents.test.js +18 -3
- package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
- 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 +372 -44
- 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 +9 -1
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/notify-dispatcher.js +188 -4
- 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 +9 -5
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +7 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- package/dist/scripts/run-test-files.js +13 -0
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +3 -0
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +99 -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/__tests__/workflow-transition.test.js +6 -0
- package/dist/state/__tests__/workflow-transition.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/state/workflow-transition.d.ts +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +7 -0
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +4 -3
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +36 -44
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +163 -15
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +10 -20
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +51 -21
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +764 -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 +837 -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/package.json +2 -1
- 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 +92 -50
- package/plugins/oh-my-codex/skills/autoresearch/SKILL.md +4 -0
- package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/cancel/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +8 -8
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +23 -12
- package/plugins/oh-my-codex/skills/plan/SKILL.md +8 -8
- package/plugins/oh-my-codex/skills/prometheus-strict/README.md +35 -0
- package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +219 -0
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +7 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +22 -7
- 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/prometheus-strict-metis.md +274 -0
- package/prompts/prometheus-strict-momus.md +82 -0
- package/prompts/prometheus-strict-oracle.md +107 -0
- package/prompts/researcher.md +22 -3
- package/skills/autopilot/SKILL.md +92 -50
- package/skills/autoresearch/SKILL.md +4 -0
- package/skills/autoresearch-goal/SKILL.md +1 -1
- package/skills/best-practice-research/SKILL.md +1 -1
- package/skills/cancel/SKILL.md +2 -2
- package/skills/deep-interview/SKILL.md +8 -8
- package/skills/omx-setup/SKILL.md +1 -1
- package/skills/pipeline/SKILL.md +23 -12
- package/skills/plan/SKILL.md +8 -8
- package/skills/prometheus-strict/README.md +35 -0
- package/skills/prometheus-strict/SKILL.md +219 -0
- package/skills/ralph/SKILL.md +7 -0
- package/skills/ralplan/SKILL.md +22 -7
- 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 +1757 -210
- package/src/scripts/__tests__/docs-site-contract.test.ts +47 -0
- package/src/scripts/__tests__/notify-dispatcher.test.ts +132 -3
- package/src/scripts/__tests__/run-test-files.test.ts +67 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +31 -0
- package/src/scripts/__tests__/verify-native-agents.test.ts +23 -3
- package/src/scripts/cleanup-explore-harness.ts +1 -0
- package/src/scripts/codex-native-hook.ts +393 -40
- package/src/scripts/codex-native-pre-post.ts +16 -1
- package/src/scripts/notify-dispatcher.ts +202 -4
- package/src/scripts/notify-hook/process-runner.ts +40 -16
- package/src/scripts/notify-hook/team-dispatch.ts +9 -5
- package/src/scripts/notify-hook/team-tmux-guard.ts +7 -0
- package/src/scripts/run-test-files.ts +13 -0
- package/src/scripts/smoke-packed-install.ts +105 -0
- package/src/scripts/sync-plugin-mirror.ts +3 -3
- package/src/scripts/verify-native-agents.ts +2 -2
- package/templates/catalog-manifest.json +22 -0
|
@@ -3,8 +3,9 @@ import { closeSync, existsSync, openSync, readFileSync, readSync } from "fs";
|
|
|
3
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
|
-
import {
|
|
6
|
+
import { readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
|
|
7
7
|
import {
|
|
8
|
+
SKILL_ACTIVE_STATE_FILE,
|
|
8
9
|
extractSessionIdFromInitializedStatePath,
|
|
9
10
|
getSkillActiveStatePathsForStateDir,
|
|
10
11
|
listActiveSkills,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
} from "../state/skill-active.js";
|
|
15
16
|
import {
|
|
16
17
|
readSubagentSessionSummary,
|
|
18
|
+
readSubagentTrackingState,
|
|
17
19
|
recordSubagentTurnForSession,
|
|
18
20
|
} from "../subagents/tracker.js";
|
|
19
21
|
import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
|
|
@@ -69,6 +71,7 @@ import {
|
|
|
69
71
|
} from "../hooks/extensibility/events.js";
|
|
70
72
|
import type { HookEventEnvelope } from "../hooks/extensibility/types.js";
|
|
71
73
|
import { dispatchHookEventRuntime } from "../hooks/extensibility/runtime.js";
|
|
74
|
+
import { getNotificationConfig, getVerbosity } from "../notifications/config.js";
|
|
72
75
|
import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
|
|
73
76
|
import {
|
|
74
77
|
onPreCompact as buildWikiPreCompactContext,
|
|
@@ -78,6 +81,11 @@ import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDec
|
|
|
78
81
|
import { readRunState } from "../runtime/run-state.js";
|
|
79
82
|
import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
|
|
80
83
|
import { getRunContinuationSnapshot, shouldContinueRun } from "../runtime/run-loop.js";
|
|
84
|
+
import {
|
|
85
|
+
parseUltragoalSteeringDirective,
|
|
86
|
+
steerUltragoal,
|
|
87
|
+
type UltragoalSteeringProposal,
|
|
88
|
+
} from "../ultragoal/artifacts.js";
|
|
81
89
|
import { triagePrompt } from "../hooks/triage-heuristic.js";
|
|
82
90
|
import { readTriageConfig } from "../hooks/triage-config.js";
|
|
83
91
|
import {
|
|
@@ -291,18 +299,39 @@ async function isNativeSubagentHook(
|
|
|
291
299
|
nativeSessionId: string,
|
|
292
300
|
threadId: string,
|
|
293
301
|
): Promise<boolean> {
|
|
294
|
-
const sessionId = canonicalSessionId.trim();
|
|
295
|
-
if (!sessionId) return false;
|
|
296
|
-
|
|
297
|
-
const summary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
|
|
298
|
-
if (!summary) return false;
|
|
299
|
-
|
|
300
302
|
const candidateIds = [nativeSessionId, threadId]
|
|
301
303
|
.map((value) => value.trim())
|
|
302
304
|
.filter(Boolean);
|
|
303
305
|
if (candidateIds.length === 0) return false;
|
|
304
306
|
|
|
305
|
-
|
|
307
|
+
const sessionId = canonicalSessionId.trim();
|
|
308
|
+
if (sessionId) {
|
|
309
|
+
const summary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
|
|
310
|
+
if (summary && candidateIds.some((id) => summary.allSubagentThreadIds.includes(id))) {
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Native Codex resume can report the child native session as the canonical
|
|
316
|
+
// session id before OMX reconciles it back to the owning session. In that
|
|
317
|
+
// window the per-session summary lookup above misses the child and a
|
|
318
|
+
// subagent UserPromptSubmit can accidentally activate workflow keywords from
|
|
319
|
+
// quoted review context. Fall back to the global tracking index so any known
|
|
320
|
+
// subagent thread is treated as subagent-scoped, regardless of the current
|
|
321
|
+
// hook payload's session-id mapping.
|
|
322
|
+
const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
|
|
323
|
+
if (!trackingState) return false;
|
|
324
|
+
|
|
325
|
+
return Object.values(trackingState.sessions).some((session) => (
|
|
326
|
+
candidateIds.some((id) => session.threads[id]?.kind === "subagent")
|
|
327
|
+
));
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function shouldSuppressSubagentLifecycleHookDispatch(): boolean {
|
|
331
|
+
const config = getNotificationConfig();
|
|
332
|
+
if (config?.includeChildAgents === true) return false;
|
|
333
|
+
const verbosity = getVerbosity(config);
|
|
334
|
+
return verbosity !== "agent" && verbosity !== "verbose";
|
|
306
335
|
}
|
|
307
336
|
|
|
308
337
|
async function recordIgnoredNativeSubagentSessionStart(
|
|
@@ -419,6 +448,104 @@ function readPromptText(payload: CodexHookPayload): string {
|
|
|
419
448
|
return "";
|
|
420
449
|
}
|
|
421
450
|
|
|
451
|
+
|
|
452
|
+
function extractBalancedJsonObject(text: string, startIndex: number): string | null {
|
|
453
|
+
let depth = 0;
|
|
454
|
+
let inString = false;
|
|
455
|
+
let escaped = false;
|
|
456
|
+
for (let index = startIndex; index < text.length; index++) {
|
|
457
|
+
const char = text[index];
|
|
458
|
+
if (inString) {
|
|
459
|
+
if (escaped) escaped = false;
|
|
460
|
+
else if (char === "\\") escaped = true;
|
|
461
|
+
else if (char === '"') inString = false;
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
if (char === '"') {
|
|
465
|
+
inString = true;
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
if (char === "{") depth += 1;
|
|
469
|
+
else if (char === "}") {
|
|
470
|
+
depth -= 1;
|
|
471
|
+
if (depth === 0) return text.slice(startIndex, index + 1);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function normalizePromptSteeringProposal(raw: unknown, prompt: string): UltragoalSteeringProposal | null {
|
|
478
|
+
const candidate = safeObject(raw);
|
|
479
|
+
const nested = candidate.omx_ultragoal_steer ?? candidate.ultragoal_steer ?? candidate.steering ?? candidate;
|
|
480
|
+
const proposal = parseUltragoalSteeringDirective(JSON.stringify(nested));
|
|
481
|
+
if (!proposal) return null;
|
|
482
|
+
if (proposal.source !== "user_prompt_submit") return null;
|
|
483
|
+
const normalized = prompt.trim().toLowerCase();
|
|
484
|
+
return {
|
|
485
|
+
...proposal,
|
|
486
|
+
directiveText: proposal.directiveText ?? safeContextSnippet(prompt, 600),
|
|
487
|
+
promptSignature: proposal.promptSignature ?? promptSignature(normalized),
|
|
488
|
+
idempotencyKey: proposal.idempotencyKey ?? `user_prompt_submit:${promptSignature(normalized)}`,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function parseUserPromptUltragoalSteeringDirective(prompt: string): UltragoalSteeringProposal | null {
|
|
493
|
+
const trimmed = prompt.trim();
|
|
494
|
+
if (!trimmed) return null;
|
|
495
|
+
const fenced = trimmed.match(/```(?:omx-ultragoal-steer|ultragoal-steer)\s*([\s\S]*?)```/i);
|
|
496
|
+
if (fenced?.[1]) {
|
|
497
|
+
try {
|
|
498
|
+
return normalizePromptSteeringProposal(JSON.parse(fenced[1]), prompt);
|
|
499
|
+
} catch {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const label = trimmed.match(/(?:^|\n)\s*(?:OMX_ULTRAGOAL_STEER|omx\.ultragoal\.steer|omx ultragoal steer)\s*:\s*{/i);
|
|
505
|
+
if (label?.index !== undefined) {
|
|
506
|
+
const brace = trimmed.indexOf("{", label.index);
|
|
507
|
+
const json = brace >= 0 ? extractBalancedJsonObject(trimmed, brace) : null;
|
|
508
|
+
if (json) {
|
|
509
|
+
try {
|
|
510
|
+
return normalizePromptSteeringProposal(JSON.parse(json), prompt);
|
|
511
|
+
} catch {
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (trimmed.startsWith("{")) {
|
|
518
|
+
try {
|
|
519
|
+
const parsed = JSON.parse(trimmed);
|
|
520
|
+
const object = safeObject(parsed);
|
|
521
|
+
if ("omx_ultragoal_steer" in object || "ultragoal_steer" in object) {
|
|
522
|
+
return normalizePromptSteeringProposal(parsed, prompt);
|
|
523
|
+
}
|
|
524
|
+
} catch {
|
|
525
|
+
return null;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
async function applyUserPromptUltragoalSteering(cwd: string, prompt: string): Promise<string | null> {
|
|
532
|
+
const proposal = parseUserPromptUltragoalSteeringDirective(prompt);
|
|
533
|
+
if (!proposal) return null;
|
|
534
|
+
try {
|
|
535
|
+
const result = await steerUltragoal(cwd, proposal);
|
|
536
|
+
const status = result.deduped ? "deduped" : result.accepted ? "accepted" : "rejected";
|
|
537
|
+
const reasons = result.rejectedReasons.length > 0 ? ` rejectedReasons=${result.rejectedReasons.join("; ")}` : "";
|
|
538
|
+
return [
|
|
539
|
+
`OMX native UserPromptSubmit applied bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${status}.`,
|
|
540
|
+
`mutation=${result.audit.kind}; source=${result.audit.source}; targets=${result.audit.targetGoalIds.join(",") || "none"}; idempotencyKey=${result.audit.idempotencyKey ?? "none"}.${reasons}`,
|
|
541
|
+
"Only explicit structured steering directives are parsed; normal prose is ignored and cannot mutate .omx/ultragoal.",
|
|
542
|
+
].join(" ");
|
|
543
|
+
} catch (error) {
|
|
544
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
545
|
+
return `OMX native UserPromptSubmit rejected bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${message}`;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
422
549
|
function sanitizePayloadForHookContext(
|
|
423
550
|
payload: CodexHookPayload,
|
|
424
551
|
hookEventName: CodexHookEventName,
|
|
@@ -793,13 +920,12 @@ async function reopenRalphCompletionAuditBlock(block: RalphCompletionAuditBlockS
|
|
|
793
920
|
const nowIso = new Date().toISOString();
|
|
794
921
|
const next: Record<string, unknown> = {
|
|
795
922
|
...block.state,
|
|
796
|
-
active:
|
|
797
|
-
current_phase: "
|
|
923
|
+
active: false,
|
|
924
|
+
current_phase: "complete",
|
|
798
925
|
completion_audit_gate: "blocked",
|
|
799
926
|
completion_audit_missing_reason: block.reason,
|
|
800
927
|
completion_audit_blocked_at: nowIso,
|
|
801
928
|
};
|
|
802
|
-
delete next.completed_at;
|
|
803
929
|
await writeFile(block.path, JSON.stringify(next, null, 2));
|
|
804
930
|
}
|
|
805
931
|
|
|
@@ -1573,6 +1699,17 @@ function buildSkillStateCliInstruction(mode: string, statePath: string): string
|
|
|
1573
1699
|
return `skill: ${mode} activated and initial state initialized at ${statePath}; use CLI-first state updates via \`omx state write/read/clear --input '<json>' --json\`; use omx_state MCP only when explicit MCP compatibility is enabled.`;
|
|
1574
1700
|
}
|
|
1575
1701
|
|
|
1702
|
+
function buildAutopilotPromptActivationNote(skillState?: SkillActiveState | null): string | null {
|
|
1703
|
+
if (skillState?.initialized_mode !== "autopilot") return null;
|
|
1704
|
+
return [
|
|
1705
|
+
"Autopilot protocol: the durable default chain is $deep-interview -> $ralplan -> $ultragoal (+ $team if needed) -> $code-review -> $ultraqa (deep-interview -> ralplan -> ultragoal -> code-review -> ultraqa).",
|
|
1706
|
+
"Start/resume at current_phase=deep-interview unless the task is clear and bounded; if deep-interview is intentionally skipped, persist and state an explicit deep_interview_gate.skip_reason before moving to ralplan.",
|
|
1707
|
+
"The ralplan phase is not complete until Planner output has been reviewed sequentially by Architect and then Critic; do not hand off to Ultragoal or implementation until the ralplan state/artifact records both ralplan_architect_review and ralplan_critic_review with approval or an explicit blocker.",
|
|
1708
|
+
"Do not silently fall back to ordinary $plan/ralplan-only handling; keep autopilot-state.json, skill-active-state.json, HUD/statusline, and Codex goal-mode handoff guidance visible while the workflow is active.",
|
|
1709
|
+
"When Codex goal tools are available, call get_goal/create_goal only from the active thread handoff and treat the active goal as the completion contract until code-review and ultraqa are clean.",
|
|
1710
|
+
].join(" ");
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1576
1713
|
function buildAdditionalContextMessage(
|
|
1577
1714
|
prompt: string,
|
|
1578
1715
|
skillState?: SkillActiveState | null,
|
|
@@ -1604,8 +1741,9 @@ function buildAdditionalContextMessage(
|
|
|
1604
1741
|
? "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."
|
|
1605
1742
|
: null;
|
|
1606
1743
|
const ultragoalPromptActivationNote = match.skill === "ultragoal"
|
|
1607
|
-
? "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."
|
|
1744
|
+
? "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."
|
|
1608
1745
|
: null;
|
|
1746
|
+
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState);
|
|
1609
1747
|
const combinedTransitionMessage = (() => {
|
|
1610
1748
|
if (!skillState?.transition_message) return null;
|
|
1611
1749
|
if (matches.length <= 1 || activeSkills.length <= 1) return skillState.transition_message;
|
|
@@ -1633,6 +1771,7 @@ function buildAdditionalContextMessage(
|
|
|
1633
1771
|
: null,
|
|
1634
1772
|
promptPriorityMessage,
|
|
1635
1773
|
ultragoalPromptActivationNote,
|
|
1774
|
+
autopilotPromptActivationNote,
|
|
1636
1775
|
skillState.initialized_mode && skillState.initialized_state_path
|
|
1637
1776
|
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
1638
1777
|
: null,
|
|
@@ -1659,6 +1798,7 @@ function buildAdditionalContextMessage(
|
|
|
1659
1798
|
deepInterviewPromptActivationNote,
|
|
1660
1799
|
ultraworkPromptActivationNote,
|
|
1661
1800
|
ultragoalPromptActivationNote,
|
|
1801
|
+
autopilotPromptActivationNote,
|
|
1662
1802
|
buildTeamRuntimeInstruction(cwd, payload),
|
|
1663
1803
|
buildTeamHelpInstruction(cwd, payload),
|
|
1664
1804
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
@@ -1677,12 +1817,13 @@ function buildAdditionalContextMessage(
|
|
|
1677
1817
|
deepInterviewPromptActivationNote,
|
|
1678
1818
|
ultraworkPromptActivationNote,
|
|
1679
1819
|
ultragoalPromptActivationNote,
|
|
1820
|
+
autopilotPromptActivationNote,
|
|
1680
1821
|
ralphPromptActivationNote,
|
|
1681
1822
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
1682
1823
|
].join(" ");
|
|
1683
1824
|
}
|
|
1684
1825
|
|
|
1685
|
-
return [detectedKeywordMessage, promptPriorityMessage, ultragoalPromptActivationNote, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
|
|
1826
|
+
return [detectedKeywordMessage, promptPriorityMessage, ultragoalPromptActivationNote, autopilotPromptActivationNote, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
|
|
1686
1827
|
}
|
|
1687
1828
|
|
|
1688
1829
|
function parseTeamWorkerEnv(rawValue: string): { teamName: string; workerName: string } | null {
|
|
@@ -1867,6 +2008,9 @@ async function buildModeBasedStopOutput(
|
|
|
1867
2008
|
cwd: string,
|
|
1868
2009
|
sessionId?: string,
|
|
1869
2010
|
): Promise<Record<string, unknown> | null> {
|
|
2011
|
+
if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, mode)) {
|
|
2012
|
+
return null;
|
|
2013
|
+
}
|
|
1870
2014
|
const state = await readModeStateForActiveDecision(mode, sessionId?.trim() || undefined, cwd);
|
|
1871
2015
|
if (!state || !shouldContinueRun(state)) return null;
|
|
1872
2016
|
const phase = formatPhase(state.current_phase);
|
|
@@ -1895,6 +2039,22 @@ function reportsAutoresearchGoalObjectiveMismatch(text: string): boolean {
|
|
|
1895
2039
|
&& /objective mismatch/i.test(text);
|
|
1896
2040
|
}
|
|
1897
2041
|
|
|
2042
|
+
function reportsBlockedPerformanceGoalObjectiveMismatch(state: unknown): boolean {
|
|
2043
|
+
const performanceState = safeObject(state);
|
|
2044
|
+
const lastValidation = safeObject(performanceState.lastValidation);
|
|
2045
|
+
if (safeString(performanceState.workflow) !== "performance-goal") return false;
|
|
2046
|
+
if (safeString(performanceState.status) !== "blocked") return false;
|
|
2047
|
+
if (safeString(lastValidation.status) !== "blocked") return false;
|
|
2048
|
+
|
|
2049
|
+
const evidence = [
|
|
2050
|
+
safeString(lastValidation.evidence),
|
|
2051
|
+
safeString(lastValidation.message),
|
|
2052
|
+
safeString(performanceState.evidence),
|
|
2053
|
+
safeString(performanceState.message),
|
|
2054
|
+
].join(" ");
|
|
2055
|
+
return /objective mismatch/i.test(evidence);
|
|
2056
|
+
}
|
|
2057
|
+
|
|
1898
2058
|
async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Promise<{ workflow: string; command: string; remediation?: string } | null> {
|
|
1899
2059
|
const ultragoal = await readJsonIfExists(join(cwd, ".omx", "ultragoal", "goals.json"));
|
|
1900
2060
|
const aggregateCompletion = safeObject(ultragoal?.aggregateCompletion);
|
|
@@ -1912,7 +2072,8 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Pro
|
|
|
1912
2072
|
`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.`,
|
|
1913
2073
|
`If get_goal instead returns a different completed legacy objective and complete checkpointing fails, do not repeat --status complete in this thread.`,
|
|
1914
2074
|
`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>'.`,
|
|
1915
|
-
"
|
|
2075
|
+
`If get_goal itself is unavailable with a Codex DB/schema/context error such as "no such table: thread_goals", record an auditable safe-recovery blocker instead: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<unavailable get_goal error JSON or path>' --evidence '<get_goal unavailable due to Codex DB/schema/context error; safe recovery requires a working Codex goal context>'.`,
|
|
2076
|
+
"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.",
|
|
1916
2077
|
].join(" "),
|
|
1917
2078
|
};
|
|
1918
2079
|
}
|
|
@@ -1922,6 +2083,9 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Pro
|
|
|
1922
2083
|
if (!entry.isDirectory()) continue;
|
|
1923
2084
|
const state = await readJsonIfExists(join(performanceRoot, entry.name, "state.json"));
|
|
1924
2085
|
const status = safeString(state?.status);
|
|
2086
|
+
if (reportsBlockedPerformanceGoalObjectiveMismatch(state)) {
|
|
2087
|
+
continue;
|
|
2088
|
+
}
|
|
1925
2089
|
if (state?.workflow === "performance-goal" && status && status !== "complete") {
|
|
1926
2090
|
return {
|
|
1927
2091
|
workflow: "performance-goal",
|
|
@@ -1948,8 +2112,8 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd: string): Pro
|
|
|
1948
2112
|
workflow: "autoresearch-goal",
|
|
1949
2113
|
command: `omx autoresearch-goal complete --slug ${safeString(mission.slug) || entry.name} --codex-goal-json '<get_goal JSON or path>'`,
|
|
1950
2114
|
remediation: [
|
|
1951
|
-
"If that command fails with a Codex goal objective mismatch after a
|
|
1952
|
-
"Either retry with a correct
|
|
2115
|
+
"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.",
|
|
2116
|
+
"Either retry with a correct refreshed snapshot or record an explicit blocked verdict for this autoresearch-goal and continue from the explicit blocker path.",
|
|
1953
2117
|
].join(" "),
|
|
1954
2118
|
};
|
|
1955
2119
|
}
|
|
@@ -1995,36 +2159,60 @@ async function buildGoalWorkflowReconciliationStopOutput(
|
|
|
1995
2159
|
};
|
|
1996
2160
|
}
|
|
1997
2161
|
|
|
2162
|
+
interface TeamModeStateForStop {
|
|
2163
|
+
state: Record<string, unknown>;
|
|
2164
|
+
scope: "session" | "root";
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
function teamStateMatchesThreadForStop(
|
|
2168
|
+
state: Record<string, unknown>,
|
|
2169
|
+
threadId?: string,
|
|
2170
|
+
options: { requireOwnerThread?: boolean } = {},
|
|
2171
|
+
): boolean {
|
|
2172
|
+
const normalizedThreadId = safeString(threadId).trim();
|
|
2173
|
+
if (!normalizedThreadId) return true;
|
|
2174
|
+
|
|
2175
|
+
const ownerThreadId = safeString(state.owner_codex_thread_id ?? state.thread_id).trim();
|
|
2176
|
+
if (!ownerThreadId) return options.requireOwnerThread !== true;
|
|
2177
|
+
return ownerThreadId === normalizedThreadId;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
1998
2180
|
async function readTeamModeStateForStop(
|
|
1999
2181
|
cwd: string,
|
|
2000
2182
|
stateDir: string,
|
|
2001
2183
|
sessionId?: string,
|
|
2002
|
-
|
|
2184
|
+
threadId?: string,
|
|
2185
|
+
): Promise<TeamModeStateForStop | null> {
|
|
2003
2186
|
const normalizedSessionId = safeString(sessionId).trim();
|
|
2004
|
-
if (!normalizedSessionId)
|
|
2005
|
-
return await readModeState("team", cwd);
|
|
2006
|
-
}
|
|
2187
|
+
if (!normalizedSessionId) return null;
|
|
2007
2188
|
|
|
2008
2189
|
const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId, stateDir);
|
|
2009
|
-
if (scopedState)
|
|
2190
|
+
if (scopedState) {
|
|
2191
|
+
return teamStateMatchesThreadForStop(scopedState, threadId)
|
|
2192
|
+
? { state: scopedState, scope: "session" }
|
|
2193
|
+
: null;
|
|
2194
|
+
}
|
|
2010
2195
|
|
|
2011
2196
|
const rootState = await readJsonIfExists(join(stateDir, "team-state.json"));
|
|
2012
2197
|
if (rootState?.active !== true) return null;
|
|
2013
2198
|
|
|
2199
|
+
const teamName = safeString(rootState.team_name).trim();
|
|
2200
|
+
if (!teamName) return null;
|
|
2201
|
+
|
|
2014
2202
|
const ownerSessionId = safeString(rootState.session_id).trim();
|
|
2015
|
-
if (ownerSessionId
|
|
2016
|
-
|
|
2017
|
-
}
|
|
2203
|
+
if (!ownerSessionId || ownerSessionId !== normalizedSessionId) return null;
|
|
2204
|
+
if (!teamStateMatchesThreadForStop(rootState, threadId, { requireOwnerThread: true })) return null;
|
|
2018
2205
|
|
|
2019
|
-
return rootState;
|
|
2206
|
+
return { state: rootState, scope: "root" };
|
|
2020
2207
|
}
|
|
2021
2208
|
|
|
2022
|
-
async function buildTeamStopOutput(cwd: string, sessionId?: string): Promise<Record<string, unknown> | null> {
|
|
2209
|
+
async function buildTeamStopOutput(cwd: string, sessionId?: string, threadId?: string): Promise<Record<string, unknown> | null> {
|
|
2023
2210
|
if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, "team")) {
|
|
2024
2211
|
return null;
|
|
2025
2212
|
}
|
|
2026
|
-
const
|
|
2027
|
-
if (
|
|
2213
|
+
const teamStateForStop = await readTeamModeStateForStop(cwd, getBaseStateDir(cwd), sessionId, threadId);
|
|
2214
|
+
if (!teamStateForStop || teamStateForStop.state.active !== true) return null;
|
|
2215
|
+
const teamState = teamStateForStop.state;
|
|
2028
2216
|
const teamName = safeString(teamState.team_name).trim();
|
|
2029
2217
|
if (teamName) {
|
|
2030
2218
|
const canonicalTeamDir = join(resolveCanonicalTeamStateRoot(cwd), "team", teamName);
|
|
@@ -2033,7 +2221,9 @@ async function buildTeamStopOutput(cwd: string, sessionId?: string): Promise<Rec
|
|
|
2033
2221
|
}
|
|
2034
2222
|
}
|
|
2035
2223
|
const coarsePhase = teamState.current_phase;
|
|
2036
|
-
const
|
|
2224
|
+
const canonicalPhaseState = teamName ? await readTeamPhase(teamName, cwd) : null;
|
|
2225
|
+
if (teamStateForStop.scope === "root" && !canonicalPhaseState) return null;
|
|
2226
|
+
const canonicalPhase = canonicalPhaseState?.current_phase ?? coarsePhase;
|
|
2037
2227
|
if (!isNonTerminalPhase(canonicalPhase)) return null;
|
|
2038
2228
|
return buildTeamStopOutputForPhase(teamName, formatPhase(canonicalPhase));
|
|
2039
2229
|
}
|
|
@@ -2140,6 +2330,151 @@ async function readStopSessionPinnedState(
|
|
|
2140
2330
|
return readJsonIfExists(statePath);
|
|
2141
2331
|
}
|
|
2142
2332
|
|
|
2333
|
+
const DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES = [
|
|
2334
|
+
".omx/context",
|
|
2335
|
+
".omx/interviews",
|
|
2336
|
+
".omx/specs",
|
|
2337
|
+
".omx/state",
|
|
2338
|
+
] as const;
|
|
2339
|
+
|
|
2340
|
+
const DEEP_INTERVIEW_IMPLEMENTATION_TOOL_NAMES = new Set([
|
|
2341
|
+
"Write",
|
|
2342
|
+
"Edit",
|
|
2343
|
+
"MultiEdit",
|
|
2344
|
+
"apply_patch",
|
|
2345
|
+
"ApplyPatch",
|
|
2346
|
+
]);
|
|
2347
|
+
|
|
2348
|
+
function isActiveDeepInterviewPhase(state: Record<string, unknown> | null): boolean {
|
|
2349
|
+
if (!state || state.active !== true) return false;
|
|
2350
|
+
const mode = safeString(state.mode).trim();
|
|
2351
|
+
if (mode && mode !== "deep-interview") return false;
|
|
2352
|
+
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
2353
|
+
if (phase && (TERMINAL_MODE_PHASES.has(phase) || phase === "completing")) return false;
|
|
2354
|
+
return true;
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
function isAllowedDeepInterviewArtifactPath(cwd: string, rawPath: string): boolean {
|
|
2358
|
+
const trimmed = rawPath.trim().replace(/^['"]|['"]$/g, "");
|
|
2359
|
+
if (!trimmed || trimmed.includes("\0")) return false;
|
|
2360
|
+
let relativePath: string;
|
|
2361
|
+
try {
|
|
2362
|
+
const absolute = resolve(cwd, trimmed);
|
|
2363
|
+
relativePath = relative(cwd, absolute).replace(/\\/g, "/");
|
|
2364
|
+
} catch {
|
|
2365
|
+
return false;
|
|
2366
|
+
}
|
|
2367
|
+
if (!relativePath || relativePath.startsWith("..") || relativePath.startsWith("/")) return false;
|
|
2368
|
+
return DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES.some((prefix) => (
|
|
2369
|
+
relativePath === prefix || relativePath.startsWith(`${prefix}/`)
|
|
2370
|
+
));
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
function readPreToolUseCommand(payload: CodexHookPayload): string {
|
|
2374
|
+
const toolInput = safeObject(payload.tool_input);
|
|
2375
|
+
return safeString(toolInput.command).trim();
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
function readPreToolUsePathCandidates(payload: CodexHookPayload): string[] {
|
|
2379
|
+
const input = safeObject(payload.tool_input);
|
|
2380
|
+
const candidates = [
|
|
2381
|
+
input.file_path,
|
|
2382
|
+
input.filePath,
|
|
2383
|
+
input.path,
|
|
2384
|
+
input.target_path,
|
|
2385
|
+
input.targetPath,
|
|
2386
|
+
];
|
|
2387
|
+
return candidates.map((candidate) => safeString(candidate).trim()).filter(Boolean);
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
function commandHasDeepInterviewWriteIntent(command: string): boolean {
|
|
2391
|
+
return /\bapply_patch\b/.test(command)
|
|
2392
|
+
|| /(?:^|[;&|]\s*)(?:cat|printf|echo)\b[\s\S]{0,240}>\s*[^\s&|;]+/.test(command)
|
|
2393
|
+
|| /\btee\s+(?:-a\s+)?[^\s&|;]+/.test(command)
|
|
2394
|
+
|| /\bsed\s+(?:[^\n;&|]*\s)?-i(?:\b|['"])/.test(command)
|
|
2395
|
+
|| /\b(?:python3?|node|perl|ruby)\b[\s\S]{0,260}\b(?:writeFileSync|writeFile|write_text|open\([^)]*["']w|File\.write|Path\()/.test(command)
|
|
2396
|
+
|| /\b(?:git\s+(?:checkout|switch|restore|reset|apply|am|merge|rebase)|npm\s+(?:install|i|ci)|pnpm\s+(?:install|i)|yarn\s+(?:install|add))\b/.test(command);
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
function extractDeepInterviewCommandWriteTargets(command: string): string[] {
|
|
2400
|
+
const targets: string[] = [];
|
|
2401
|
+
for (const match of command.matchAll(/(?:^|[^>])>{1,2}\s*(["']?)([^\s&|;<>]+)\1/g)) {
|
|
2402
|
+
const candidate = safeString(match[2]).trim();
|
|
2403
|
+
if (candidate) targets.push(candidate);
|
|
2404
|
+
}
|
|
2405
|
+
for (const match of command.matchAll(/\btee\s+(?:-a\s+)?(["']?)([^\s&|;<>]+)\1/g)) {
|
|
2406
|
+
const candidate = safeString(match[2]).trim();
|
|
2407
|
+
if (candidate) targets.push(candidate);
|
|
2408
|
+
}
|
|
2409
|
+
return targets;
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
function isAllowedDeepInterviewBashWrite(cwd: string, command: string): boolean {
|
|
2413
|
+
if (!commandHasDeepInterviewWriteIntent(command)) return true;
|
|
2414
|
+
if (/\bomx\s+(?:state\s+(?:write|read|clear)|question)\b/.test(command)) return true;
|
|
2415
|
+
const targets = extractDeepInterviewCommandWriteTargets(command);
|
|
2416
|
+
return targets.length > 0 && targets.every((target) => isAllowedDeepInterviewArtifactPath(cwd, target));
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
async function readActiveDeepInterviewStateForPreToolUse(
|
|
2420
|
+
cwd: string,
|
|
2421
|
+
stateDir: string,
|
|
2422
|
+
sessionId: string,
|
|
2423
|
+
threadId: string,
|
|
2424
|
+
): Promise<Record<string, unknown> | null> {
|
|
2425
|
+
const modeState = sessionId
|
|
2426
|
+
? await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId, stateDir)
|
|
2427
|
+
: await readJsonIfExists(join(stateDir, "deep-interview-state.json"));
|
|
2428
|
+
if (!isActiveDeepInterviewPhase(modeState) || !modeState) return null;
|
|
2429
|
+
if (!modeStateMatchesSkillStopContext(modeState, cwd, sessionId)) return null;
|
|
2430
|
+
|
|
2431
|
+
const canonicalState = sessionId
|
|
2432
|
+
? await readVisibleSkillActiveStateForStateDir(stateDir, sessionId)
|
|
2433
|
+
: await readSkillActiveState(join(stateDir, SKILL_ACTIVE_STATE_FILE));
|
|
2434
|
+
if (!canonicalState) return modeState;
|
|
2435
|
+
const hasActiveDeepInterviewSkill = listActiveSkills(canonicalState).some((entry) => (
|
|
2436
|
+
entry.skill === "deep-interview"
|
|
2437
|
+
&& matchesSkillStopContext(entry, canonicalState, sessionId, threadId)
|
|
2438
|
+
));
|
|
2439
|
+
return hasActiveDeepInterviewSkill ? modeState : null;
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
async function buildDeepInterviewPreToolUseBoundaryOutput(
|
|
2443
|
+
payload: CodexHookPayload,
|
|
2444
|
+
cwd: string,
|
|
2445
|
+
stateDir: string,
|
|
2446
|
+
): Promise<Record<string, unknown> | null> {
|
|
2447
|
+
const sessionId = readPayloadSessionId(payload);
|
|
2448
|
+
const threadId = readPayloadThreadId(payload);
|
|
2449
|
+
const activeState = await readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionId, threadId);
|
|
2450
|
+
if (!activeState) return null;
|
|
2451
|
+
|
|
2452
|
+
const toolName = safeString(payload.tool_name).trim();
|
|
2453
|
+
const command = readPreToolUseCommand(payload);
|
|
2454
|
+
const pathCandidates = readPreToolUsePathCandidates(payload);
|
|
2455
|
+
let blocked = false;
|
|
2456
|
+
|
|
2457
|
+
if (toolName === "Bash") {
|
|
2458
|
+
blocked = !isAllowedDeepInterviewBashWrite(cwd, command);
|
|
2459
|
+
} else if (DEEP_INTERVIEW_IMPLEMENTATION_TOOL_NAMES.has(toolName)) {
|
|
2460
|
+
blocked = pathCandidates.length === 0
|
|
2461
|
+
|| !pathCandidates.every((candidate) => isAllowedDeepInterviewArtifactPath(cwd, candidate));
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
if (!blocked) return null;
|
|
2465
|
+
|
|
2466
|
+
const phase = formatPhase(activeState.current_phase ?? activeState.currentPhase, "planning");
|
|
2467
|
+
return {
|
|
2468
|
+
decision: "block",
|
|
2469
|
+
reason: `Deep-interview is active (phase: ${phase}); implementation/write tools are blocked until an explicit handoff workflow is activated.`,
|
|
2470
|
+
hookSpecificOutput: {
|
|
2471
|
+
hookEventName: "PreToolUse",
|
|
2472
|
+
additionalContext:
|
|
2473
|
+
"Deep-interview is requirements/spec mode. Treat detailed user answers as interview/spec material, not implicit implementation authorization. You may write only deep-interview artifacts under `.omx/context/`, `.omx/interviews/`, `.omx/specs/`, or required `.omx/state/` files. To implement, first ask for or process an explicit transition such as `$ralplan`, `$autopilot`, `$ralph`, `$team`, or `$ultragoal`.",
|
|
2474
|
+
},
|
|
2475
|
+
};
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2143
2478
|
function matchesSkillStopContext(
|
|
2144
2479
|
entry: { session_id?: string; thread_id?: string },
|
|
2145
2480
|
state: { session_id?: string; thread_id?: string },
|
|
@@ -2777,6 +3112,7 @@ async function returnPersistentStopBlock(
|
|
|
2777
3112
|
async function findCanonicalActiveTeamForSession(
|
|
2778
3113
|
cwd: string,
|
|
2779
3114
|
sessionId: string,
|
|
3115
|
+
threadId?: string,
|
|
2780
3116
|
): Promise<{ teamName: string; phase: string } | null> {
|
|
2781
3117
|
if (!sessionId.trim()) return null;
|
|
2782
3118
|
const teamsRoot = join(resolveCanonicalTeamStateRoot(cwd), "team");
|
|
@@ -2795,6 +3131,7 @@ async function findCanonicalActiveTeamForSession(
|
|
|
2795
3131
|
if (!manifest || !phaseState) continue;
|
|
2796
3132
|
const ownerSessionId = (manifest.leader?.session_id ?? "").trim();
|
|
2797
3133
|
if (ownerSessionId && ownerSessionId !== sessionId.trim()) continue;
|
|
3134
|
+
if (!teamStateMatchesThreadForStop(manifest.leader as unknown as Record<string, unknown>, threadId)) continue;
|
|
2798
3135
|
if (!isNonTerminalPhase(phaseState.current_phase)) continue;
|
|
2799
3136
|
|
|
2800
3137
|
return {
|
|
@@ -2810,12 +3147,13 @@ async function resolveActiveTeamNameForStop(
|
|
|
2810
3147
|
cwd: string,
|
|
2811
3148
|
stateDir: string,
|
|
2812
3149
|
sessionId: string,
|
|
3150
|
+
threadId?: string,
|
|
2813
3151
|
): Promise<string> {
|
|
2814
|
-
const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId);
|
|
2815
|
-
const directTeamName = safeString(directState?.team_name).trim();
|
|
2816
|
-
if (directState?.active === true && directTeamName) return directTeamName;
|
|
3152
|
+
const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId, threadId);
|
|
3153
|
+
const directTeamName = safeString(directState?.state.team_name).trim();
|
|
3154
|
+
if (directState?.state.active === true && directTeamName) return directTeamName;
|
|
2817
3155
|
|
|
2818
|
-
const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, sessionId);
|
|
3156
|
+
const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, sessionId, threadId);
|
|
2819
3157
|
return canonicalTeam?.teamName ?? "";
|
|
2820
3158
|
}
|
|
2821
3159
|
|
|
@@ -2827,7 +3165,7 @@ async function maybeBuildReleaseReadinessFinalizeStopOutput(
|
|
|
2827
3165
|
): Promise<{ matched: boolean; output: Record<string, unknown> | null }> {
|
|
2828
3166
|
if (!sessionId) return { matched: false, output: null };
|
|
2829
3167
|
|
|
2830
|
-
const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId);
|
|
3168
|
+
const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId, readPayloadThreadId(payload));
|
|
2831
3169
|
if (!teamName) return { matched: false, output: null };
|
|
2832
3170
|
|
|
2833
3171
|
const explicitReleaseReadinessContext =
|
|
@@ -3040,7 +3378,7 @@ async function buildStopHookOutput(
|
|
|
3040
3378
|
`OMX Ralph completion audit is missing required evidence (${ralphCompletionAuditBlock.reason}; state: ${blockingPath}).`,
|
|
3041
3379
|
"Continue verification and do not report complete yet.",
|
|
3042
3380
|
"Record machine-readable completion evidence before stopping:",
|
|
3043
|
-
|
|
3381
|
+
'- 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',
|
|
3044
3382
|
"- or set completion_audit_path / completion_audit_evidence_path to a repo-relative JSON file with those same fields.",
|
|
3045
3383
|
"Markdown artifacts and flat top-level checklist/evidence fields are not accepted by the Ralph Stop gate.",
|
|
3046
3384
|
].join(" ");
|
|
@@ -3156,7 +3494,7 @@ async function buildStopHookOutput(
|
|
|
3156
3494
|
);
|
|
3157
3495
|
if (releaseReadinessFinalizeResult.matched) return releaseReadinessFinalizeResult.output;
|
|
3158
3496
|
|
|
3159
|
-
const teamOutput = await buildTeamStopOutput(cwd, canonicalSessionId);
|
|
3497
|
+
const teamOutput = await buildTeamStopOutput(cwd, canonicalSessionId, threadId);
|
|
3160
3498
|
if (teamOutput) {
|
|
3161
3499
|
return await returnPersistentStopBlock(
|
|
3162
3500
|
payload,
|
|
@@ -3188,7 +3526,7 @@ async function buildStopHookOutput(
|
|
|
3188
3526
|
|
|
3189
3527
|
const canonicalTeam = await readCanonicalTerminalRunStateForStop(cwd, canonicalSessionId, "team")
|
|
3190
3528
|
? null
|
|
3191
|
-
: await findCanonicalActiveTeamForSession(cwd, canonicalSessionId);
|
|
3529
|
+
: await findCanonicalActiveTeamForSession(cwd, canonicalSessionId, threadId);
|
|
3192
3530
|
if (canonicalTeam) {
|
|
3193
3531
|
const canonicalTeamOutput = buildTeamStopOutputForPhase(
|
|
3194
3532
|
canonicalTeam.teamName,
|
|
@@ -3337,6 +3675,7 @@ export async function dispatchCodexNativeHook(
|
|
|
3337
3675
|
let skillState: SkillActiveState | null = null;
|
|
3338
3676
|
let triageAdditionalContext: string | null = null;
|
|
3339
3677
|
let goalWorkflowAdditionalContext: string | null = null;
|
|
3678
|
+
let ultragoalSteeringAdditionalContext: string | null = null;
|
|
3340
3679
|
|
|
3341
3680
|
const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
|
|
3342
3681
|
const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
|
|
@@ -3345,11 +3684,13 @@ export async function dispatchCodexNativeHook(
|
|
|
3345
3684
|
let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
3346
3685
|
let resolvedNativeSessionId = nativeSessionId;
|
|
3347
3686
|
let skipCanonicalSessionStartContext = false;
|
|
3687
|
+
let isSubagentSessionStart = false;
|
|
3348
3688
|
|
|
3349
3689
|
if (hookEventName === "SessionStart" && nativeSessionId) {
|
|
3350
3690
|
const transcriptPath = safeString(payload.transcript_path ?? payload.transcriptPath).trim();
|
|
3351
3691
|
const subagentSessionStart = readNativeSubagentSessionStartMetadata(transcriptPath);
|
|
3352
3692
|
if (subagentSessionStart && canonicalSessionId) {
|
|
3693
|
+
isSubagentSessionStart = true;
|
|
3353
3694
|
const belongsToCanonicalSession = await nativeSubagentSessionStartBelongsToCanonicalSession(
|
|
3354
3695
|
cwd,
|
|
3355
3696
|
canonicalSessionId,
|
|
@@ -3418,10 +3759,16 @@ export async function dispatchCodexNativeHook(
|
|
|
3418
3759
|
.map((candidateSessionId) => isNativeSubagentHook(cwd, candidateSessionId, nativeSessionId, threadId)),
|
|
3419
3760
|
)).some(Boolean)
|
|
3420
3761
|
: false;
|
|
3762
|
+
const suppressNoisySubagentLifecycleDispatch =
|
|
3763
|
+
(isSubagentSessionStart || isSubagentStop)
|
|
3764
|
+
&& shouldSuppressSubagentLifecycleHookDispatch();
|
|
3421
3765
|
|
|
3422
3766
|
if (hookEventName === "UserPromptSubmit") {
|
|
3423
3767
|
const prompt = readPromptText(payload);
|
|
3424
3768
|
goalWorkflowAdditionalContext = await buildGoalWorkflowReconciliationPromptWarning(cwd, prompt).catch(() => null);
|
|
3769
|
+
ultragoalSteeringAdditionalContext = prompt && !isSubagentPromptSubmit
|
|
3770
|
+
? 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)}`)
|
|
3771
|
+
: null;
|
|
3425
3772
|
if (prompt && !isSubagentPromptSubmit) {
|
|
3426
3773
|
skillState = buildNativeOutsideTmuxTeamPromptBlockState(
|
|
3427
3774
|
prompt,
|
|
@@ -3513,7 +3860,7 @@ export async function dispatchCodexNativeHook(
|
|
|
3513
3860
|
await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => {});
|
|
3514
3861
|
}
|
|
3515
3862
|
|
|
3516
|
-
if (omxEventName && !skipCanonicalSessionStartContext) {
|
|
3863
|
+
if (omxEventName && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
|
|
3517
3864
|
const baseContext = buildBaseContext(cwd, payload, hookEventName!, canonicalSessionId);
|
|
3518
3865
|
if (resolvedNativeSessionId) {
|
|
3519
3866
|
baseContext.native_session_id = resolvedNativeSessionId;
|
|
@@ -3554,7 +3901,12 @@ export async function dispatchCodexNativeHook(
|
|
|
3554
3901
|
})
|
|
3555
3902
|
: isSubagentPromptSubmit
|
|
3556
3903
|
? null
|
|
3557
|
-
:
|
|
3904
|
+
: [
|
|
3905
|
+
buildAdditionalContextMessage(readPromptText(payload), skillState, cwd, payload),
|
|
3906
|
+
ultragoalSteeringAdditionalContext,
|
|
3907
|
+
goalWorkflowAdditionalContext,
|
|
3908
|
+
triageAdditionalContext,
|
|
3909
|
+
].filter((entry): entry is string => Boolean(entry)).join("\n\n") || null;
|
|
3558
3910
|
if (additionalContext) {
|
|
3559
3911
|
outputJson = {
|
|
3560
3912
|
hookSpecificOutput: {
|
|
@@ -3564,7 +3916,8 @@ export async function dispatchCodexNativeHook(
|
|
|
3564
3916
|
};
|
|
3565
3917
|
}
|
|
3566
3918
|
} else if (hookEventName === "PreToolUse") {
|
|
3567
|
-
outputJson =
|
|
3919
|
+
outputJson = await buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir)
|
|
3920
|
+
?? buildNativePreToolUseOutput(payload);
|
|
3568
3921
|
} else if (hookEventName === "PostToolUse") {
|
|
3569
3922
|
if (detectMcpTransportFailure(payload)) {
|
|
3570
3923
|
await markTeamTransportFailure(cwd, payload);
|