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,9 +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 {
|
|
7
|
-
import { extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
|
|
8
|
-
import { readSubagentSessionSummary, recordSubagentTurnForSession, } from "../subagents/tracker.js";
|
|
6
|
+
import { readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
|
|
7
|
+
import { SKILL_ACTIVE_STATE_FILE, extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
|
|
8
|
+
import { readSubagentSessionSummary, readSubagentTrackingState, recordSubagentTurnForSession, } from "../subagents/tracker.js";
|
|
9
9
|
import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
|
|
10
10
|
import { appendToLog, isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
|
|
11
11
|
import { appendTeamEvent, readTeamLeaderAttention, readTeamManifestV2, readTeamPhase, writeTeamLeaderAttention, writeTeamPhase, } from "../team/state.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";
|
|
@@ -173,18 +175,36 @@ async function nativeSubagentSessionStartBelongsToCanonicalSession(cwd, canonica
|
|
|
173
175
|
return summary.allThreadIds.includes(parentThreadId);
|
|
174
176
|
}
|
|
175
177
|
async function isNativeSubagentHook(cwd, canonicalSessionId, nativeSessionId, threadId) {
|
|
176
|
-
const sessionId = canonicalSessionId.trim();
|
|
177
|
-
if (!sessionId)
|
|
178
|
-
return false;
|
|
179
|
-
const summary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
|
|
180
|
-
if (!summary)
|
|
181
|
-
return false;
|
|
182
178
|
const candidateIds = [nativeSessionId, threadId]
|
|
183
179
|
.map((value) => value.trim())
|
|
184
180
|
.filter(Boolean);
|
|
185
181
|
if (candidateIds.length === 0)
|
|
186
182
|
return false;
|
|
187
|
-
|
|
183
|
+
const sessionId = canonicalSessionId.trim();
|
|
184
|
+
if (sessionId) {
|
|
185
|
+
const summary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
|
|
186
|
+
if (summary && candidateIds.some((id) => summary.allSubagentThreadIds.includes(id))) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Native Codex resume can report the child native session as the canonical
|
|
191
|
+
// session id before OMX reconciles it back to the owning session. In that
|
|
192
|
+
// window the per-session summary lookup above misses the child and a
|
|
193
|
+
// subagent UserPromptSubmit can accidentally activate workflow keywords from
|
|
194
|
+
// quoted review context. Fall back to the global tracking index so any known
|
|
195
|
+
// subagent thread is treated as subagent-scoped, regardless of the current
|
|
196
|
+
// hook payload's session-id mapping.
|
|
197
|
+
const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
|
|
198
|
+
if (!trackingState)
|
|
199
|
+
return false;
|
|
200
|
+
return Object.values(trackingState.sessions).some((session) => (candidateIds.some((id) => session.threads[id]?.kind === "subagent")));
|
|
201
|
+
}
|
|
202
|
+
function shouldSuppressSubagentLifecycleHookDispatch() {
|
|
203
|
+
const config = getNotificationConfig();
|
|
204
|
+
if (config?.includeChildAgents === true)
|
|
205
|
+
return false;
|
|
206
|
+
const verbosity = getVerbosity(config);
|
|
207
|
+
return verbosity !== "agent" && verbosity !== "verbose";
|
|
188
208
|
}
|
|
189
209
|
async function recordIgnoredNativeSubagentSessionStart(cwd, canonicalSessionId, childSessionId, metadata, transcriptPath) {
|
|
190
210
|
await appendToLog(cwd, {
|
|
@@ -286,6 +306,110 @@ function readPromptText(payload) {
|
|
|
286
306
|
}
|
|
287
307
|
return "";
|
|
288
308
|
}
|
|
309
|
+
function extractBalancedJsonObject(text, startIndex) {
|
|
310
|
+
let depth = 0;
|
|
311
|
+
let inString = false;
|
|
312
|
+
let escaped = false;
|
|
313
|
+
for (let index = startIndex; index < text.length; index++) {
|
|
314
|
+
const char = text[index];
|
|
315
|
+
if (inString) {
|
|
316
|
+
if (escaped)
|
|
317
|
+
escaped = false;
|
|
318
|
+
else if (char === "\\")
|
|
319
|
+
escaped = true;
|
|
320
|
+
else if (char === '"')
|
|
321
|
+
inString = false;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (char === '"') {
|
|
325
|
+
inString = true;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (char === "{")
|
|
329
|
+
depth += 1;
|
|
330
|
+
else if (char === "}") {
|
|
331
|
+
depth -= 1;
|
|
332
|
+
if (depth === 0)
|
|
333
|
+
return text.slice(startIndex, index + 1);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
function normalizePromptSteeringProposal(raw, prompt) {
|
|
339
|
+
const candidate = safeObject(raw);
|
|
340
|
+
const nested = candidate.omx_ultragoal_steer ?? candidate.ultragoal_steer ?? candidate.steering ?? candidate;
|
|
341
|
+
const proposal = parseUltragoalSteeringDirective(JSON.stringify(nested));
|
|
342
|
+
if (!proposal)
|
|
343
|
+
return null;
|
|
344
|
+
if (proposal.source !== "user_prompt_submit")
|
|
345
|
+
return null;
|
|
346
|
+
const normalized = prompt.trim().toLowerCase();
|
|
347
|
+
return {
|
|
348
|
+
...proposal,
|
|
349
|
+
directiveText: proposal.directiveText ?? safeContextSnippet(prompt, 600),
|
|
350
|
+
promptSignature: proposal.promptSignature ?? promptSignature(normalized),
|
|
351
|
+
idempotencyKey: proposal.idempotencyKey ?? `user_prompt_submit:${promptSignature(normalized)}`,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function parseUserPromptUltragoalSteeringDirective(prompt) {
|
|
355
|
+
const trimmed = prompt.trim();
|
|
356
|
+
if (!trimmed)
|
|
357
|
+
return null;
|
|
358
|
+
const fenced = trimmed.match(/```(?:omx-ultragoal-steer|ultragoal-steer)\s*([\s\S]*?)```/i);
|
|
359
|
+
if (fenced?.[1]) {
|
|
360
|
+
try {
|
|
361
|
+
return normalizePromptSteeringProposal(JSON.parse(fenced[1]), prompt);
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const label = trimmed.match(/(?:^|\n)\s*(?:OMX_ULTRAGOAL_STEER|omx\.ultragoal\.steer|omx ultragoal steer)\s*:\s*{/i);
|
|
368
|
+
if (label?.index !== undefined) {
|
|
369
|
+
const brace = trimmed.indexOf("{", label.index);
|
|
370
|
+
const json = brace >= 0 ? extractBalancedJsonObject(trimmed, brace) : null;
|
|
371
|
+
if (json) {
|
|
372
|
+
try {
|
|
373
|
+
return normalizePromptSteeringProposal(JSON.parse(json), prompt);
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (trimmed.startsWith("{")) {
|
|
381
|
+
try {
|
|
382
|
+
const parsed = JSON.parse(trimmed);
|
|
383
|
+
const object = safeObject(parsed);
|
|
384
|
+
if ("omx_ultragoal_steer" in object || "ultragoal_steer" in object) {
|
|
385
|
+
return normalizePromptSteeringProposal(parsed, prompt);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
async function applyUserPromptUltragoalSteering(cwd, prompt) {
|
|
395
|
+
const proposal = parseUserPromptUltragoalSteeringDirective(prompt);
|
|
396
|
+
if (!proposal)
|
|
397
|
+
return null;
|
|
398
|
+
try {
|
|
399
|
+
const result = await steerUltragoal(cwd, proposal);
|
|
400
|
+
const status = result.deduped ? "deduped" : result.accepted ? "accepted" : "rejected";
|
|
401
|
+
const reasons = result.rejectedReasons.length > 0 ? ` rejectedReasons=${result.rejectedReasons.join("; ")}` : "";
|
|
402
|
+
return [
|
|
403
|
+
`OMX native UserPromptSubmit applied bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${status}.`,
|
|
404
|
+
`mutation=${result.audit.kind}; source=${result.audit.source}; targets=${result.audit.targetGoalIds.join(",") || "none"}; idempotencyKey=${result.audit.idempotencyKey ?? "none"}.${reasons}`,
|
|
405
|
+
"Only explicit structured steering directives are parsed; normal prose is ignored and cannot mutate .omx/ultragoal.",
|
|
406
|
+
].join(" ");
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
410
|
+
return `OMX native UserPromptSubmit rejected bounded .omx/ultragoal steering for G002-cli-and-prompt-submit-bridge: ${message}`;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
289
413
|
function sanitizePayloadForHookContext(payload, hookEventName, canonicalSessionId = "") {
|
|
290
414
|
const sanitized = { ...payload };
|
|
291
415
|
if (hookEventName === "UserPromptSubmit") {
|
|
@@ -582,13 +706,12 @@ async function reopenRalphCompletionAuditBlock(block) {
|
|
|
582
706
|
const nowIso = new Date().toISOString();
|
|
583
707
|
const next = {
|
|
584
708
|
...block.state,
|
|
585
|
-
active:
|
|
586
|
-
current_phase: "
|
|
709
|
+
active: false,
|
|
710
|
+
current_phase: "complete",
|
|
587
711
|
completion_audit_gate: "blocked",
|
|
588
712
|
completion_audit_missing_reason: block.reason,
|
|
589
713
|
completion_audit_blocked_at: nowIso,
|
|
590
714
|
};
|
|
591
|
-
delete next.completed_at;
|
|
592
715
|
await writeFile(block.path, JSON.stringify(next, null, 2));
|
|
593
716
|
}
|
|
594
717
|
async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerContext) {
|
|
@@ -1249,6 +1372,17 @@ function buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessio
|
|
|
1249
1372
|
function buildSkillStateCliInstruction(mode, statePath) {
|
|
1250
1373
|
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.`;
|
|
1251
1374
|
}
|
|
1375
|
+
function buildAutopilotPromptActivationNote(skillState) {
|
|
1376
|
+
if (skillState?.initialized_mode !== "autopilot")
|
|
1377
|
+
return null;
|
|
1378
|
+
return [
|
|
1379
|
+
"Autopilot protocol: the durable default chain is $deep-interview -> $ralplan -> $ultragoal (+ $team if needed) -> $code-review -> $ultraqa (deep-interview -> ralplan -> ultragoal -> code-review -> ultraqa).",
|
|
1380
|
+
"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.",
|
|
1381
|
+
"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.",
|
|
1382
|
+
"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.",
|
|
1383
|
+
"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.",
|
|
1384
|
+
].join(" ");
|
|
1385
|
+
}
|
|
1252
1386
|
function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(), payload) {
|
|
1253
1387
|
if (!prompt)
|
|
1254
1388
|
return null;
|
|
@@ -1277,8 +1411,9 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1277
1411
|
? "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."
|
|
1278
1412
|
: null;
|
|
1279
1413
|
const ultragoalPromptActivationNote = match.skill === "ultragoal"
|
|
1280
|
-
? "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."
|
|
1414
|
+
? "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."
|
|
1281
1415
|
: null;
|
|
1416
|
+
const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState);
|
|
1282
1417
|
const combinedTransitionMessage = (() => {
|
|
1283
1418
|
if (!skillState?.transition_message)
|
|
1284
1419
|
return null;
|
|
@@ -1307,6 +1442,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1307
1442
|
: null,
|
|
1308
1443
|
promptPriorityMessage,
|
|
1309
1444
|
ultragoalPromptActivationNote,
|
|
1445
|
+
autopilotPromptActivationNote,
|
|
1310
1446
|
skillState.initialized_mode && skillState.initialized_state_path
|
|
1311
1447
|
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
1312
1448
|
: null,
|
|
@@ -1332,6 +1468,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1332
1468
|
deepInterviewPromptActivationNote,
|
|
1333
1469
|
ultraworkPromptActivationNote,
|
|
1334
1470
|
ultragoalPromptActivationNote,
|
|
1471
|
+
autopilotPromptActivationNote,
|
|
1335
1472
|
buildTeamRuntimeInstruction(cwd, payload),
|
|
1336
1473
|
buildTeamHelpInstruction(cwd, payload),
|
|
1337
1474
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
@@ -1349,11 +1486,12 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1349
1486
|
deepInterviewPromptActivationNote,
|
|
1350
1487
|
ultraworkPromptActivationNote,
|
|
1351
1488
|
ultragoalPromptActivationNote,
|
|
1489
|
+
autopilotPromptActivationNote,
|
|
1352
1490
|
ralphPromptActivationNote,
|
|
1353
1491
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
1354
1492
|
].join(" ");
|
|
1355
1493
|
}
|
|
1356
|
-
return [detectedKeywordMessage, promptPriorityMessage, ultragoalPromptActivationNote, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
|
|
1494
|
+
return [detectedKeywordMessage, promptPriorityMessage, ultragoalPromptActivationNote, autopilotPromptActivationNote, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
|
|
1357
1495
|
}
|
|
1358
1496
|
function parseTeamWorkerEnv(rawValue) {
|
|
1359
1497
|
const match = /^([a-z0-9][a-z0-9-]{0,29})\/(worker-\d+)$/.exec(rawValue.trim());
|
|
@@ -1489,6 +1627,9 @@ function isStopExempt(payload) {
|
|
|
1489
1627
|
|| value.includes("limit"));
|
|
1490
1628
|
}
|
|
1491
1629
|
async function buildModeBasedStopOutput(mode, cwd, sessionId) {
|
|
1630
|
+
if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, mode)) {
|
|
1631
|
+
return null;
|
|
1632
|
+
}
|
|
1492
1633
|
const state = await readModeStateForActiveDecision(mode, sessionId?.trim() || undefined, cwd);
|
|
1493
1634
|
if (!state || !shouldContinueRun(state))
|
|
1494
1635
|
return null;
|
|
@@ -1515,6 +1656,23 @@ function reportsAutoresearchGoalObjectiveMismatch(text) {
|
|
|
1515
1656
|
&& /\b(?:complete|completion|reconciliation)\b/i.test(text)
|
|
1516
1657
|
&& /objective mismatch/i.test(text);
|
|
1517
1658
|
}
|
|
1659
|
+
function reportsBlockedPerformanceGoalObjectiveMismatch(state) {
|
|
1660
|
+
const performanceState = safeObject(state);
|
|
1661
|
+
const lastValidation = safeObject(performanceState.lastValidation);
|
|
1662
|
+
if (safeString(performanceState.workflow) !== "performance-goal")
|
|
1663
|
+
return false;
|
|
1664
|
+
if (safeString(performanceState.status) !== "blocked")
|
|
1665
|
+
return false;
|
|
1666
|
+
if (safeString(lastValidation.status) !== "blocked")
|
|
1667
|
+
return false;
|
|
1668
|
+
const evidence = [
|
|
1669
|
+
safeString(lastValidation.evidence),
|
|
1670
|
+
safeString(lastValidation.message),
|
|
1671
|
+
safeString(performanceState.evidence),
|
|
1672
|
+
safeString(performanceState.message),
|
|
1673
|
+
].join(" ");
|
|
1674
|
+
return /objective mismatch/i.test(evidence);
|
|
1675
|
+
}
|
|
1518
1676
|
async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
1519
1677
|
const ultragoal = await readJsonIfExists(join(cwd, ".omx", "ultragoal", "goals.json"));
|
|
1520
1678
|
const aggregateCompletion = safeObject(ultragoal?.aggregateCompletion);
|
|
@@ -1532,7 +1690,8 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
|
1532
1690
|
`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.`,
|
|
1533
1691
|
`If get_goal instead returns a different completed legacy objective and complete checkpointing fails, do not repeat --status complete in this thread.`,
|
|
1534
1692
|
`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>'.`,
|
|
1535
|
-
"
|
|
1693
|
+
`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>'.`,
|
|
1694
|
+
"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.",
|
|
1536
1695
|
].join(" "),
|
|
1537
1696
|
};
|
|
1538
1697
|
}
|
|
@@ -1542,6 +1701,9 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
|
1542
1701
|
continue;
|
|
1543
1702
|
const state = await readJsonIfExists(join(performanceRoot, entry.name, "state.json"));
|
|
1544
1703
|
const status = safeString(state?.status);
|
|
1704
|
+
if (reportsBlockedPerformanceGoalObjectiveMismatch(state)) {
|
|
1705
|
+
continue;
|
|
1706
|
+
}
|
|
1545
1707
|
if (state?.workflow === "performance-goal" && status && status !== "complete") {
|
|
1546
1708
|
return {
|
|
1547
1709
|
workflow: "performance-goal",
|
|
@@ -1566,8 +1728,8 @@ async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
|
1566
1728
|
workflow: "autoresearch-goal",
|
|
1567
1729
|
command: `omx autoresearch-goal complete --slug ${safeString(mission.slug) || entry.name} --codex-goal-json '<get_goal JSON or path>'`,
|
|
1568
1730
|
remediation: [
|
|
1569
|
-
"If that command fails with a Codex goal objective mismatch after a
|
|
1570
|
-
"Either retry with a correct
|
|
1731
|
+
"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.",
|
|
1732
|
+
"Either retry with a correct refreshed snapshot or record an explicit blocked verdict for this autoresearch-goal and continue from the explicit blocker path.",
|
|
1571
1733
|
].join(" "),
|
|
1572
1734
|
};
|
|
1573
1735
|
}
|
|
@@ -1609,30 +1771,46 @@ async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
|
|
|
1609
1771
|
systemMessage,
|
|
1610
1772
|
};
|
|
1611
1773
|
}
|
|
1612
|
-
|
|
1774
|
+
function teamStateMatchesThreadForStop(state, threadId, options = {}) {
|
|
1775
|
+
const normalizedThreadId = safeString(threadId).trim();
|
|
1776
|
+
if (!normalizedThreadId)
|
|
1777
|
+
return true;
|
|
1778
|
+
const ownerThreadId = safeString(state.owner_codex_thread_id ?? state.thread_id).trim();
|
|
1779
|
+
if (!ownerThreadId)
|
|
1780
|
+
return options.requireOwnerThread !== true;
|
|
1781
|
+
return ownerThreadId === normalizedThreadId;
|
|
1782
|
+
}
|
|
1783
|
+
async function readTeamModeStateForStop(cwd, stateDir, sessionId, threadId) {
|
|
1613
1784
|
const normalizedSessionId = safeString(sessionId).trim();
|
|
1614
|
-
if (!normalizedSessionId)
|
|
1615
|
-
return
|
|
1616
|
-
}
|
|
1785
|
+
if (!normalizedSessionId)
|
|
1786
|
+
return null;
|
|
1617
1787
|
const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId, stateDir);
|
|
1618
|
-
if (scopedState)
|
|
1619
|
-
return scopedState
|
|
1788
|
+
if (scopedState) {
|
|
1789
|
+
return teamStateMatchesThreadForStop(scopedState, threadId)
|
|
1790
|
+
? { state: scopedState, scope: "session" }
|
|
1791
|
+
: null;
|
|
1792
|
+
}
|
|
1620
1793
|
const rootState = await readJsonIfExists(join(stateDir, "team-state.json"));
|
|
1621
1794
|
if (rootState?.active !== true)
|
|
1622
1795
|
return null;
|
|
1796
|
+
const teamName = safeString(rootState.team_name).trim();
|
|
1797
|
+
if (!teamName)
|
|
1798
|
+
return null;
|
|
1623
1799
|
const ownerSessionId = safeString(rootState.session_id).trim();
|
|
1624
|
-
if (ownerSessionId
|
|
1800
|
+
if (!ownerSessionId || ownerSessionId !== normalizedSessionId)
|
|
1625
1801
|
return null;
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1802
|
+
if (!teamStateMatchesThreadForStop(rootState, threadId, { requireOwnerThread: true }))
|
|
1803
|
+
return null;
|
|
1804
|
+
return { state: rootState, scope: "root" };
|
|
1628
1805
|
}
|
|
1629
|
-
async function buildTeamStopOutput(cwd, sessionId) {
|
|
1806
|
+
async function buildTeamStopOutput(cwd, sessionId, threadId) {
|
|
1630
1807
|
if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, "team")) {
|
|
1631
1808
|
return null;
|
|
1632
1809
|
}
|
|
1633
|
-
const
|
|
1634
|
-
if (
|
|
1810
|
+
const teamStateForStop = await readTeamModeStateForStop(cwd, getBaseStateDir(cwd), sessionId, threadId);
|
|
1811
|
+
if (!teamStateForStop || teamStateForStop.state.active !== true)
|
|
1635
1812
|
return null;
|
|
1813
|
+
const teamState = teamStateForStop.state;
|
|
1636
1814
|
const teamName = safeString(teamState.team_name).trim();
|
|
1637
1815
|
if (teamName) {
|
|
1638
1816
|
const canonicalTeamDir = join(resolveCanonicalTeamStateRoot(cwd), "team", teamName);
|
|
@@ -1641,7 +1819,10 @@ async function buildTeamStopOutput(cwd, sessionId) {
|
|
|
1641
1819
|
}
|
|
1642
1820
|
}
|
|
1643
1821
|
const coarsePhase = teamState.current_phase;
|
|
1644
|
-
const
|
|
1822
|
+
const canonicalPhaseState = teamName ? await readTeamPhase(teamName, cwd) : null;
|
|
1823
|
+
if (teamStateForStop.scope === "root" && !canonicalPhaseState)
|
|
1824
|
+
return null;
|
|
1825
|
+
const canonicalPhase = canonicalPhaseState?.current_phase ?? coarsePhase;
|
|
1645
1826
|
if (!isNonTerminalPhase(canonicalPhase))
|
|
1646
1827
|
return null;
|
|
1647
1828
|
return buildTeamStopOutputForPhase(teamName, formatPhase(canonicalPhase));
|
|
@@ -1724,6 +1905,137 @@ async function readStopSessionPinnedState(fileName, cwd, sessionId, stateDir) {
|
|
|
1724
1905
|
: getStateFilePath(fileName, cwd, sessionId || undefined);
|
|
1725
1906
|
return readJsonIfExists(statePath);
|
|
1726
1907
|
}
|
|
1908
|
+
const DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES = [
|
|
1909
|
+
".omx/context",
|
|
1910
|
+
".omx/interviews",
|
|
1911
|
+
".omx/specs",
|
|
1912
|
+
".omx/state",
|
|
1913
|
+
];
|
|
1914
|
+
const DEEP_INTERVIEW_IMPLEMENTATION_TOOL_NAMES = new Set([
|
|
1915
|
+
"Write",
|
|
1916
|
+
"Edit",
|
|
1917
|
+
"MultiEdit",
|
|
1918
|
+
"apply_patch",
|
|
1919
|
+
"ApplyPatch",
|
|
1920
|
+
]);
|
|
1921
|
+
function isActiveDeepInterviewPhase(state) {
|
|
1922
|
+
if (!state || state.active !== true)
|
|
1923
|
+
return false;
|
|
1924
|
+
const mode = safeString(state.mode).trim();
|
|
1925
|
+
if (mode && mode !== "deep-interview")
|
|
1926
|
+
return false;
|
|
1927
|
+
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
1928
|
+
if (phase && (TERMINAL_MODE_PHASES.has(phase) || phase === "completing"))
|
|
1929
|
+
return false;
|
|
1930
|
+
return true;
|
|
1931
|
+
}
|
|
1932
|
+
function isAllowedDeepInterviewArtifactPath(cwd, rawPath) {
|
|
1933
|
+
const trimmed = rawPath.trim().replace(/^['"]|['"]$/g, "");
|
|
1934
|
+
if (!trimmed || trimmed.includes("\0"))
|
|
1935
|
+
return false;
|
|
1936
|
+
let relativePath;
|
|
1937
|
+
try {
|
|
1938
|
+
const absolute = resolve(cwd, trimmed);
|
|
1939
|
+
relativePath = relative(cwd, absolute).replace(/\\/g, "/");
|
|
1940
|
+
}
|
|
1941
|
+
catch {
|
|
1942
|
+
return false;
|
|
1943
|
+
}
|
|
1944
|
+
if (!relativePath || relativePath.startsWith("..") || relativePath.startsWith("/"))
|
|
1945
|
+
return false;
|
|
1946
|
+
return DEEP_INTERVIEW_ALLOWED_WRITE_PREFIXES.some((prefix) => (relativePath === prefix || relativePath.startsWith(`${prefix}/`)));
|
|
1947
|
+
}
|
|
1948
|
+
function readPreToolUseCommand(payload) {
|
|
1949
|
+
const toolInput = safeObject(payload.tool_input);
|
|
1950
|
+
return safeString(toolInput.command).trim();
|
|
1951
|
+
}
|
|
1952
|
+
function readPreToolUsePathCandidates(payload) {
|
|
1953
|
+
const input = safeObject(payload.tool_input);
|
|
1954
|
+
const candidates = [
|
|
1955
|
+
input.file_path,
|
|
1956
|
+
input.filePath,
|
|
1957
|
+
input.path,
|
|
1958
|
+
input.target_path,
|
|
1959
|
+
input.targetPath,
|
|
1960
|
+
];
|
|
1961
|
+
return candidates.map((candidate) => safeString(candidate).trim()).filter(Boolean);
|
|
1962
|
+
}
|
|
1963
|
+
function commandHasDeepInterviewWriteIntent(command) {
|
|
1964
|
+
return /\bapply_patch\b/.test(command)
|
|
1965
|
+
|| /(?:^|[;&|]\s*)(?:cat|printf|echo)\b[\s\S]{0,240}>\s*[^\s&|;]+/.test(command)
|
|
1966
|
+
|| /\btee\s+(?:-a\s+)?[^\s&|;]+/.test(command)
|
|
1967
|
+
|| /\bsed\s+(?:[^\n;&|]*\s)?-i(?:\b|['"])/.test(command)
|
|
1968
|
+
|| /\b(?:python3?|node|perl|ruby)\b[\s\S]{0,260}\b(?:writeFileSync|writeFile|write_text|open\([^)]*["']w|File\.write|Path\()/.test(command)
|
|
1969
|
+
|| /\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);
|
|
1970
|
+
}
|
|
1971
|
+
function extractDeepInterviewCommandWriteTargets(command) {
|
|
1972
|
+
const targets = [];
|
|
1973
|
+
for (const match of command.matchAll(/(?:^|[^>])>{1,2}\s*(["']?)([^\s&|;<>]+)\1/g)) {
|
|
1974
|
+
const candidate = safeString(match[2]).trim();
|
|
1975
|
+
if (candidate)
|
|
1976
|
+
targets.push(candidate);
|
|
1977
|
+
}
|
|
1978
|
+
for (const match of command.matchAll(/\btee\s+(?:-a\s+)?(["']?)([^\s&|;<>]+)\1/g)) {
|
|
1979
|
+
const candidate = safeString(match[2]).trim();
|
|
1980
|
+
if (candidate)
|
|
1981
|
+
targets.push(candidate);
|
|
1982
|
+
}
|
|
1983
|
+
return targets;
|
|
1984
|
+
}
|
|
1985
|
+
function isAllowedDeepInterviewBashWrite(cwd, command) {
|
|
1986
|
+
if (!commandHasDeepInterviewWriteIntent(command))
|
|
1987
|
+
return true;
|
|
1988
|
+
if (/\bomx\s+(?:state\s+(?:write|read|clear)|question)\b/.test(command))
|
|
1989
|
+
return true;
|
|
1990
|
+
const targets = extractDeepInterviewCommandWriteTargets(command);
|
|
1991
|
+
return targets.length > 0 && targets.every((target) => isAllowedDeepInterviewArtifactPath(cwd, target));
|
|
1992
|
+
}
|
|
1993
|
+
async function readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionId, threadId) {
|
|
1994
|
+
const modeState = sessionId
|
|
1995
|
+
? await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId, stateDir)
|
|
1996
|
+
: await readJsonIfExists(join(stateDir, "deep-interview-state.json"));
|
|
1997
|
+
if (!isActiveDeepInterviewPhase(modeState) || !modeState)
|
|
1998
|
+
return null;
|
|
1999
|
+
if (!modeStateMatchesSkillStopContext(modeState, cwd, sessionId))
|
|
2000
|
+
return null;
|
|
2001
|
+
const canonicalState = sessionId
|
|
2002
|
+
? await readVisibleSkillActiveStateForStateDir(stateDir, sessionId)
|
|
2003
|
+
: await readSkillActiveState(join(stateDir, SKILL_ACTIVE_STATE_FILE));
|
|
2004
|
+
if (!canonicalState)
|
|
2005
|
+
return modeState;
|
|
2006
|
+
const hasActiveDeepInterviewSkill = listActiveSkills(canonicalState).some((entry) => (entry.skill === "deep-interview"
|
|
2007
|
+
&& matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
|
|
2008
|
+
return hasActiveDeepInterviewSkill ? modeState : null;
|
|
2009
|
+
}
|
|
2010
|
+
async function buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir) {
|
|
2011
|
+
const sessionId = readPayloadSessionId(payload);
|
|
2012
|
+
const threadId = readPayloadThreadId(payload);
|
|
2013
|
+
const activeState = await readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionId, threadId);
|
|
2014
|
+
if (!activeState)
|
|
2015
|
+
return null;
|
|
2016
|
+
const toolName = safeString(payload.tool_name).trim();
|
|
2017
|
+
const command = readPreToolUseCommand(payload);
|
|
2018
|
+
const pathCandidates = readPreToolUsePathCandidates(payload);
|
|
2019
|
+
let blocked = false;
|
|
2020
|
+
if (toolName === "Bash") {
|
|
2021
|
+
blocked = !isAllowedDeepInterviewBashWrite(cwd, command);
|
|
2022
|
+
}
|
|
2023
|
+
else if (DEEP_INTERVIEW_IMPLEMENTATION_TOOL_NAMES.has(toolName)) {
|
|
2024
|
+
blocked = pathCandidates.length === 0
|
|
2025
|
+
|| !pathCandidates.every((candidate) => isAllowedDeepInterviewArtifactPath(cwd, candidate));
|
|
2026
|
+
}
|
|
2027
|
+
if (!blocked)
|
|
2028
|
+
return null;
|
|
2029
|
+
const phase = formatPhase(activeState.current_phase ?? activeState.currentPhase, "planning");
|
|
2030
|
+
return {
|
|
2031
|
+
decision: "block",
|
|
2032
|
+
reason: `Deep-interview is active (phase: ${phase}); implementation/write tools are blocked until an explicit handoff workflow is activated.`,
|
|
2033
|
+
hookSpecificOutput: {
|
|
2034
|
+
hookEventName: "PreToolUse",
|
|
2035
|
+
additionalContext: "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`.",
|
|
2036
|
+
},
|
|
2037
|
+
};
|
|
2038
|
+
}
|
|
1727
2039
|
function matchesSkillStopContext(entry, state, sessionId, threadId) {
|
|
1728
2040
|
const entrySessionId = safeString(entry.session_id ?? state.session_id).trim();
|
|
1729
2041
|
const entryThreadId = safeString(entry.thread_id ?? state.thread_id).trim();
|
|
@@ -2175,7 +2487,7 @@ async function maybeReturnRepeatableStopOutput(payload, stateDir, signature, out
|
|
|
2175
2487
|
async function returnPersistentStopBlock(payload, stateDir, signatureKind, signatureValue, output, canonicalSessionId, options = { allowRepeatDuringStopHook: true }) {
|
|
2176
2488
|
return await maybeReturnRepeatableStopOutput(payload, stateDir, buildRepeatableStopSignature(payload, signatureKind, signatureValue, canonicalSessionId), output, canonicalSessionId, options);
|
|
2177
2489
|
}
|
|
2178
|
-
async function findCanonicalActiveTeamForSession(cwd, sessionId) {
|
|
2490
|
+
async function findCanonicalActiveTeamForSession(cwd, sessionId, threadId) {
|
|
2179
2491
|
if (!sessionId.trim())
|
|
2180
2492
|
return null;
|
|
2181
2493
|
const teamsRoot = join(resolveCanonicalTeamStateRoot(cwd), "team");
|
|
@@ -2197,6 +2509,8 @@ async function findCanonicalActiveTeamForSession(cwd, sessionId) {
|
|
|
2197
2509
|
const ownerSessionId = (manifest.leader?.session_id ?? "").trim();
|
|
2198
2510
|
if (ownerSessionId && ownerSessionId !== sessionId.trim())
|
|
2199
2511
|
continue;
|
|
2512
|
+
if (!teamStateMatchesThreadForStop(manifest.leader, threadId))
|
|
2513
|
+
continue;
|
|
2200
2514
|
if (!isNonTerminalPhase(phaseState.current_phase))
|
|
2201
2515
|
continue;
|
|
2202
2516
|
return {
|
|
@@ -2206,18 +2520,18 @@ async function findCanonicalActiveTeamForSession(cwd, sessionId) {
|
|
|
2206
2520
|
}
|
|
2207
2521
|
return null;
|
|
2208
2522
|
}
|
|
2209
|
-
async function resolveActiveTeamNameForStop(cwd, stateDir, sessionId) {
|
|
2210
|
-
const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId);
|
|
2211
|
-
const directTeamName = safeString(directState?.team_name).trim();
|
|
2212
|
-
if (directState?.active === true && directTeamName)
|
|
2523
|
+
async function resolveActiveTeamNameForStop(cwd, stateDir, sessionId, threadId) {
|
|
2524
|
+
const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId, threadId);
|
|
2525
|
+
const directTeamName = safeString(directState?.state.team_name).trim();
|
|
2526
|
+
if (directState?.state.active === true && directTeamName)
|
|
2213
2527
|
return directTeamName;
|
|
2214
|
-
const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, sessionId);
|
|
2528
|
+
const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, sessionId, threadId);
|
|
2215
2529
|
return canonicalTeam?.teamName ?? "";
|
|
2216
2530
|
}
|
|
2217
2531
|
async function maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateDir, sessionId) {
|
|
2218
2532
|
if (!sessionId)
|
|
2219
2533
|
return { matched: false, output: null };
|
|
2220
|
-
const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId);
|
|
2534
|
+
const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId, readPayloadThreadId(payload));
|
|
2221
2535
|
if (!teamName)
|
|
2222
2536
|
return { matched: false, output: null };
|
|
2223
2537
|
const explicitReleaseReadinessContext = hasReleaseReadinessMode(payload)
|
|
@@ -2373,7 +2687,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2373
2687
|
`OMX Ralph completion audit is missing required evidence (${ralphCompletionAuditBlock.reason}; state: ${blockingPath}).`,
|
|
2374
2688
|
"Continue verification and do not report complete yet.",
|
|
2375
2689
|
"Record machine-readable completion evidence before stopping:",
|
|
2376
|
-
|
|
2690
|
+
'- 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',
|
|
2377
2691
|
"- or set completion_audit_path / completion_audit_evidence_path to a repo-relative JSON file with those same fields.",
|
|
2378
2692
|
"Markdown artifacts and flat top-level checklist/evidence fields are not accepted by the Ralph Stop gate.",
|
|
2379
2693
|
].join(" ");
|
|
@@ -2434,7 +2748,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2434
2748
|
const releaseReadinessFinalizeResult = await maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateDir, canonicalSessionId);
|
|
2435
2749
|
if (releaseReadinessFinalizeResult.matched)
|
|
2436
2750
|
return releaseReadinessFinalizeResult.output;
|
|
2437
|
-
const teamOutput = await buildTeamStopOutput(cwd, canonicalSessionId);
|
|
2751
|
+
const teamOutput = await buildTeamStopOutput(cwd, canonicalSessionId, threadId);
|
|
2438
2752
|
if (teamOutput) {
|
|
2439
2753
|
return await returnPersistentStopBlock(payload, stateDir, "team-stop", safeString(teamOutput.stopReason), teamOutput, canonicalSessionId);
|
|
2440
2754
|
}
|
|
@@ -2445,7 +2759,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2445
2759
|
}
|
|
2446
2760
|
const canonicalTeam = await readCanonicalTerminalRunStateForStop(cwd, canonicalSessionId, "team")
|
|
2447
2761
|
? null
|
|
2448
|
-
: await findCanonicalActiveTeamForSession(cwd, canonicalSessionId);
|
|
2762
|
+
: await findCanonicalActiveTeamForSession(cwd, canonicalSessionId, threadId);
|
|
2449
2763
|
if (canonicalTeam) {
|
|
2450
2764
|
const canonicalTeamOutput = buildTeamStopOutputForPhase(canonicalTeam.teamName, canonicalTeam.phase);
|
|
2451
2765
|
const repeatedCanonicalTeamOutput = await returnPersistentStopBlock(payload, stateDir, "team-stop", `${canonicalTeam.teamName}|${canonicalTeam.phase}`, canonicalTeamOutput, canonicalSessionId);
|
|
@@ -2512,6 +2826,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2512
2826
|
let skillState = null;
|
|
2513
2827
|
let triageAdditionalContext = null;
|
|
2514
2828
|
let goalWorkflowAdditionalContext = null;
|
|
2829
|
+
let ultragoalSteeringAdditionalContext = null;
|
|
2515
2830
|
const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
|
|
2516
2831
|
const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
|
|
2517
2832
|
const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
|
|
@@ -2519,10 +2834,12 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2519
2834
|
let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
2520
2835
|
let resolvedNativeSessionId = nativeSessionId;
|
|
2521
2836
|
let skipCanonicalSessionStartContext = false;
|
|
2837
|
+
let isSubagentSessionStart = false;
|
|
2522
2838
|
if (hookEventName === "SessionStart" && nativeSessionId) {
|
|
2523
2839
|
const transcriptPath = safeString(payload.transcript_path ?? payload.transcriptPath).trim();
|
|
2524
2840
|
const subagentSessionStart = readNativeSubagentSessionStartMetadata(transcriptPath);
|
|
2525
2841
|
if (subagentSessionStart && canonicalSessionId) {
|
|
2842
|
+
isSubagentSessionStart = true;
|
|
2526
2843
|
const belongsToCanonicalSession = await nativeSubagentSessionStartBelongsToCanonicalSession(cwd, canonicalSessionId, currentSessionState, subagentSessionStart);
|
|
2527
2844
|
if (belongsToCanonicalSession) {
|
|
2528
2845
|
resolvedNativeSessionId = nativeSessionId;
|
|
@@ -2570,9 +2887,14 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2570
2887
|
].filter(Boolean))]
|
|
2571
2888
|
.map((candidateSessionId) => isNativeSubagentHook(cwd, candidateSessionId, nativeSessionId, threadId)))).some(Boolean)
|
|
2572
2889
|
: false;
|
|
2890
|
+
const suppressNoisySubagentLifecycleDispatch = (isSubagentSessionStart || isSubagentStop)
|
|
2891
|
+
&& shouldSuppressSubagentLifecycleHookDispatch();
|
|
2573
2892
|
if (hookEventName === "UserPromptSubmit") {
|
|
2574
2893
|
const prompt = readPromptText(payload);
|
|
2575
2894
|
goalWorkflowAdditionalContext = await buildGoalWorkflowReconciliationPromptWarning(cwd, prompt).catch(() => null);
|
|
2895
|
+
ultragoalSteeringAdditionalContext = prompt && !isSubagentPromptSubmit
|
|
2896
|
+
? 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)}`)
|
|
2897
|
+
: null;
|
|
2576
2898
|
if (prompt && !isSubagentPromptSubmit) {
|
|
2577
2899
|
skillState = buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessionIdForState, threadId || undefined, turnId || undefined) ?? await recordSkillActivation({
|
|
2578
2900
|
stateDir,
|
|
@@ -2661,7 +2983,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2661
2983
|
const reconcileHudForPromptSubmitFn = options.reconcileHudForPromptSubmitFn ?? reconcileHudForPromptSubmit;
|
|
2662
2984
|
await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => { });
|
|
2663
2985
|
}
|
|
2664
|
-
if (omxEventName && !skipCanonicalSessionStartContext) {
|
|
2986
|
+
if (omxEventName && !skipCanonicalSessionStartContext && !suppressNoisySubagentLifecycleDispatch) {
|
|
2665
2987
|
const baseContext = buildBaseContext(cwd, payload, hookEventName, canonicalSessionId);
|
|
2666
2988
|
if (resolvedNativeSessionId) {
|
|
2667
2989
|
baseContext.native_session_id = resolvedNativeSessionId;
|
|
@@ -2698,7 +3020,12 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2698
3020
|
})
|
|
2699
3021
|
: isSubagentPromptSubmit
|
|
2700
3022
|
? null
|
|
2701
|
-
:
|
|
3023
|
+
: [
|
|
3024
|
+
buildAdditionalContextMessage(readPromptText(payload), skillState, cwd, payload),
|
|
3025
|
+
ultragoalSteeringAdditionalContext,
|
|
3026
|
+
goalWorkflowAdditionalContext,
|
|
3027
|
+
triageAdditionalContext,
|
|
3028
|
+
].filter((entry) => Boolean(entry)).join("\n\n") || null;
|
|
2702
3029
|
if (additionalContext) {
|
|
2703
3030
|
outputJson = {
|
|
2704
3031
|
hookSpecificOutput: {
|
|
@@ -2709,7 +3036,8 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2709
3036
|
}
|
|
2710
3037
|
}
|
|
2711
3038
|
else if (hookEventName === "PreToolUse") {
|
|
2712
|
-
outputJson =
|
|
3039
|
+
outputJson = await buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir)
|
|
3040
|
+
?? buildNativePreToolUseOutput(payload);
|
|
2713
3041
|
}
|
|
2714
3042
|
else if (hookEventName === "PostToolUse") {
|
|
2715
3043
|
if (detectMcpTransportFailure(payload)) {
|