oh-my-codex 0.16.0 → 0.16.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 +5 -5
- package/Cargo.toml +1 -1
- package/README.md +2 -2
- package/crates/omx-explore/src/main.rs +434 -28
- package/dist/agents/__tests__/native-config.test.js +50 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +3 -2
- package/dist/agents/native-config.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +1 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +120 -3
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/imagegen-continuation.test.d.ts +2 -0
- package/dist/cli/__tests__/imagegen-continuation.test.d.ts.map +1 -0
- package/dist/cli/__tests__/imagegen-continuation.test.js +135 -0
- package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -0
- package/dist/cli/__tests__/index.test.js +182 -18
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +88 -2
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +62 -0
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +48 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +12 -0
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +465 -12
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +50 -5
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +6 -2
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +211 -12
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +11 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +124 -18
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +37 -3
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +100 -9
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts +1 -0
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +42 -7
- package/dist/cli/team.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 +29 -8
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +2 -1
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +97 -2
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +22 -0
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/models.test.js +18 -1
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/__tests__/wiki-config-contract.test.js +2 -1
- package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +17 -3
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +102 -2
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +4 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +69 -12
- package/dist/config/generator.js.map +1 -1
- package/dist/config/models.d.ts +6 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +37 -0
- package/dist/config/models.js.map +1 -1
- package/dist/exec/followup.d.ts +1 -0
- package/dist/exec/followup.d.ts.map +1 -1
- package/dist/exec/followup.js +9 -3
- package/dist/exec/followup.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js +19 -0
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js +19 -2
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +40 -0
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/foreground-isolation-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/foreground-isolation-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/foreground-isolation-contract.test.js +28 -0
- package/dist/hooks/__tests__/foreground-isolation-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/keyword-detector.test.js +37 -25
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +10 -4
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/session.test.js +32 -0
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/__tests__/wiki-docs-contract.test.js +6 -4
- package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +1 -1
- package/dist/hooks/codebase-map.d.ts.map +1 -1
- package/dist/hooks/codebase-map.js +3 -2
- package/dist/hooks/codebase-map.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js +6 -4
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/logging.d.ts.map +1 -1
- package/dist/hooks/extensibility/logging.js +3 -2
- package/dist/hooks/extensibility/logging.js.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.js +4 -3
- package/dist/hooks/extensibility/sdk/paths.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +2 -4
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +22 -12
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +8 -7
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +1 -1
- package/dist/hud/__tests__/state.test.js +24 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/index.js +1 -1
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +22 -8
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.js +1 -1
- package/dist/hud/tmux.js.map +1 -1
- package/dist/imagegen/continuation.d.ts +44 -0
- package/dist/imagegen/continuation.d.ts.map +1 -0
- package/dist/imagegen/continuation.js +220 -0
- package/dist/imagegen/continuation.js.map +1 -0
- package/dist/mcp/__tests__/bootstrap.test.js +47 -2
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +49 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +145 -6
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/__tests__/wiki-server.test.js +97 -1
- package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +2 -0
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +95 -15
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/lifecycle-telemetry.d.ts +16 -0
- package/dist/mcp/lifecycle-telemetry.d.ts.map +1 -0
- package/dist/mcp/lifecycle-telemetry.js +95 -0
- package/dist/mcp/lifecycle-telemetry.js.map +1 -0
- package/dist/mcp/wiki-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.js +11 -2
- package/dist/mcp/wiki-server.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +274 -5
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/team-exec.d.ts +2 -0
- package/dist/pipeline/stages/team-exec.d.ts.map +1 -1
- package/dist/pipeline/stages/team-exec.js +51 -26
- package/dist/pipeline/stages/team-exec.js.map +1 -1
- package/dist/planning/__tests__/artifacts.test.js +138 -3
- package/dist/planning/__tests__/artifacts.test.js.map +1 -1
- package/dist/planning/__tests__/context-pack-status.test.d.ts +2 -0
- package/dist/planning/__tests__/context-pack-status.test.d.ts.map +1 -0
- package/dist/planning/__tests__/context-pack-status.test.js +271 -0
- package/dist/planning/__tests__/context-pack-status.test.js.map +1 -0
- package/dist/planning/artifacts.d.ts +12 -1
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +32 -9
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/planning/context-pack-status.d.ts +42 -0
- package/dist/planning/context-pack-status.d.ts.map +1 -0
- package/dist/planning/context-pack-status.js +479 -0
- package/dist/planning/context-pack-status.js.map +1 -0
- package/dist/runtime/__tests__/process-tree.test.d.ts +2 -0
- package/dist/runtime/__tests__/process-tree.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/process-tree.test.js +107 -0
- package/dist/runtime/__tests__/process-tree.test.js.map +1 -0
- package/dist/runtime/process-tree.d.ts +28 -0
- package/dist/runtime/process-tree.d.ts.map +1 -0
- package/dist/runtime/process-tree.js +230 -0
- package/dist/runtime/process-tree.js.map +1 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js +267 -2
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-state-io.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-state-io.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +40 -0
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -0
- package/dist/scripts/codex-execution-surface.d.ts +1 -1
- package/dist/scripts/codex-execution-surface.d.ts.map +1 -1
- package/dist/scripts/codex-execution-surface.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +141 -9
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +6 -9
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/process-runner.d.ts.map +1 -1
- package/dist/scripts/notify-hook/process-runner.js +4 -1
- package/dist/scripts/notify-hook/process-runner.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +4 -7
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook.js +25 -3
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/verify-native-agents.d.ts.map +1 -1
- package/dist/scripts/verify-native-agents.js +3 -1
- package/dist/scripts/verify-native-agents.js.map +1 -1
- package/dist/sidecar/__tests__/tmux.test.js +1 -1
- package/dist/sidecar/__tests__/tmux.test.js.map +1 -1
- package/dist/sidecar/tmux.js +1 -1
- package/dist/sidecar/tmux.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +79 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +10 -18
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +45 -1
- 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 +1 -20
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +1 -0
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +28 -18
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +3 -2
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.js +2 -2
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js +96 -0
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/followup-planner.test.js +16 -0
- package/dist/team/__tests__/followup-planner.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +16 -0
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/repo-aware-decomposition.test.js +20 -0
- package/dist/team/__tests__/repo-aware-decomposition.test.js.map +1 -1
- package/dist/team/__tests__/runtime-cli.test.js +16 -0
- package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +209 -11
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +110 -0
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +9 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +6 -0
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/approved-execution.d.ts +13 -0
- package/dist/team/approved-execution.d.ts.map +1 -1
- package/dist/team/approved-execution.js +40 -22
- package/dist/team/approved-execution.js.map +1 -1
- package/dist/team/followup-planner.d.ts +1 -0
- package/dist/team/followup-planner.d.ts.map +1 -1
- package/dist/team/followup-planner.js +9 -9
- package/dist/team/followup-planner.js.map +1 -1
- package/dist/team/model-contract.d.ts +1 -1
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +4 -3
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/repo-aware-decomposition.d.ts +1 -0
- package/dist/team/repo-aware-decomposition.d.ts.map +1 -1
- package/dist/team/repo-aware-decomposition.js +5 -1
- package/dist/team/repo-aware-decomposition.js.map +1 -1
- package/dist/team/runtime-cli.d.ts +4 -0
- package/dist/team/runtime-cli.d.ts.map +1 -1
- package/dist/team/runtime-cli.js +14 -1
- package/dist/team/runtime-cli.js.map +1 -1
- package/dist/team/runtime.d.ts +1 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +46 -16
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +13 -6
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +7 -0
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +129 -4
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.d.ts +2 -0
- package/dist/ultragoal/__tests__/docs-contract.test.d.ts.map +1 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js +31 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -0
- package/dist/ultragoal/artifacts.d.ts +6 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +108 -4
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/utils/paths.d.ts +3 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +6 -2
- package/dist/utils/paths.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +44 -14
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/wiki/__tests__/ingest.test.js +35 -1
- package/dist/wiki/__tests__/ingest.test.js.map +1 -1
- package/dist/wiki/__tests__/lint.test.js +14 -1
- package/dist/wiki/__tests__/lint.test.js.map +1 -1
- package/dist/wiki/__tests__/query.test.js +28 -3
- package/dist/wiki/__tests__/query.test.js.map +1 -1
- package/dist/wiki/__tests__/session-hooks.test.js +30 -2
- package/dist/wiki/__tests__/session-hooks.test.js.map +1 -1
- package/dist/wiki/__tests__/storage.test.js +62 -22
- package/dist/wiki/__tests__/storage.test.js.map +1 -1
- package/dist/wiki/index.d.ts +2 -2
- package/dist/wiki/index.d.ts.map +1 -1
- package/dist/wiki/index.js +2 -2
- package/dist/wiki/index.js.map +1 -1
- package/dist/wiki/ingest.js +2 -2
- package/dist/wiki/ingest.js.map +1 -1
- package/dist/wiki/lifecycle.d.ts +5 -0
- package/dist/wiki/lifecycle.d.ts.map +1 -1
- package/dist/wiki/lifecycle.js +31 -4
- package/dist/wiki/lifecycle.js.map +1 -1
- package/dist/wiki/lint.d.ts.map +1 -1
- package/dist/wiki/lint.js +12 -8
- package/dist/wiki/lint.js.map +1 -1
- package/dist/wiki/query.d.ts.map +1 -1
- package/dist/wiki/query.js +3 -2
- package/dist/wiki/query.js.map +1 -1
- package/dist/wiki/storage.d.ts +4 -0
- package/dist/wiki/storage.d.ts.map +1 -1
- package/dist/wiki/storage.js +54 -18
- package/dist/wiki/storage.js.map +1 -1
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +9 -0
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +25 -2
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/plan/SKILL.md +7 -4
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +13 -3
- package/plugins/oh-my-codex/skills/team/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +11 -7
- package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +8 -0
- package/plugins/oh-my-codex/skills/wiki/SKILL.md +5 -5
- package/prompts/planner.md +1 -1
- package/skills/ai-slop-cleaner/SKILL.md +9 -0
- package/skills/deep-interview/SKILL.md +25 -2
- package/skills/omx-setup/SKILL.md +1 -1
- package/skills/plan/SKILL.md +7 -4
- package/skills/ralplan/SKILL.md +13 -3
- package/skills/team/SKILL.md +2 -2
- package/skills/ultragoal/SKILL.md +11 -7
- package/skills/visual-ralph/SKILL.md +8 -0
- package/skills/wiki/SKILL.md +5 -5
- package/src/scripts/__tests__/codex-native-hook.test.ts +302 -2
- package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
- package/src/scripts/codex-execution-surface.ts +2 -0
- package/src/scripts/codex-native-hook.ts +163 -16
- package/src/scripts/notify-hook/managed-tmux.ts +6 -7
- package/src/scripts/notify-hook/process-runner.ts +4 -1
- package/src/scripts/notify-hook/state-io.ts +5 -7
- package/src/scripts/notify-hook.ts +26 -3
- package/src/scripts/verify-native-agents.ts +3 -1
package/skills/ralplan/SKILL.md
CHANGED
|
@@ -54,14 +54,24 @@ The consensus workflow:
|
|
|
54
54
|
d. Return to Critic evaluation
|
|
55
55
|
e. Repeat this loop until Critic returns `APPROVE` or 5 iterations are reached
|
|
56
56
|
f. If 5 iterations are reached without `APPROVE`, present the best version to the user
|
|
57
|
-
6. On Critic approval *(--interactive only)*: If `--interactive` is set, use the structured question UI to present the plan with approval options (Approve and execute via ralph / Approve and implement via team / Request changes / Reject). Final plan must include ADR (Decision, Drivers, Alternatives considered, Why chosen, Consequences, Follow-ups), an explicit available-agent-types roster, concrete follow-up staffing guidance for both `ralph` and `team`, suggested reasoning levels by lane, explicit `omx team` / `$team` launch hints,
|
|
58
|
-
7. *(--interactive only)* User chooses: Approve (ralph or
|
|
59
|
-
8. *(--interactive only)* On approval: invoke `$ralph` for sequential execution
|
|
57
|
+
6. On Critic approval *(--interactive only)*: If `--interactive` is set, use the structured question UI to present the plan with approval options (Approve and execute via ralph / Approve and implement via team / Start a goal-mode follow-up / Request changes / Reject). Final plan must include ADR (Decision, Drivers, Alternatives considered, Why chosen, Consequences, Follow-ups), an explicit available-agent-types roster, concrete follow-up staffing guidance for both `ralph` and `team`, suggested reasoning levels by lane, explicit `omx team` / `$team` launch hints, a concrete **team verification** path, and a product-facing **Goal-Mode Follow-up Suggestions** section. Recommend `$ultragoal` by default for goal-mode follow-up, use `$autoresearch-goal` instead when the context is a research project, and use `$performance-goal` instead when the context is an optimization or performance project. Otherwise, output the final plan and stop.
|
|
58
|
+
7. *(--interactive only)* User chooses: Approve (ralph, team, or a goal-mode follow-up), Request changes, or Reject
|
|
59
|
+
8. *(--interactive only)* On approval: invoke `$ralph` for sequential execution, `$team` for parallel team execution, or the selected goal-mode follow-up (`$ultragoal`, `$autoresearch-goal`, or `$performance-goal`) with the approved plan and matching success/evaluator context -- never implement directly. Preserve the explicit available-agent-types roster, reasoning-by-lane guidance, role/staffing allocation guidance, launch hints, and verification-path guidance from the approved plan for Ralph/team paths.
|
|
60
60
|
|
|
61
61
|
> **Important:** Steps 3 and 4 MUST run sequentially. Do NOT issue both agent calls in the same parallel batch. Always await the Architect result before invoking Critic.
|
|
62
62
|
|
|
63
63
|
Follow the Plan skill's full documentation for consensus mode details.
|
|
64
64
|
|
|
65
|
+
## Goal-Mode Follow-up Suggestions
|
|
66
|
+
|
|
67
|
+
When ralplan outputs a final handoff or asks the user to choose a next lane, include product-facing goal-mode suggestions alongside the existing Ralph and team options:
|
|
68
|
+
|
|
69
|
+
- `$ultragoal` — **default goal-mode follow-up** for implementation or general goal-oriented follow-up plans that should become durable Codex/OMX goals with sequential completion tracking.
|
|
70
|
+
- `$autoresearch-goal` — research-project follow-up when the plan centers on a question, literature/reference gathering, evaluator-backed research, or a professor/critic-style research deliverable.
|
|
71
|
+
- `$performance-goal` — optimization/performance follow-up when the plan centers on speed, latency, throughput, memory, benchmark, or other measurable performance work.
|
|
72
|
+
|
|
73
|
+
Keep `$ralph` and `$team` as first-class execution options where appropriate: use Ralph for persistent single-owner completion/verification pressure and team for coordinated parallel implementation. Do not present the goal-mode options as replacements for Ralph/team when the task is mainly implementation delivery; present them as better fits when durable goal tracking, research validation, or performance evaluators are the primary need.
|
|
74
|
+
|
|
65
75
|
## Pre-context Intake
|
|
66
76
|
|
|
67
77
|
Before consensus planning or execution handoff, ensure a grounded context snapshot exists:
|
package/skills/team/SKILL.md
CHANGED
|
@@ -183,7 +183,7 @@ Default-model rule:
|
|
|
183
183
|
Thinking-level rule (critical):
|
|
184
184
|
- **No model-name heuristic mapping.**
|
|
185
185
|
- Team runtime must **not** infer `model_reasoning_effort` from model-name substrings (e.g., `spark`, `high-capability`, `mini`).
|
|
186
|
-
- When the leader assigns teammate roles/tasks, OMX allocates **per-worker reasoning effort dynamically** from the resolved worker role (`low`, `medium`, `high`).
|
|
186
|
+
- When the leader assigns teammate roles/tasks, OMX allocates **per-worker reasoning effort dynamically** from the resolved worker role and `agentReasoning` overrides (`low`, `medium`, `high`, `xhigh`).
|
|
187
187
|
- Explicit launch args still win: if `OMX_TEAM_WORKER_LAUNCH_ARGS` already includes `-c model_reasoning_effort=...`, that explicit value overrides dynamic allocation for every worker.
|
|
188
188
|
|
|
189
189
|
Normalization requirements:
|
|
@@ -191,7 +191,7 @@ Normalization requirements:
|
|
|
191
191
|
- Remove duplicate/conflicting model flags
|
|
192
192
|
- Emit exactly one final canonical flag: `--model <value>`
|
|
193
193
|
- Preserve unrelated args in worker launch config
|
|
194
|
-
- If explicit reasoning exists, preserve canonical `-c model_reasoning_effort="<level>"`; otherwise inject the worker role's default reasoning level
|
|
194
|
+
- If explicit reasoning exists, preserve canonical `-c model_reasoning_effort="<level>"`; otherwise inject the worker role's default or `agentReasoning`-overridden reasoning level
|
|
195
195
|
|
|
196
196
|
## Required Lifecycle (Operator Contract)
|
|
197
197
|
|
|
@@ -9,7 +9,7 @@ Use when the user asks for `ultragoal`, `create-goals`, `complete-goals`, durabl
|
|
|
9
9
|
|
|
10
10
|
## Purpose
|
|
11
11
|
|
|
12
|
-
`ultragoal` turns a brief into repo-native artifacts and then drives
|
|
12
|
+
`ultragoal` turns a brief into repo-native artifacts and then drives a Codex goal safely through goal tools. New plans default to an aggregate Codex goal for the whole ultragoal run while OMX tracks G001/G002 story progress in the ledger.
|
|
13
13
|
|
|
14
14
|
- `.omx/ultragoal/brief.md`
|
|
15
15
|
- `.omx/ultragoal/goals.json`
|
|
@@ -21,6 +21,7 @@ Use when the user asks for `ultragoal`, `create-goals`, `complete-goals`, durabl
|
|
|
21
21
|
- `omx ultragoal create-goals --brief "<brief>"`
|
|
22
22
|
- `omx ultragoal create-goals --brief-file <path>`
|
|
23
23
|
- `cat <brief> | omx ultragoal create-goals --from-stdin`
|
|
24
|
+
- `omx ultragoal create-goals --codex-goal-mode per-story --brief "<brief>"` only when one fresh Codex thread per story is explicitly preferred
|
|
24
25
|
2. Inspect `.omx/ultragoal/goals.json` and refine if needed.
|
|
25
26
|
|
|
26
27
|
## Complete goals
|
|
@@ -30,20 +31,23 @@ Loop until `omx ultragoal status` reports all goals complete:
|
|
|
30
31
|
1. Run `omx ultragoal complete-goals`.
|
|
31
32
|
2. Read the printed handoff.
|
|
32
33
|
3. Call `get_goal`.
|
|
33
|
-
4. If no active Codex goal exists, call `create_goal` with the printed payload.
|
|
34
|
-
5. Complete
|
|
35
|
-
6. Run a completion audit against the objective and real artifacts/tests.
|
|
36
|
-
7.
|
|
34
|
+
4. If no active Codex goal exists, call `create_goal` with the printed payload. In aggregate mode, if the same aggregate Codex objective is already active, continue the current OMX story without creating a new Codex goal.
|
|
35
|
+
5. Complete the current OMX story only.
|
|
36
|
+
6. Run a completion audit against the story objective and real artifacts/tests.
|
|
37
|
+
7. In aggregate mode, do **not** call `update_goal` for intermediate stories; checkpoint with a fresh `get_goal` snapshot whose aggregate objective is still `active`. On the final story only, call `update_goal({status: "complete"})`, then call `get_goal` again for a fresh `complete` snapshot.
|
|
37
38
|
8. Checkpoint the durable ledger with that snapshot:
|
|
38
39
|
`omx ultragoal checkpoint --goal-id <id> --status complete --evidence "<evidence>" --codex-goal-json <get_goal-json-or-path>`
|
|
39
40
|
9. If blocked or failed, checkpoint failure:
|
|
40
41
|
`omx ultragoal checkpoint --goal-id <id> --status failed --evidence "<blocker/evidence>"`
|
|
41
|
-
10.
|
|
42
|
+
10. For legacy per-story completed-goal blockers, preserve the non-terminal blocker with:
|
|
43
|
+
`omx ultragoal checkpoint --goal-id <id> --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json <get_goal-json-or-path>`
|
|
44
|
+
11. Resume failed goals with `omx ultragoal complete-goals --retry-failed`.
|
|
42
45
|
|
|
43
46
|
## Constraints
|
|
44
47
|
|
|
45
48
|
- The shell command cannot directly invoke Codex interactive `/goal`; it emits a model-facing handoff for the active Codex agent.
|
|
46
49
|
- Never call `create_goal` when `get_goal` reports a different active goal.
|
|
47
|
-
- Never call `update_goal` unless the
|
|
50
|
+
- Never call `update_goal` unless the aggregate run or legacy per-story goal is actually complete.
|
|
51
|
+
- In aggregate mode, intermediate story checkpoints require a matching `active` Codex snapshot; final story completion requires a matching `complete` snapshot after `update_goal`.
|
|
48
52
|
- Completion checkpoints require read-only Codex snapshot reconciliation: pass fresh `get_goal` JSON/path with `--codex-goal-json`; shell commands and hooks must not mutate Codex goal state.
|
|
49
53
|
- Treat `ledger.jsonl` as the durable audit trail; checkpoint after every success or failure.
|
|
@@ -65,6 +65,14 @@ Prompt requirements:
|
|
|
65
65
|
- forbid logos/watermarks/unrequested brand marks,
|
|
66
66
|
- ask imagegen to avoid impossible UI details or unreadable text.
|
|
67
67
|
|
|
68
|
+
When running under OMX CLI/runtime and a generated reference is part of an active Ralph-style loop, queue a continuation checkpoint before invoking the built-in image tool:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
omx imagegen continuation <session-id> --artifact <slug-or-filename> --generated-dir "$CODEX_HOME/generated_images/<session>" --work-dir ".omx/artifacts/visual-ralph/<slug>"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This helper records `.omx/state/sessions/<session>/imagegen-pending.json` and uses the existing Stop-hook follow-up queue. It exists because built-in image generation may have to end the assistant turn immediately; the next Stop checkpoint should resume artifact recovery, copy the generated image into the workspace, and run the required visual QA/verdict gate instead of relying on a manual `$ralph` re-prompt.
|
|
75
|
+
|
|
68
76
|
For project-bound implementation, copy the approved reference into the workspace, for example under `.omx/artifacts/visual-ralph/<slug>/reference.png`. Never leave the implementation reference only in `$CODEX_HOME/generated_images/...`.
|
|
69
77
|
|
|
70
78
|
### 3. Require explicit user approval
|
package/skills/wiki/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wiki
|
|
3
|
-
description: Persistent markdown project wiki stored under
|
|
3
|
+
description: Persistent markdown project wiki stored under repository omx_wiki with keyword search and lifecycle capture
|
|
4
4
|
triggers: ["wiki add", "wiki lint", "wiki query", "wiki read", "wiki delete"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -42,9 +42,9 @@ wiki_refresh()
|
|
|
42
42
|
`architecture`, `decision`, `pattern`, `debugging`, `environment`, `session-log`, `reference`, `convention`
|
|
43
43
|
|
|
44
44
|
## Storage
|
|
45
|
-
- Pages:
|
|
46
|
-
- Index:
|
|
47
|
-
- Log:
|
|
45
|
+
- Pages: `omx_wiki/*.md`
|
|
46
|
+
- Index: `omx_wiki/index.md`
|
|
47
|
+
- Log: `omx_wiki/log.md`
|
|
48
48
|
|
|
49
49
|
## Cross-References
|
|
50
50
|
Use `[[page-name]]` wiki-link syntax to create cross-references between pages.
|
|
@@ -54,4 +54,4 @@ At session end, discoveries can be captured as `session-log-*` pages. Configure
|
|
|
54
54
|
|
|
55
55
|
## Hard Constraints
|
|
56
56
|
- No vector embeddings — query uses keyword + tag matching only
|
|
57
|
-
- Wiki files
|
|
57
|
+
- Wiki files are repository project knowledge under `omx_wiki/`; legacy `.omx/wiki/` is read-only compatibility input when no canonical wiki exists
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { chmod, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
@@ -24,6 +24,8 @@ import { writeSessionStart } from "../../hooks/session.js";
|
|
|
24
24
|
import { resetTriageConfigCache } from "../../hooks/triage-config.js";
|
|
25
25
|
import { executeStateOperation } from "../../state/operations.js";
|
|
26
26
|
import { OMX_TMUX_HUD_OWNER_ENV } from "../../hud/reconcile.js";
|
|
27
|
+
import { writePage } from "../../wiki/storage.js";
|
|
28
|
+
import { WIKI_SCHEMA_VERSION } from "../../wiki/types.js";
|
|
27
29
|
|
|
28
30
|
function nativeHookScriptPath(): string {
|
|
29
31
|
return join(process.cwd(), "dist", "scripts", "codex-native-hook.js");
|
|
@@ -188,6 +190,8 @@ const TEAM_ENV_KEYS = [
|
|
|
188
190
|
"OMX_TEAM_STATE_ROOT",
|
|
189
191
|
"OMX_TEAM_LEADER_CWD",
|
|
190
192
|
"OMX_SESSION_ID",
|
|
193
|
+
"OMX_ROOT",
|
|
194
|
+
"OMX_STATE_ROOT",
|
|
191
195
|
"SESSION_ID",
|
|
192
196
|
"OMX_QUESTION_RETURN_PANE",
|
|
193
197
|
"OMX_LEADER_PANE_ID",
|
|
@@ -223,6 +227,8 @@ describe("codex native hook config", () => {
|
|
|
223
227
|
"PreToolUse",
|
|
224
228
|
"PostToolUse",
|
|
225
229
|
"UserPromptSubmit",
|
|
230
|
+
"PreCompact",
|
|
231
|
+
"PostCompact",
|
|
226
232
|
"Stop",
|
|
227
233
|
]);
|
|
228
234
|
|
|
@@ -437,14 +443,142 @@ describe("codex native hook dispatch", () => {
|
|
|
437
443
|
}
|
|
438
444
|
});
|
|
439
445
|
|
|
446
|
+
it("logs Stop dispatch failures without foreground stderr noise", async () => {
|
|
447
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-cli-stop-dispatch-silent-"));
|
|
448
|
+
try {
|
|
449
|
+
const result = spawnSync(process.execPath, [nativeHookScriptPath()], {
|
|
450
|
+
cwd,
|
|
451
|
+
input: JSON.stringify({
|
|
452
|
+
hook_event_name: "Stop",
|
|
453
|
+
cwd,
|
|
454
|
+
session_id: "sess-cli-stop-dispatch-silent",
|
|
455
|
+
thread_id: "thread-cli-stop-dispatch-silent",
|
|
456
|
+
turn_id: "turn-cli-stop-dispatch-silent",
|
|
457
|
+
}),
|
|
458
|
+
encoding: "utf-8",
|
|
459
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
460
|
+
env: {
|
|
461
|
+
...process.env,
|
|
462
|
+
NODE_ENV: "test",
|
|
463
|
+
OMX_NATIVE_HOOK_TEST_THROW_STOP_DISPATCH: "1",
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
468
|
+
assert.equal(result.stderr, "");
|
|
469
|
+
const output = parseSingleJsonStdout(result.stdout);
|
|
470
|
+
assert.equal(output.stopReason, "native_stop_dispatch_failure");
|
|
471
|
+
|
|
472
|
+
const logFiles = await readdir(join(cwd, ".omx", "logs"));
|
|
473
|
+
assert.equal(logFiles.some((name) => /^native-hook-\d{4}-\d{2}-\d{2}\.jsonl$/.test(name)), true);
|
|
474
|
+
} finally {
|
|
475
|
+
await rm(cwd, { recursive: true, force: true });
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it("keeps non-Stop dispatch failures fail-closed without foreground stderr noise", async () => {
|
|
480
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-cli-pretool-dispatch-silent-"));
|
|
481
|
+
try {
|
|
482
|
+
const result = spawnSync(process.execPath, [nativeHookScriptPath()], {
|
|
483
|
+
cwd,
|
|
484
|
+
input: JSON.stringify({
|
|
485
|
+
hook_event_name: "PreToolUse",
|
|
486
|
+
cwd,
|
|
487
|
+
session_id: "sess-cli-pretool-dispatch-silent",
|
|
488
|
+
thread_id: "thread-cli-pretool-dispatch-silent",
|
|
489
|
+
turn_id: "turn-cli-pretool-dispatch-silent",
|
|
490
|
+
tool_name: "Bash",
|
|
491
|
+
tool_input: { command: "pwd" },
|
|
492
|
+
}),
|
|
493
|
+
encoding: "utf-8",
|
|
494
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
495
|
+
env: {
|
|
496
|
+
...process.env,
|
|
497
|
+
NODE_ENV: "test",
|
|
498
|
+
OMX_NATIVE_HOOK_TEST_THROW_DISPATCH: "1",
|
|
499
|
+
},
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
assert.equal(result.status, 1);
|
|
503
|
+
assert.equal(result.stdout, "");
|
|
504
|
+
assert.equal(result.stderr, "");
|
|
505
|
+
|
|
506
|
+
const logFiles = await readdir(join(cwd, ".omx", "logs"));
|
|
507
|
+
assert.equal(logFiles.some((name) => /^native-hook-\d{4}-\d{2}-\d{2}\.jsonl$/.test(name)), true);
|
|
508
|
+
} finally {
|
|
509
|
+
await rm(cwd, { recursive: true, force: true });
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
|
|
440
513
|
it("maps Codex events onto OMX logical surfaces", () => {
|
|
441
514
|
assert.equal(mapCodexHookEventToOmxEvent("SessionStart"), "session-start");
|
|
442
515
|
assert.equal(mapCodexHookEventToOmxEvent("UserPromptSubmit"), "keyword-detector");
|
|
443
516
|
assert.equal(mapCodexHookEventToOmxEvent("PreToolUse"), "pre-tool-use");
|
|
444
517
|
assert.equal(mapCodexHookEventToOmxEvent("PostToolUse"), "post-tool-use");
|
|
518
|
+
assert.equal(mapCodexHookEventToOmxEvent("PreCompact"), "pre-compact");
|
|
519
|
+
assert.equal(mapCodexHookEventToOmxEvent("PostCompact"), "post-compact");
|
|
445
520
|
assert.equal(mapCodexHookEventToOmxEvent("Stop"), "stop");
|
|
446
521
|
});
|
|
447
522
|
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
it("returns bounded wiki context for PreCompact", async () => {
|
|
526
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-precompact-"));
|
|
527
|
+
try {
|
|
528
|
+
writePage(cwd, {
|
|
529
|
+
filename: "architecture.md",
|
|
530
|
+
frontmatter: {
|
|
531
|
+
title: "Architecture",
|
|
532
|
+
tags: ["architecture"],
|
|
533
|
+
created: "2026-05-08T00:00:00.000Z",
|
|
534
|
+
updated: "2026-05-08T00:00:00.000Z",
|
|
535
|
+
sources: [],
|
|
536
|
+
links: [],
|
|
537
|
+
category: "architecture",
|
|
538
|
+
confidence: "high",
|
|
539
|
+
schemaVersion: WIKI_SCHEMA_VERSION,
|
|
540
|
+
},
|
|
541
|
+
content: "\n# Architecture\n\nCompaction-relevant architecture note.\n",
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
const result = await dispatchCodexNativeHook({
|
|
545
|
+
hook_event_name: "PreCompact",
|
|
546
|
+
cwd,
|
|
547
|
+
session_id: "sess-precompact",
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
assert.equal(result.hookEventName, "PreCompact");
|
|
551
|
+
assert.equal(result.omxEventName, "pre-compact");
|
|
552
|
+
const additionalContext = (result.outputJson as { hookSpecificOutput?: { additionalContext?: string } } | null)
|
|
553
|
+
?.hookSpecificOutput?.additionalContext ?? "";
|
|
554
|
+
assert.match(additionalContext, /Wiki: 1 pages/);
|
|
555
|
+
assert.match(additionalContext, /architecture/);
|
|
556
|
+
} finally {
|
|
557
|
+
await rm(cwd, { recursive: true, force: true });
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
it("returns a PostCompact nudge to write compaction artifacts to omx_wiki", async () => {
|
|
562
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-postcompact-"));
|
|
563
|
+
try {
|
|
564
|
+
const result = await dispatchCodexNativeHook({
|
|
565
|
+
hook_event_name: "PostCompact",
|
|
566
|
+
cwd,
|
|
567
|
+
session_id: "sess-postcompact",
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
assert.equal(result.hookEventName, "PostCompact");
|
|
571
|
+
assert.equal(result.omxEventName, "post-compact");
|
|
572
|
+
const additionalContext = (result.outputJson as { hookSpecificOutput?: { additionalContext?: string } } | null)
|
|
573
|
+
?.hookSpecificOutput?.additionalContext ?? "";
|
|
574
|
+
assert.match(additionalContext, /PostCompact Nudge/);
|
|
575
|
+
assert.match(additionalContext, /omx_wiki/);
|
|
576
|
+
assert.match(additionalContext, /compaction artifacts/);
|
|
577
|
+
} finally {
|
|
578
|
+
await rm(cwd, { recursive: true, force: true });
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
|
|
448
582
|
it("writes SessionStart state against the long-lived session owner pid and injects environment context", async () => {
|
|
449
583
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-session-start-"));
|
|
450
584
|
try {
|
|
@@ -1032,7 +1166,12 @@ describe("codex native hook dispatch", () => {
|
|
|
1032
1166
|
assert.ok(result.outputJson, "UserPromptSubmit should emit developer context");
|
|
1033
1167
|
assert.match(JSON.stringify(result.outputJson), /skill: ralplan activated and initial state initialized at \.omx\/state\/sessions\/sess-1\/ralplan-state\.json; write subsequent updates via omx_state MCP\./);
|
|
1034
1168
|
|
|
1035
|
-
|
|
1169
|
+
assert.equal(
|
|
1170
|
+
existsSync(join(cwd, ".omx", "state", "skill-active-state.json")),
|
|
1171
|
+
false,
|
|
1172
|
+
"session-scoped keyword activation should not write root skill-active-state.json",
|
|
1173
|
+
);
|
|
1174
|
+
const statePath = join(cwd, ".omx", "state", "sessions", "sess-1", "skill-active-state.json");
|
|
1036
1175
|
assert.equal(existsSync(statePath), true);
|
|
1037
1176
|
const state = JSON.parse(await readFile(statePath, "utf-8")) as {
|
|
1038
1177
|
skill?: string;
|
|
@@ -8409,6 +8548,167 @@ exit 0
|
|
|
8409
8548
|
}
|
|
8410
8549
|
});
|
|
8411
8550
|
|
|
8551
|
+
it("clears stale root skill-active state when current session ralplan is terminal", async () => {
|
|
8552
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-stale-root-skill-terminal-"));
|
|
8553
|
+
try {
|
|
8554
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
8555
|
+
const sessionId = "sess-stop-terminal-ralplan";
|
|
8556
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
8557
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
8558
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
8559
|
+
active: false,
|
|
8560
|
+
mode: "ralplan",
|
|
8561
|
+
current_phase: "completed",
|
|
8562
|
+
lifecycle_outcome: "finished",
|
|
8563
|
+
run_outcome: "finish",
|
|
8564
|
+
final_artifact: "proposed_plan",
|
|
8565
|
+
});
|
|
8566
|
+
await writeJson(join(stateDir, "skill-active-state.json"), {
|
|
8567
|
+
active: true,
|
|
8568
|
+
skill: "ultrawork",
|
|
8569
|
+
phase: "planning",
|
|
8570
|
+
source: "keyword-detector",
|
|
8571
|
+
active_skills: [
|
|
8572
|
+
{ skill: "ultrawork", phase: "planning", active: true },
|
|
8573
|
+
],
|
|
8574
|
+
});
|
|
8575
|
+
|
|
8576
|
+
const result = await dispatchCodexNativeHook(
|
|
8577
|
+
{
|
|
8578
|
+
hook_event_name: "Stop",
|
|
8579
|
+
cwd,
|
|
8580
|
+
session_id: sessionId,
|
|
8581
|
+
thread_id: "thread-stop-terminal-ralplan",
|
|
8582
|
+
turn_id: "turn-stop-terminal-ralplan-1",
|
|
8583
|
+
last_assistant_message: "Done.",
|
|
8584
|
+
},
|
|
8585
|
+
{ cwd },
|
|
8586
|
+
);
|
|
8587
|
+
|
|
8588
|
+
assert.equal(result.omxEventName, "stop");
|
|
8589
|
+
assert.equal(result.outputJson, null);
|
|
8590
|
+
|
|
8591
|
+
const rootSkillState = JSON.parse(
|
|
8592
|
+
await readFile(join(stateDir, "skill-active-state.json"), "utf-8"),
|
|
8593
|
+
) as { active?: boolean; active_skills?: unknown[]; reconciliation_reason?: string };
|
|
8594
|
+
assert.equal(rootSkillState.active, false);
|
|
8595
|
+
assert.deepEqual(rootSkillState.active_skills, []);
|
|
8596
|
+
assert.equal(rootSkillState.reconciliation_reason, "stop_hook_session_state_terminal");
|
|
8597
|
+
} finally {
|
|
8598
|
+
await rm(cwd, { recursive: true, force: true });
|
|
8599
|
+
}
|
|
8600
|
+
});
|
|
8601
|
+
|
|
8602
|
+
it("preserves legitimate session-scoped ultrawork blocking while reconciling root skill-active state", async () => {
|
|
8603
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-active-root-skill-session-mode-"));
|
|
8604
|
+
try {
|
|
8605
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
8606
|
+
const sessionId = "sess-stop-active-ultrawork";
|
|
8607
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
8608
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
8609
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ultrawork-state.json"), {
|
|
8610
|
+
active: true,
|
|
8611
|
+
mode: "ultrawork",
|
|
8612
|
+
current_phase: "executing",
|
|
8613
|
+
session_id: sessionId,
|
|
8614
|
+
});
|
|
8615
|
+
await writeJson(join(stateDir, "skill-active-state.json"), {
|
|
8616
|
+
active: true,
|
|
8617
|
+
skill: "ultrawork",
|
|
8618
|
+
phase: "planning",
|
|
8619
|
+
source: "keyword-detector",
|
|
8620
|
+
active_skills: [
|
|
8621
|
+
{ skill: "ultrawork", phase: "planning", active: true, session_id: sessionId },
|
|
8622
|
+
],
|
|
8623
|
+
});
|
|
8624
|
+
|
|
8625
|
+
const result = await dispatchCodexNativeHook(
|
|
8626
|
+
{
|
|
8627
|
+
hook_event_name: "Stop",
|
|
8628
|
+
cwd,
|
|
8629
|
+
session_id: sessionId,
|
|
8630
|
+
thread_id: "thread-stop-active-ultrawork",
|
|
8631
|
+
turn_id: "turn-stop-active-ultrawork-1",
|
|
8632
|
+
},
|
|
8633
|
+
{ cwd },
|
|
8634
|
+
);
|
|
8635
|
+
|
|
8636
|
+
assert.equal(result.omxEventName, "stop");
|
|
8637
|
+
assert.deepEqual(result.outputJson, {
|
|
8638
|
+
decision: "block",
|
|
8639
|
+
reason: "OMX ultrawork is still active (phase: executing); continue the task and gather fresh verification evidence before stopping.",
|
|
8640
|
+
stopReason: "ultrawork_executing",
|
|
8641
|
+
systemMessage: "OMX ultrawork is still active (phase: executing).",
|
|
8642
|
+
});
|
|
8643
|
+
|
|
8644
|
+
const rootSkillState = JSON.parse(
|
|
8645
|
+
await readFile(join(stateDir, "skill-active-state.json"), "utf-8"),
|
|
8646
|
+
) as { active?: boolean; active_skills?: Array<{ skill?: string }> };
|
|
8647
|
+
assert.equal(rootSkillState.active, true);
|
|
8648
|
+
assert.deepEqual(rootSkillState.active_skills?.map((entry) => entry.skill), ["ultrawork"]);
|
|
8649
|
+
} finally {
|
|
8650
|
+
await rm(cwd, { recursive: true, force: true });
|
|
8651
|
+
}
|
|
8652
|
+
});
|
|
8653
|
+
|
|
8654
|
+
it("reconciles stale root skill-active state under OMX_ROOT boxed state", async () => {
|
|
8655
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-boxed-source-"));
|
|
8656
|
+
const omxRoot = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-boxed-root-"));
|
|
8657
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
8658
|
+
try {
|
|
8659
|
+
process.env.OMX_ROOT = omxRoot;
|
|
8660
|
+
const stateDir = join(omxRoot, ".omx", "state");
|
|
8661
|
+
const sourceStateDir = join(cwd, ".omx", "state");
|
|
8662
|
+
const sessionId = "sess-stop-boxed-ralplan";
|
|
8663
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
8664
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
8665
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
8666
|
+
active: false,
|
|
8667
|
+
mode: "ralplan",
|
|
8668
|
+
current_phase: "completed",
|
|
8669
|
+
lifecycle_outcome: "finished",
|
|
8670
|
+
run_outcome: "finish",
|
|
8671
|
+
});
|
|
8672
|
+
await writeJson(join(stateDir, "skill-active-state.json"), {
|
|
8673
|
+
active: true,
|
|
8674
|
+
skill: "ultrawork",
|
|
8675
|
+
phase: "planning",
|
|
8676
|
+
source: "keyword-detector",
|
|
8677
|
+
active_skills: [
|
|
8678
|
+
{ skill: "ultrawork", phase: "planning", active: true },
|
|
8679
|
+
],
|
|
8680
|
+
});
|
|
8681
|
+
|
|
8682
|
+
const result = await dispatchCodexNativeHook(
|
|
8683
|
+
{
|
|
8684
|
+
hook_event_name: "Stop",
|
|
8685
|
+
cwd,
|
|
8686
|
+
session_id: sessionId,
|
|
8687
|
+
thread_id: "thread-stop-boxed-ralplan",
|
|
8688
|
+
turn_id: "turn-stop-boxed-ralplan-1",
|
|
8689
|
+
last_assistant_message: "Done.",
|
|
8690
|
+
},
|
|
8691
|
+
{ cwd },
|
|
8692
|
+
);
|
|
8693
|
+
|
|
8694
|
+
assert.equal(result.omxEventName, "stop");
|
|
8695
|
+
assert.equal(result.outputJson, null);
|
|
8696
|
+
|
|
8697
|
+
const boxedRootSkillState = JSON.parse(
|
|
8698
|
+
await readFile(join(stateDir, "skill-active-state.json"), "utf-8"),
|
|
8699
|
+
) as { active?: boolean; active_skills?: unknown[]; reconciliation_reason?: string };
|
|
8700
|
+
assert.equal(boxedRootSkillState.active, false);
|
|
8701
|
+
assert.deepEqual(boxedRootSkillState.active_skills, []);
|
|
8702
|
+
assert.equal(boxedRootSkillState.reconciliation_reason, "stop_hook_session_state_terminal");
|
|
8703
|
+
assert.equal(existsSync(join(sourceStateDir, "skill-active-state.json")), false);
|
|
8704
|
+
} finally {
|
|
8705
|
+
if (previousOmxRoot === undefined) delete process.env.OMX_ROOT;
|
|
8706
|
+
else process.env.OMX_ROOT = previousOmxRoot;
|
|
8707
|
+
await rm(cwd, { recursive: true, force: true });
|
|
8708
|
+
await rm(omxRoot, { recursive: true, force: true });
|
|
8709
|
+
}
|
|
8710
|
+
});
|
|
8711
|
+
|
|
8412
8712
|
it("auto-continues native Stop for permission-seeking prompts even outside OMX runtime", async () => {
|
|
8413
8713
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-auto-nudge-plain-session-"));
|
|
8414
8714
|
try {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
getScopedStatePath,
|
|
9
|
+
readScopedJsonIfExists,
|
|
10
|
+
resolveScopedStateDir,
|
|
11
|
+
writeScopedJson,
|
|
12
|
+
} from '../notify-hook/state-io.js';
|
|
13
|
+
|
|
14
|
+
describe('notify-hook state I/O session authority', () => {
|
|
15
|
+
it('uses an explicit session id before the current session pointer', async () => {
|
|
16
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-notify-state-io-'));
|
|
17
|
+
try {
|
|
18
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
19
|
+
await mkdir(join(stateDir, 'sessions', 'sess-current'), { recursive: true });
|
|
20
|
+
await mkdir(join(stateDir, 'sessions', 'sess-explicit'), { recursive: true });
|
|
21
|
+
await writeFile(
|
|
22
|
+
join(stateDir, 'session.json'),
|
|
23
|
+
JSON.stringify({ session_id: 'sess-current', cwd: wd }, null, 2),
|
|
24
|
+
'utf-8',
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
assert.equal(
|
|
28
|
+
await resolveScopedStateDir(stateDir, 'sess-explicit'),
|
|
29
|
+
join(stateDir, 'sessions', 'sess-explicit'),
|
|
30
|
+
);
|
|
31
|
+
assert.equal(
|
|
32
|
+
await getScopedStatePath(stateDir, 'hud-state.json', 'sess-explicit'),
|
|
33
|
+
join(stateDir, 'sessions', 'sess-explicit', 'hud-state.json'),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
await writeScopedJson(stateDir, 'hud-state.json', 'sess-explicit', { turn_count: 3 });
|
|
37
|
+
const explicitHud = JSON.parse(
|
|
38
|
+
await readFile(join(stateDir, 'sessions', 'sess-explicit', 'hud-state.json'), 'utf-8'),
|
|
39
|
+
) as { turn_count?: unknown };
|
|
40
|
+
assert.equal(explicitHud.turn_count, 3);
|
|
41
|
+
} finally {
|
|
42
|
+
await rm(wd, { recursive: true, force: true });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('does not read current-session data when an explicit session has no state file', async () => {
|
|
47
|
+
const wd = await mkdtemp(join(tmpdir(), 'omx-notify-state-io-missing-'));
|
|
48
|
+
try {
|
|
49
|
+
const stateDir = join(wd, '.omx', 'state');
|
|
50
|
+
await mkdir(join(stateDir, 'sessions', 'sess-current'), { recursive: true });
|
|
51
|
+
await writeFile(
|
|
52
|
+
join(stateDir, 'session.json'),
|
|
53
|
+
JSON.stringify({ session_id: 'sess-current', cwd: wd }, null, 2),
|
|
54
|
+
'utf-8',
|
|
55
|
+
);
|
|
56
|
+
await writeFile(
|
|
57
|
+
join(stateDir, 'sessions', 'sess-current', 'auto-nudge-state.json'),
|
|
58
|
+
JSON.stringify({ count: 9 }, null, 2),
|
|
59
|
+
'utf-8',
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const value = await readScopedJsonIfExists(
|
|
63
|
+
stateDir,
|
|
64
|
+
'auto-nudge-state.json',
|
|
65
|
+
'sess-explicit',
|
|
66
|
+
null,
|
|
67
|
+
);
|
|
68
|
+
assert.equal(value, null);
|
|
69
|
+
} finally {
|
|
70
|
+
await rm(wd, { recursive: true, force: true });
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|