oh-my-codex 0.13.2 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +5 -5
- package/Cargo.toml +1 -1
- package/README.md +14 -8
- package/crates/omx-explore/src/main.rs +94 -1
- package/crates/omx-sparkshell/src/codex_bridge.rs +59 -12
- package/crates/omx-sparkshell/tests/execution.rs +48 -0
- package/dist/autoresearch/__tests__/skill-validation.test.d.ts +2 -0
- package/dist/autoresearch/__tests__/skill-validation.test.d.ts.map +1 -0
- package/dist/autoresearch/__tests__/skill-validation.test.js +91 -0
- package/dist/autoresearch/__tests__/skill-validation.test.js.map +1 -0
- package/dist/autoresearch/skill-validation.d.ts +13 -0
- package/dist/autoresearch/skill-validation.d.ts.map +1 -0
- package/dist/autoresearch/skill-validation.js +165 -0
- package/dist/autoresearch/skill-validation.js.map +1 -0
- package/dist/catalog/__tests__/schema.test.js +6 -0
- package/dist/catalog/__tests__/schema.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js +236 -273
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch.test.js +64 -653
- package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +33 -1
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +18 -2
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/nested-help-routing.test.js +2 -1
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +5 -0
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.d.ts +2 -0
- package/dist/cli/__tests__/question.test.d.ts.map +1 -0
- package/dist/cli/__tests__/question.test.js +166 -0
- package/dist/cli/__tests__/question.test.js.map +1 -0
- package/dist/cli/__tests__/session-search-help.test.js +1 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +32 -7
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +8 -6
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -0
- package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +23 -0
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +65 -5
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +360 -26
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/autoresearch-guided.d.ts +24 -7
- package/dist/cli/autoresearch-guided.d.ts.map +1 -1
- package/dist/cli/autoresearch-guided.js +189 -130
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/autoresearch.d.ts +3 -2
- package/dist/cli/autoresearch.d.ts.map +1 -1
- package/dist/cli/autoresearch.js +29 -305
- package/dist/cli/autoresearch.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +43 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +18 -3
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +15 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/question.d.ts +3 -0
- package/dist/cli/question.d.ts.map +1 -0
- package/dist/cli/question.js +182 -0
- package/dist/cli/question.js.map +1 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +25 -3
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.d.ts.map +1 -1
- package/dist/cli/sparkshell.js +11 -1
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +159 -394
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +3 -1
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update.d.ts +37 -9
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +204 -26
- package/dist/cli/update.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +51 -14
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +35 -10
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/generator.d.ts +1 -0
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +61 -7
- package/dist/config/generator.js.map +1 -1
- package/dist/hooks/__tests__/analyze-routing-contract.test.js +22 -13
- package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js +3 -3
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/code-review-skill-contract.test.js +56 -0
- package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.js +2 -2
- package/dist/hooks/__tests__/debugger-log-recency-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +51 -5
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js +43 -0
- package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js +38 -0
- package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +2 -2
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +308 -17
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +570 -2
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +717 -16
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +25 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +894 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +34 -0
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +132 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js +22 -4
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js +4 -2
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts +1 -0
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js +19 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +28 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js +5 -4
- package/dist/hooks/__tests__/prompt-orchestration-boundary.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-team-routing.test.js +2 -2
- package/dist/hooks/__tests__/prompt-team-routing.test.js.map +1 -1
- package/dist/hooks/__tests__/triage-config.test.d.ts +2 -0
- package/dist/hooks/__tests__/triage-config.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/triage-config.test.js +211 -0
- package/dist/hooks/__tests__/triage-config.test.js.map +1 -0
- package/dist/hooks/__tests__/triage-heuristic.test.d.ts +2 -0
- package/dist/hooks/__tests__/triage-heuristic.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/triage-heuristic.test.js +230 -0
- package/dist/hooks/__tests__/triage-heuristic.test.js.map +1 -0
- package/dist/hooks/__tests__/triage-state.test.d.ts +2 -0
- package/dist/hooks/__tests__/triage-state.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/triage-state.test.js +426 -0
- package/dist/hooks/__tests__/triage-state.test.js.map +1 -0
- package/dist/hooks/keyword-detector.d.ts +26 -7
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +97 -26
- 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 +16 -9
- 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 +28 -1
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hooks/triage-config.d.ts +33 -0
- package/dist/hooks/triage-config.d.ts.map +1 -0
- package/dist/hooks/triage-config.js +87 -0
- package/dist/hooks/triage-config.js.map +1 -0
- package/dist/hooks/triage-heuristic.d.ts +20 -0
- package/dist/hooks/triage-heuristic.d.ts.map +1 -0
- package/dist/hooks/triage-heuristic.js +210 -0
- package/dist/hooks/triage-heuristic.js.map +1 -0
- package/dist/hooks/triage-state.d.ts +63 -0
- package/dist/hooks/triage-state.d.ts.map +1 -0
- package/dist/hooks/triage-state.js +138 -0
- package/dist/hooks/triage-state.js.map +1 -0
- package/dist/hud/__tests__/reconcile.test.js +20 -0
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/reconcile.d.ts +1 -0
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +2 -1
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +5 -24
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +127 -0
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +1 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +3 -11
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/state-server.d.ts +25 -0
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/state-server.js +41 -0
- package/dist/mcp/state-server.js.map +1 -1
- package/dist/modes/__tests__/base-ralph-contract.test.js +15 -0
- package/dist/modes/__tests__/base-ralph-contract.test.js.map +1 -1
- package/dist/modes/base.d.ts +1 -0
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +22 -6
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/index.test.js +75 -0
- package/dist/notifications/__tests__/index.test.js.map +1 -1
- package/dist/notifications/__tests__/session-status.test.js +90 -0
- package/dist/notifications/__tests__/session-status.test.js.map +1 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +39 -22
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/session-status.d.ts +2 -0
- package/dist/notifications/session-status.d.ts.map +1 -1
- package/dist/notifications/session-status.js +19 -4
- package/dist/notifications/session-status.js.map +1 -1
- package/dist/openclaw/index.d.ts +5 -3
- package/dist/openclaw/index.d.ts.map +1 -1
- package/dist/openclaw/index.js +5 -3
- package/dist/openclaw/index.js.map +1 -1
- package/dist/question/__tests__/client.test.d.ts +2 -0
- package/dist/question/__tests__/client.test.d.ts.map +1 -0
- package/dist/question/__tests__/client.test.js +70 -0
- package/dist/question/__tests__/client.test.js.map +1 -0
- package/dist/question/__tests__/deep-interview.test.d.ts +2 -0
- package/dist/question/__tests__/deep-interview.test.d.ts.map +1 -0
- package/dist/question/__tests__/deep-interview.test.js +118 -0
- package/dist/question/__tests__/deep-interview.test.js.map +1 -0
- package/dist/question/__tests__/policy.test.d.ts +2 -0
- package/dist/question/__tests__/policy.test.d.ts.map +1 -0
- package/dist/question/__tests__/policy.test.js +107 -0
- package/dist/question/__tests__/policy.test.js.map +1 -0
- package/dist/question/__tests__/renderer.test.d.ts +2 -0
- package/dist/question/__tests__/renderer.test.d.ts.map +1 -0
- package/dist/question/__tests__/renderer.test.js +238 -0
- package/dist/question/__tests__/renderer.test.js.map +1 -0
- package/dist/question/__tests__/state.test.d.ts +2 -0
- package/dist/question/__tests__/state.test.d.ts.map +1 -0
- package/dist/question/__tests__/state.test.js +75 -0
- package/dist/question/__tests__/state.test.js.map +1 -0
- package/dist/question/__tests__/types.test.d.ts +2 -0
- package/dist/question/__tests__/types.test.d.ts.map +1 -0
- package/dist/question/__tests__/types.test.js +44 -0
- package/dist/question/__tests__/types.test.js.map +1 -0
- package/dist/question/__tests__/ui.test.d.ts +2 -0
- package/dist/question/__tests__/ui.test.d.ts.map +1 -0
- package/dist/question/__tests__/ui.test.js +169 -0
- package/dist/question/__tests__/ui.test.js.map +1 -0
- package/dist/question/client.d.ts +54 -0
- package/dist/question/client.d.ts.map +1 -0
- package/dist/question/client.js +77 -0
- package/dist/question/client.js.map +1 -0
- package/dist/question/deep-interview.d.ts +30 -0
- package/dist/question/deep-interview.d.ts.map +1 -0
- package/dist/question/deep-interview.js +118 -0
- package/dist/question/deep-interview.js.map +1 -0
- package/dist/question/policy.d.ts +18 -0
- package/dist/question/policy.d.ts.map +1 -0
- package/dist/question/policy.js +77 -0
- package/dist/question/policy.js.map +1 -0
- package/dist/question/renderer.d.ts +20 -0
- package/dist/question/renderer.d.ts.map +1 -0
- package/dist/question/renderer.js +190 -0
- package/dist/question/renderer.js.map +1 -0
- package/dist/question/state.d.ts +19 -0
- package/dist/question/state.d.ts.map +1 -0
- package/dist/question/state.js +108 -0
- package/dist/question/state.js.map +1 -0
- package/dist/question/types.d.ts +66 -0
- package/dist/question/types.d.ts.map +1 -0
- package/dist/question/types.js +82 -0
- package/dist/question/types.js.map +1 -0
- package/dist/question/ui.d.ts +38 -0
- package/dist/question/ui.d.ts.map +1 -0
- package/dist/question/ui.js +321 -0
- package/dist/question/ui.js.map +1 -0
- package/dist/ralph/contract.d.ts +1 -1
- package/dist/ralph/contract.d.ts.map +1 -1
- package/dist/ralph/contract.js +4 -1
- package/dist/ralph/contract.js.map +1 -1
- package/dist/ralplan/runtime.js +1 -1
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/__tests__/run-loop.test.d.ts +2 -0
- package/dist/runtime/__tests__/run-loop.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/run-loop.test.js +35 -0
- package/dist/runtime/__tests__/run-loop.test.js.map +1 -0
- package/dist/runtime/__tests__/run-outcome.test.d.ts +2 -0
- package/dist/runtime/__tests__/run-outcome.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/run-outcome.test.js +102 -0
- package/dist/runtime/__tests__/run-outcome.test.js.map +1 -0
- package/dist/runtime/__tests__/run-state.test.d.ts +2 -0
- package/dist/runtime/__tests__/run-state.test.d.ts.map +1 -0
- package/dist/runtime/__tests__/run-state.test.js +37 -0
- package/dist/runtime/__tests__/run-state.test.js.map +1 -0
- package/dist/runtime/run-loop.d.ts +45 -0
- package/dist/runtime/run-loop.d.ts.map +1 -0
- package/dist/runtime/run-loop.js +51 -0
- package/dist/runtime/run-loop.js.map +1 -0
- package/dist/runtime/run-outcome.d.ts +46 -0
- package/dist/runtime/run-outcome.d.ts.map +1 -0
- package/dist/runtime/run-outcome.js +285 -0
- package/dist/runtime/run-outcome.js.map +1 -0
- package/dist/runtime/run-state.d.ts +40 -0
- package/dist/runtime/run-state.d.ts.map +1 -0
- package/dist/runtime/run-state.js +120 -0
- package/dist/runtime/run-state.js.map +1 -0
- package/dist/runtime/terminal-lifecycle.d.ts +11 -0
- package/dist/runtime/terminal-lifecycle.d.ts.map +1 -0
- package/dist/runtime/terminal-lifecycle.js +52 -0
- package/dist/runtime/terminal-lifecycle.js.map +1 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js +1459 -126
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/postinstall.test.d.ts +2 -0
- package/dist/scripts/__tests__/postinstall.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/postinstall.test.js +178 -0
- package/dist/scripts/__tests__/postinstall.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts +3 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +308 -61
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-fallback-watcher.js +81 -2
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts +27 -0
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +83 -20
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +64 -38
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook.js +15 -5
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall.d.ts +22 -0
- package/dist/scripts/postinstall.d.ts.map +1 -0
- package/dist/scripts/postinstall.js +105 -0
- package/dist/scripts/postinstall.js.map +1 -0
- package/dist/scripts/sync-prompt-guidance-fragments.js +5 -0
- package/dist/scripts/sync-prompt-guidance-fragments.js.map +1 -1
- package/dist/state/__tests__/operations-ralph-phase.test.js +21 -0
- package/dist/state/__tests__/operations-ralph-phase.test.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +18 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +11 -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 +15 -0
- package/dist/state/operations.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +14 -1
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +3 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/followup-planner.test.js +15 -0
- package/dist/team/__tests__/followup-planner.test.js.map +1 -1
- package/dist/team/__tests__/role-router.test.js +47 -0
- package/dist/team/__tests__/role-router.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +108 -2
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/followup-planner.d.ts.map +1 -1
- package/dist/team/followup-planner.js +31 -9
- package/dist/team/followup-planner.js.map +1 -1
- package/dist/team/role-router.d.ts.map +1 -1
- package/dist/team/role-router.js +73 -0
- package/dist/team/role-router.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +18 -4
- package/dist/team/runtime.js.map +1 -1
- package/dist/utils/__tests__/dep-versions.test.js +25 -8
- package/dist/utils/__tests__/dep-versions.test.js.map +1 -1
- package/dist/utils/__tests__/paths.test.js +45 -0
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/paths.d.ts +2 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +22 -7
- package/dist/utils/paths.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/package.json +4 -2
- package/prompts/architect.md +4 -0
- package/prompts/code-reviewer.md +3 -0
- package/prompts/dependency-expert.md +3 -0
- package/prompts/executor.md +5 -0
- package/prompts/explore.md +2 -0
- package/prompts/planner.md +5 -0
- package/prompts/product-analyst.md +8 -8
- package/prompts/researcher.md +78 -30
- package/prompts/verifier.md +4 -0
- package/skills/autoresearch/SKILL.md +68 -0
- package/skills/code-review/SKILL.md +94 -28
- package/skills/deep-interview/SKILL.md +100 -9
- package/skills/help/SKILL.md +3 -1
- package/skills/ralplan/SKILL.md +1 -0
- package/skills/team/SKILL.md +1 -0
- package/skills/ultrawork/SKILL.md +1 -0
- package/src/scripts/__tests__/codex-native-hook.test.ts +2373 -692
- package/src/scripts/__tests__/postinstall.test.ts +210 -0
- package/src/scripts/codex-native-hook.ts +365 -66
- package/src/scripts/notify-fallback-watcher.ts +92 -2
- package/src/scripts/notify-hook/auto-nudge.ts +89 -20
- package/src/scripts/notify-hook/managed-tmux.ts +70 -31
- package/src/scripts/notify-hook/ralph-session-resume.ts +1 -1
- package/src/scripts/notify-hook.ts +23 -5
- package/src/scripts/postinstall-bootstrap.js +23 -0
- package/src/scripts/postinstall.ts +161 -0
- package/src/scripts/sync-prompt-guidance-fragments.ts +4 -0
- package/templates/AGENTS.md +48 -37
- package/templates/catalog-manifest.json +7 -0
- package/templates/model-instructions/explore-lightweight-AGENTS.md +11 -0
- package/templates/model-instructions/sparkshell-lightweight-AGENTS.md +10 -0
|
@@ -2,6 +2,7 @@ import { execFileSync } from "child_process";
|
|
|
2
2
|
import { existsSync, readFileSync } from "fs";
|
|
3
3
|
import { mkdir, readFile, readdir, writeFile } from "fs/promises";
|
|
4
4
|
import { join, resolve } from "path";
|
|
5
|
+
import { pathToFileURL } from "url";
|
|
5
6
|
import { readModeState, readModeStateForSession, updateModeState } from "../modes/base.js";
|
|
6
7
|
import {
|
|
7
8
|
listActiveSkills,
|
|
@@ -9,7 +10,12 @@ import {
|
|
|
9
10
|
} from "../state/skill-active.js";
|
|
10
11
|
import { readSubagentSessionSummary } from "../subagents/tracker.js";
|
|
11
12
|
import { resolveCanonicalTeamStateRoot } from "../team/state-root.js";
|
|
12
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
isSessionStateUsable,
|
|
15
|
+
readSessionState,
|
|
16
|
+
readUsableSessionState,
|
|
17
|
+
reconcileNativeSessionStart,
|
|
18
|
+
} from "../hooks/session.js";
|
|
13
19
|
import {
|
|
14
20
|
appendTeamEvent,
|
|
15
21
|
readTeamLeaderAttention,
|
|
@@ -43,7 +49,21 @@ import {
|
|
|
43
49
|
import type { HookEventEnvelope } from "../hooks/extensibility/types.js";
|
|
44
50
|
import { dispatchHookEvent } from "../hooks/extensibility/dispatcher.js";
|
|
45
51
|
import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
|
|
52
|
+
import { shellEscapeSingle } from "../hud/tmux.js";
|
|
46
53
|
import { onSessionStart as buildWikiSessionStartContext } from "../wiki/lifecycle.js";
|
|
54
|
+
import { readAutoresearchCompletionStatus, readAutoresearchModeState } from "../autoresearch/skill-validation.js";
|
|
55
|
+
import { shouldContinueRun } from "../runtime/run-loop.js";
|
|
56
|
+
import { triagePrompt } from "../hooks/triage-heuristic.js";
|
|
57
|
+
import { readTriageConfig } from "../hooks/triage-config.js";
|
|
58
|
+
import {
|
|
59
|
+
readTriageState,
|
|
60
|
+
writeTriageState,
|
|
61
|
+
shouldSuppressFollowup,
|
|
62
|
+
promptSignature,
|
|
63
|
+
type TriageStateFile,
|
|
64
|
+
} from "../hooks/triage-state.js";
|
|
65
|
+
import { isPendingDeepInterviewQuestionEnforcement } from "../question/deep-interview.js";
|
|
66
|
+
import { resolveOmxCliEntryPath } from "../utils/paths.js";
|
|
47
67
|
|
|
48
68
|
type CodexHookEventName =
|
|
49
69
|
| "SessionStart"
|
|
@@ -57,6 +77,7 @@ type CodexHookPayload = Record<string, unknown>;
|
|
|
57
77
|
interface NativeHookDispatchOptions {
|
|
58
78
|
cwd?: string;
|
|
59
79
|
sessionOwnerPid?: number;
|
|
80
|
+
reconcileHudForPromptSubmitFn?: typeof reconcileHudForPromptSubmit;
|
|
60
81
|
}
|
|
61
82
|
|
|
62
83
|
export interface NativeHookDispatchResult {
|
|
@@ -66,7 +87,6 @@ export interface NativeHookDispatchResult {
|
|
|
66
87
|
outputJson: Record<string, unknown> | null;
|
|
67
88
|
}
|
|
68
89
|
|
|
69
|
-
const TERMINAL_RALPH_PHASES = new Set(["complete", "failed", "cancelled"]);
|
|
70
90
|
const TERMINAL_MODE_PHASES = new Set(["complete", "failed", "cancelled"]);
|
|
71
91
|
const SKILL_STOP_BLOCKERS = new Set(["ralplan"]);
|
|
72
92
|
const TEAM_TERMINAL_TASK_STATUSES = new Set(["completed", "failed"]);
|
|
@@ -79,6 +99,18 @@ const STABLE_FINAL_RECOMMENDATION_PATTERNS = [
|
|
|
79
99
|
] as const;
|
|
80
100
|
const RELEASE_READINESS_FINALIZE_SYSTEM_MESSAGE =
|
|
81
101
|
"OMX release-readiness detected a stable final recommendation with no active worker tasks; emit one concise final decision summary and finalize.";
|
|
102
|
+
const EXECUTION_HANDOFF_PATTERNS = [
|
|
103
|
+
/^(?:好|好的|行|可以|那就|那现在)?[,,\s]*(?:开始|继续|直接)\s*(?:执行|优化|实现|修改|修复)(?=$|\s|[,,。.!!??])/u,
|
|
104
|
+
/(?:按照|按|基于)(?:这个|上述|当前)?\s*(?:plan|计划|方案).{0,16}(?:开始|继续|直接)?\s*(?:执行|优化|实现|修改|修复)/u,
|
|
105
|
+
/(?:不用|别|不要).{0,6}讨论/u,
|
|
106
|
+
/\b(?:start|begin|go ahead(?: and)?|proceed(?: now)?)\s+(?:to\s+)?(?:implement|execute|apply|fix)\b/i,
|
|
107
|
+
/\b(?:according to|based on)\s+(?:the|this|that)\s+plan\b.{0,20}\b(?:start|begin|proceed(?: now)?|go ahead(?: and)?)\b/i,
|
|
108
|
+
] as const;
|
|
109
|
+
const SHORT_FOLLOWUP_PRIORITY_PATTERNS = [
|
|
110
|
+
/^(?:继续|接着|然后|那就|那现在|还有(?:一个)?问题|这些优化都做了么|这些都做了么|现在呢|本轮|当前轮|这一轮)/u,
|
|
111
|
+
/(?:按照|按|基于)(?:这个|上述|当前)?(?:plan|计划|方案)/u,
|
|
112
|
+
/\b(?:follow up|latest request|this turn|current turn|newest request)\b/i,
|
|
113
|
+
] as const;
|
|
82
114
|
|
|
83
115
|
function safeString(value: unknown): string {
|
|
84
116
|
return typeof value === "string" ? value : "";
|
|
@@ -97,6 +129,34 @@ function safePositiveInteger(value: unknown): number | null {
|
|
|
97
129
|
return null;
|
|
98
130
|
}
|
|
99
131
|
|
|
132
|
+
function normalizePromptSignalText(text: string): string {
|
|
133
|
+
return text.trim().replace(/\s+/g, " ");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function looksLikeExecutionHandoffPrompt(prompt: string): boolean {
|
|
137
|
+
const normalized = normalizePromptSignalText(prompt);
|
|
138
|
+
if (!normalized) return false;
|
|
139
|
+
return EXECUTION_HANDOFF_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function looksLikeShortFollowupPrompt(prompt: string): boolean {
|
|
143
|
+
const normalized = normalizePromptSignalText(prompt);
|
|
144
|
+
if (!normalized) return false;
|
|
145
|
+
if (looksLikeExecutionHandoffPrompt(normalized)) return true;
|
|
146
|
+
if (normalized.length > 240) return false;
|
|
147
|
+
return SHORT_FOLLOWUP_PRIORITY_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function buildPromptPriorityMessage(prompt: string): string | null {
|
|
151
|
+
if (looksLikeExecutionHandoffPrompt(prompt)) {
|
|
152
|
+
return "Newest user input is an execution handoff for the current task. Treat it as authorization to act now against the latest approved plan/request. Do not restate the prior plan unless the user explicitly asks for a recap or status update.";
|
|
153
|
+
}
|
|
154
|
+
if (looksLikeShortFollowupPrompt(prompt)) {
|
|
155
|
+
return "Newest user input is a same-thread follow-up. Answer that latest follow-up directly and prefer it over older unresolved prompts when choosing what to do next.";
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
100
160
|
function readHookEventName(payload: CodexHookPayload): CodexHookEventName | null {
|
|
101
161
|
const raw = safeString(
|
|
102
162
|
payload.hook_event_name
|
|
@@ -151,15 +211,26 @@ function readPromptText(payload: CodexHookPayload): string {
|
|
|
151
211
|
function sanitizePayloadForHookContext(
|
|
152
212
|
payload: CodexHookPayload,
|
|
153
213
|
hookEventName: CodexHookEventName,
|
|
214
|
+
canonicalSessionId = "",
|
|
154
215
|
): CodexHookPayload {
|
|
155
|
-
if (hookEventName !== "UserPromptSubmit") return payload;
|
|
156
|
-
|
|
157
216
|
const sanitized = { ...payload };
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
217
|
+
|
|
218
|
+
if (hookEventName === "UserPromptSubmit") {
|
|
219
|
+
delete sanitized.prompt;
|
|
220
|
+
delete sanitized.input;
|
|
221
|
+
delete sanitized.user_prompt;
|
|
222
|
+
delete sanitized.userPrompt;
|
|
223
|
+
delete sanitized.text;
|
|
224
|
+
return sanitized;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (hookEventName === "Stop") {
|
|
228
|
+
delete sanitized.stop_hook_active;
|
|
229
|
+
delete sanitized.stopHookActive;
|
|
230
|
+
delete sanitized.sessionId;
|
|
231
|
+
sanitized.session_id = canonicalSessionId.trim() || safeString(payload.session_id ?? payload.sessionId).trim();
|
|
232
|
+
}
|
|
233
|
+
|
|
163
234
|
return sanitized;
|
|
164
235
|
}
|
|
165
236
|
|
|
@@ -167,13 +238,14 @@ function buildBaseContext(
|
|
|
167
238
|
cwd: string,
|
|
168
239
|
payload: CodexHookPayload,
|
|
169
240
|
hookEventName: CodexHookEventName,
|
|
241
|
+
canonicalSessionId = "",
|
|
170
242
|
): Record<string, unknown> {
|
|
171
243
|
return {
|
|
172
244
|
cwd,
|
|
173
245
|
project_path: cwd,
|
|
174
246
|
transcript_path: safeString(payload.transcript_path ?? payload.transcriptPath) || null,
|
|
175
247
|
source: safeString(payload.source),
|
|
176
|
-
payload: sanitizePayloadForHookContext(payload, hookEventName),
|
|
248
|
+
payload: sanitizePayloadForHookContext(payload, hookEventName, canonicalSessionId),
|
|
177
249
|
};
|
|
178
250
|
}
|
|
179
251
|
|
|
@@ -196,27 +268,45 @@ function formatPhase(value: unknown, fallback = "active"): string {
|
|
|
196
268
|
return phase || fallback;
|
|
197
269
|
}
|
|
198
270
|
|
|
271
|
+
async function readActiveAutoresearchState(
|
|
272
|
+
cwd: string,
|
|
273
|
+
sessionId?: string,
|
|
274
|
+
): Promise<Record<string, unknown> | null> {
|
|
275
|
+
const normalizedSessionId = sessionId?.trim() || undefined;
|
|
276
|
+
if (!normalizedSessionId) return null;
|
|
277
|
+
const state = await readAutoresearchModeState(cwd, normalizedSessionId);
|
|
278
|
+
if (state?.active !== true) return null;
|
|
279
|
+
if (!isNonTerminalPhase(state.current_phase ?? state.currentPhase ?? 'executing')) return null;
|
|
280
|
+
return state;
|
|
281
|
+
}
|
|
282
|
+
|
|
199
283
|
async function readActiveRalphState(
|
|
200
284
|
stateDir: string,
|
|
201
285
|
preferredSessionId?: string,
|
|
202
286
|
): Promise<Record<string, unknown> | null> {
|
|
203
|
-
const
|
|
204
|
-
const
|
|
287
|
+
const cwd = resolve(stateDir, "..", "..");
|
|
288
|
+
const [rawSessionInfo, usableSessionInfo] = await Promise.all([
|
|
289
|
+
readSessionState(cwd),
|
|
290
|
+
readUsableSessionState(cwd),
|
|
291
|
+
]);
|
|
292
|
+
const currentOmxSessionId = safeString(usableSessionInfo?.session_id).trim();
|
|
293
|
+
const staleCurrentSessionId = rawSessionInfo && !isSessionStateUsable(rawSessionInfo, cwd)
|
|
294
|
+
? safeString(rawSessionInfo.session_id).trim()
|
|
295
|
+
: "";
|
|
205
296
|
const sessionCandidates = [...new Set([
|
|
206
297
|
safeString(preferredSessionId).trim(),
|
|
207
298
|
currentOmxSessionId,
|
|
208
299
|
].filter(Boolean))];
|
|
209
300
|
|
|
301
|
+
// Ralph Stop stays authoritative-scope-only once the Stop payload is session-bound.
|
|
302
|
+
// That is intentionally stricter than generic state MCP reads: do not scan sibling
|
|
303
|
+
// session scopes or fall back to root when a current/explicit session is in play.
|
|
210
304
|
for (const sessionId of sessionCandidates) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
&& !TERMINAL_RALPH_PHASES.has(
|
|
217
|
-
safeString(sessionScoped.current_phase).trim().toLowerCase(),
|
|
218
|
-
)
|
|
219
|
-
) {
|
|
305
|
+
if (staleCurrentSessionId && sessionId === staleCurrentSessionId) {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const sessionScoped = await readStopSessionPinnedState("ralph-state.json", cwd, sessionId);
|
|
309
|
+
if (sessionScoped?.active === true && shouldContinueRun(sessionScoped)) {
|
|
220
310
|
return sessionScoped;
|
|
221
311
|
}
|
|
222
312
|
}
|
|
@@ -224,26 +314,10 @@ async function readActiveRalphState(
|
|
|
224
314
|
if (sessionCandidates.length > 0) return null;
|
|
225
315
|
|
|
226
316
|
const direct = await readJsonIfExists(join(stateDir, "ralph-state.json"));
|
|
227
|
-
if (direct?.active === true &&
|
|
317
|
+
if (direct?.active === true && shouldContinueRun(direct)) {
|
|
228
318
|
return direct;
|
|
229
319
|
}
|
|
230
320
|
|
|
231
|
-
const sessionsRoot = join(stateDir, "sessions");
|
|
232
|
-
if (!existsSync(sessionsRoot)) return null;
|
|
233
|
-
const entries = await readdir(sessionsRoot, { withFileTypes: true }).catch(() => []);
|
|
234
|
-
for (const entry of entries) {
|
|
235
|
-
if (!entry.isDirectory()) continue;
|
|
236
|
-
const candidate = await readJsonIfExists(join(sessionsRoot, entry.name, "ralph-state.json"));
|
|
237
|
-
if (
|
|
238
|
-
candidate?.active === true
|
|
239
|
-
&& !TERMINAL_RALPH_PHASES.has(
|
|
240
|
-
safeString(candidate.current_phase).trim().toLowerCase(),
|
|
241
|
-
)
|
|
242
|
-
) {
|
|
243
|
-
return candidate;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
321
|
return null;
|
|
248
322
|
}
|
|
249
323
|
|
|
@@ -345,32 +419,55 @@ function resolveSessionOwnerPid(payload: CodexHookPayload): number {
|
|
|
345
419
|
return process.pid;
|
|
346
420
|
}
|
|
347
421
|
|
|
348
|
-
|
|
349
|
-
let repoRoot = "";
|
|
422
|
+
function tryReadGitValue(cwd: string, args: string[]): string | null {
|
|
350
423
|
try {
|
|
351
|
-
|
|
424
|
+
const value = execFileSync("git", args, {
|
|
352
425
|
cwd,
|
|
353
426
|
encoding: "utf-8",
|
|
354
427
|
stdio: ["ignore", "pipe", "ignore"],
|
|
355
428
|
windowsHide: true,
|
|
356
429
|
}).trim();
|
|
430
|
+
return value || null;
|
|
357
431
|
} catch {
|
|
358
|
-
return
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function isPathIgnoredByGit(cwd: string, path: string): boolean {
|
|
437
|
+
try {
|
|
438
|
+
execFileSync("git", ["check-ignore", "-q", path], {
|
|
439
|
+
cwd,
|
|
440
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
441
|
+
windowsHide: true,
|
|
442
|
+
});
|
|
443
|
+
return true;
|
|
444
|
+
} catch {
|
|
445
|
+
return false;
|
|
359
446
|
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
async function ensureOmxLocalIgnoreEntry(cwd: string): Promise<{ changed: boolean; excludePath?: string }> {
|
|
450
|
+
const repoRoot = tryReadGitValue(cwd, ["rev-parse", "--show-toplevel"]);
|
|
360
451
|
if (!repoRoot) return { changed: false };
|
|
452
|
+
if (isPathIgnoredByGit(repoRoot, ".omx/")) {
|
|
453
|
+
return { changed: false };
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const excludePathValue = tryReadGitValue(repoRoot, ["rev-parse", "--git-path", "info/exclude"]);
|
|
457
|
+
if (!excludePathValue) return { changed: false };
|
|
458
|
+
const excludePath = resolve(repoRoot, excludePathValue);
|
|
361
459
|
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
? await readFile(gitignorePath, "utf-8")
|
|
460
|
+
const existing = existsSync(excludePath)
|
|
461
|
+
? await readFile(excludePath, "utf-8")
|
|
365
462
|
: "";
|
|
366
463
|
const lines = existing.split(/\r?\n/).map((line) => line.trim());
|
|
367
464
|
if (lines.includes(".omx/")) {
|
|
368
|
-
return { changed: false,
|
|
465
|
+
return { changed: false, excludePath };
|
|
369
466
|
}
|
|
370
467
|
|
|
371
468
|
const next = `${existing}${existing.endsWith("\n") || existing.length === 0 ? "" : "\n"}.omx/\n`;
|
|
372
|
-
await writeFile(
|
|
373
|
-
return { changed: true,
|
|
469
|
+
await writeFile(excludePath, next);
|
|
470
|
+
return { changed: true, excludePath };
|
|
374
471
|
}
|
|
375
472
|
|
|
376
473
|
async function buildSessionStartContext(
|
|
@@ -379,9 +476,9 @@ async function buildSessionStartContext(
|
|
|
379
476
|
): Promise<string | null> {
|
|
380
477
|
const sections: string[] = [];
|
|
381
478
|
|
|
382
|
-
const
|
|
383
|
-
if (
|
|
384
|
-
sections.push(`Added .omx/ to ${
|
|
479
|
+
const localIgnoreResult = await ensureOmxLocalIgnoreEntry(cwd);
|
|
480
|
+
if (localIgnoreResult.changed) {
|
|
481
|
+
sections.push(`Added .omx/ to ${localIgnoreResult.excludePath} to keep local OMX state out of source control without mutating tracked repo ignores.`);
|
|
385
482
|
}
|
|
386
483
|
|
|
387
484
|
const modeSummaries: string[] = [];
|
|
@@ -469,11 +566,22 @@ async function buildSessionStartContext(
|
|
|
469
566
|
return sections.length > 0 ? sections.join("\n\n") : null;
|
|
470
567
|
}
|
|
471
568
|
|
|
472
|
-
function
|
|
569
|
+
function buildDeepInterviewQuestionBridgeInstruction(cwd: string): string {
|
|
570
|
+
const omxBin = resolveOmxCliEntryPath({ cwd }) || process.argv[1] || "omx";
|
|
571
|
+
const bridgeCommand = `${shellEscapeSingle(process.execPath)} ${shellEscapeSingle(omxBin)} question`;
|
|
572
|
+
return `Deep-interview must ask each interview round via \`omx question\`; do not fall back to \`request_user_input\` or plain-text questioning. If bare \`omx question\` is unavailable in this reused session, use the current-session CLI bridge command: \`${bridgeCommand}\`. Stop remains blocked while a deep-interview question obligation is pending.`;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function buildAdditionalContextMessage(
|
|
576
|
+
prompt: string,
|
|
577
|
+
skillState?: SkillActiveState | null,
|
|
578
|
+
cwd: string = process.cwd(),
|
|
579
|
+
): string | null {
|
|
473
580
|
if (!prompt) return null;
|
|
581
|
+
const promptPriorityMessage = buildPromptPriorityMessage(prompt);
|
|
474
582
|
const matches = detectKeywords(prompt);
|
|
475
583
|
const match = detectPrimaryKeyword(prompt);
|
|
476
|
-
if (!match) return
|
|
584
|
+
if (!match) return promptPriorityMessage;
|
|
477
585
|
const detectedKeywordMessage = matches.length > 1
|
|
478
586
|
? `OMX native UserPromptSubmit detected workflow keywords ${matches.map((entry) => `"${entry.keyword}" -> ${entry.skill}`).join(", ")}.`
|
|
479
587
|
: `OMX native UserPromptSubmit detected workflow keyword "${match.keyword}" -> ${match.skill}.`;
|
|
@@ -487,6 +595,9 @@ function buildAdditionalContextMessage(prompt: string, skillState?: SkillActiveS
|
|
|
487
595
|
const ralphPromptActivationNote = skillState?.initialized_mode === "ralph"
|
|
488
596
|
? "Prompt-side `$ralph` activation seeds Ralph workflow state only; it does not invoke `omx ralph`. Use `omx ralph --prd ...` only when you explicitly want the PRD-gated CLI startup path."
|
|
489
597
|
: null;
|
|
598
|
+
const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
|
|
599
|
+
? buildDeepInterviewQuestionBridgeInstruction(cwd)
|
|
600
|
+
: null;
|
|
490
601
|
const combinedTransitionMessage = (() => {
|
|
491
602
|
if (!skillState?.transition_message) return null;
|
|
492
603
|
if (matches.length <= 1 || activeSkills.length <= 1) return skillState.transition_message;
|
|
@@ -499,6 +610,7 @@ function buildAdditionalContextMessage(prompt: string, skillState?: SkillActiveS
|
|
|
499
610
|
return [
|
|
500
611
|
`OMX native UserPromptSubmit denied workflow keyword "${match.keyword}" -> ${match.skill}.`,
|
|
501
612
|
skillState.transition_error,
|
|
613
|
+
promptPriorityMessage,
|
|
502
614
|
'Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.',
|
|
503
615
|
].join(' ');
|
|
504
616
|
}
|
|
@@ -511,6 +623,7 @@ function buildAdditionalContextMessage(prompt: string, skillState?: SkillActiveS
|
|
|
511
623
|
deferredSkills.length > 0
|
|
512
624
|
? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
|
|
513
625
|
: null,
|
|
626
|
+
promptPriorityMessage,
|
|
514
627
|
skillState.initialized_mode && skillState.initialized_state_path
|
|
515
628
|
? `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`
|
|
516
629
|
: null,
|
|
@@ -532,7 +645,9 @@ function buildAdditionalContextMessage(prompt: string, skillState?: SkillActiveS
|
|
|
532
645
|
deferredSkills.length > 0
|
|
533
646
|
? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
|
|
534
647
|
: null,
|
|
648
|
+
promptPriorityMessage,
|
|
535
649
|
initializedStateMessage,
|
|
650
|
+
deepInterviewPromptActivationNote,
|
|
536
651
|
"Use the durable OMX team runtime via `omx team ...` for coordinated execution; do not replace it with in-process fanout.",
|
|
537
652
|
"If you need runtime syntax, run `omx team --help` yourself.",
|
|
538
653
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
@@ -546,13 +661,15 @@ function buildAdditionalContextMessage(prompt: string, skillState?: SkillActiveS
|
|
|
546
661
|
deferredSkills.length > 0
|
|
547
662
|
? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
|
|
548
663
|
: null,
|
|
664
|
+
promptPriorityMessage,
|
|
549
665
|
`skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`,
|
|
666
|
+
deepInterviewPromptActivationNote,
|
|
550
667
|
ralphPromptActivationNote,
|
|
551
668
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
552
669
|
].join(" ");
|
|
553
670
|
}
|
|
554
671
|
|
|
555
|
-
return
|
|
672
|
+
return [detectedKeywordMessage, promptPriorityMessage, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
|
|
556
673
|
}
|
|
557
674
|
|
|
558
675
|
function parseTeamWorkerEnv(rawValue: string): { teamName: string; workerName: string } | null {
|
|
@@ -678,7 +795,7 @@ async function buildModeBasedStopOutput(
|
|
|
678
795
|
const state = sessionId
|
|
679
796
|
? await readModeStateForSession(mode, sessionId, cwd)
|
|
680
797
|
: await readModeState(mode, cwd);
|
|
681
|
-
if (state
|
|
798
|
+
if (!state || !shouldContinueRun(state)) return null;
|
|
682
799
|
const phase = formatPhase(state.current_phase);
|
|
683
800
|
return {
|
|
684
801
|
decision: "block",
|
|
@@ -927,6 +1044,54 @@ async function readStopAutoNudgePhase(
|
|
|
927
1044
|
return modePhase === "intent-first" ? "planning" : "";
|
|
928
1045
|
}
|
|
929
1046
|
|
|
1047
|
+
async function buildDeepInterviewQuestionStopOutput(
|
|
1048
|
+
cwd: string,
|
|
1049
|
+
sessionId: string,
|
|
1050
|
+
threadId: string,
|
|
1051
|
+
): Promise<{ output: Record<string, unknown>; obligationId: string } | null> {
|
|
1052
|
+
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId);
|
|
1053
|
+
if (!modeState) return null;
|
|
1054
|
+
|
|
1055
|
+
const questionEnforcement = safeObject(modeState.question_enforcement);
|
|
1056
|
+
const hasPendingQuestionObligation = isPendingDeepInterviewQuestionEnforcement(questionEnforcement);
|
|
1057
|
+
if (modeState.active !== true && !hasPendingQuestionObligation) return null;
|
|
1058
|
+
|
|
1059
|
+
const phase = formatPhase(modeState.current_phase, "planning");
|
|
1060
|
+
if (TERMINAL_MODE_PHASES.has(phase.toLowerCase()) || phase === "completing") {
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
|
|
1065
|
+
if (canonicalState) {
|
|
1066
|
+
const blocker = listActiveSkills(canonicalState).find((entry) => (
|
|
1067
|
+
entry.skill === "deep-interview"
|
|
1068
|
+
&& matchesSkillStopContext(entry, canonicalState, sessionId, threadId)
|
|
1069
|
+
));
|
|
1070
|
+
if (!blocker) return null;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
if (!hasPendingQuestionObligation) {
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
const obligationId = safeString(questionEnforcement.obligation_id).trim();
|
|
1078
|
+
if (!obligationId) return null;
|
|
1079
|
+
|
|
1080
|
+
const systemMessage =
|
|
1081
|
+
`OMX deep-interview is still active (phase: ${phase}) and requires a structured question via omx question before stopping.`;
|
|
1082
|
+
|
|
1083
|
+
return {
|
|
1084
|
+
obligationId,
|
|
1085
|
+
output: {
|
|
1086
|
+
decision: "block",
|
|
1087
|
+
reason:
|
|
1088
|
+
`Deep interview is still active (phase: ${phase}) and has a pending structured question obligation; use \`omx question\` before stopping.`,
|
|
1089
|
+
stopReason: "deep_interview_question_required",
|
|
1090
|
+
systemMessage,
|
|
1091
|
+
},
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
|
|
930
1095
|
function resolveRepeatableStopSessionId(
|
|
931
1096
|
payload: CodexHookPayload,
|
|
932
1097
|
canonicalSessionId?: string,
|
|
@@ -1039,6 +1204,7 @@ async function returnPersistentStopBlock(
|
|
|
1039
1204
|
signatureValue: string,
|
|
1040
1205
|
output: Record<string, unknown> | null,
|
|
1041
1206
|
canonicalSessionId?: string,
|
|
1207
|
+
options: { allowRepeatDuringStopHook?: boolean } = { allowRepeatDuringStopHook: true },
|
|
1042
1208
|
): Promise<Record<string, unknown> | null> {
|
|
1043
1209
|
return await maybeReturnRepeatableStopOutput(
|
|
1044
1210
|
payload,
|
|
@@ -1046,7 +1212,7 @@ async function returnPersistentStopBlock(
|
|
|
1046
1212
|
buildRepeatableStopSignature(payload, signatureKind, signatureValue, canonicalSessionId),
|
|
1047
1213
|
output,
|
|
1048
1214
|
canonicalSessionId,
|
|
1049
|
-
|
|
1215
|
+
options,
|
|
1050
1216
|
);
|
|
1051
1217
|
}
|
|
1052
1218
|
|
|
@@ -1283,6 +1449,28 @@ async function buildStopHookOutput(
|
|
|
1283
1449
|
const threadId = readPayloadThreadId(payload);
|
|
1284
1450
|
const ralphState = await readActiveRalphState(stateDir, canonicalSessionId);
|
|
1285
1451
|
if (!ralphState) {
|
|
1452
|
+
const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
|
|
1453
|
+
if (autoresearchState) {
|
|
1454
|
+
const completion = await readAutoresearchCompletionStatus(cwd, canonicalSessionId!.trim());
|
|
1455
|
+
if (!completion.complete) {
|
|
1456
|
+
const currentPhase = safeString(autoresearchState.current_phase ?? autoresearchState.currentPhase).trim() || 'executing';
|
|
1457
|
+
const systemMessage = `OMX autoresearch is still active (phase: ${currentPhase}); continue until validator evidence is complete before stopping.`;
|
|
1458
|
+
return await maybeReturnRepeatableStopOutput(
|
|
1459
|
+
payload,
|
|
1460
|
+
stateDir,
|
|
1461
|
+
buildRepeatableStopSignature(payload, 'autoresearch-stop', `${currentPhase}|${completion.reason}`, canonicalSessionId),
|
|
1462
|
+
{
|
|
1463
|
+
decision: 'block',
|
|
1464
|
+
reason: systemMessage,
|
|
1465
|
+
stopReason: `autoresearch_${currentPhase}`,
|
|
1466
|
+
systemMessage,
|
|
1467
|
+
},
|
|
1468
|
+
canonicalSessionId,
|
|
1469
|
+
{ allowRepeatDuringStopHook: true },
|
|
1470
|
+
);
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1286
1474
|
const teamWorkerOutput = await buildTeamWorkerStopOutput(cwd);
|
|
1287
1475
|
if (hasTeamWorkerContext() && teamWorkerOutput) return teamWorkerOutput;
|
|
1288
1476
|
|
|
@@ -1307,6 +1495,7 @@ async function buildStopHookOutput(
|
|
|
1307
1495
|
safeString(ultraworkOutput.stopReason),
|
|
1308
1496
|
ultraworkOutput,
|
|
1309
1497
|
canonicalSessionId,
|
|
1498
|
+
{ allowRepeatDuringStopHook: false },
|
|
1310
1499
|
);
|
|
1311
1500
|
}
|
|
1312
1501
|
|
|
@@ -1343,6 +1532,22 @@ async function buildStopHookOutput(
|
|
|
1343
1532
|
}
|
|
1344
1533
|
|
|
1345
1534
|
if (canonicalSessionId) {
|
|
1535
|
+
const deepInterviewQuestionOutput = await buildDeepInterviewQuestionStopOutput(
|
|
1536
|
+
cwd,
|
|
1537
|
+
canonicalSessionId,
|
|
1538
|
+
threadId,
|
|
1539
|
+
);
|
|
1540
|
+
if (deepInterviewQuestionOutput) {
|
|
1541
|
+
return await returnPersistentStopBlock(
|
|
1542
|
+
payload,
|
|
1543
|
+
stateDir,
|
|
1544
|
+
"deep-interview-question-stop",
|
|
1545
|
+
deepInterviewQuestionOutput.obligationId,
|
|
1546
|
+
deepInterviewQuestionOutput.output,
|
|
1547
|
+
canonicalSessionId,
|
|
1548
|
+
);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1346
1551
|
const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, canonicalSessionId);
|
|
1347
1552
|
if (canonicalTeam) {
|
|
1348
1553
|
const canonicalTeamOutput = buildTeamStopOutputForPhase(
|
|
@@ -1435,23 +1640,42 @@ export async function dispatchCodexNativeHook(
|
|
|
1435
1640
|
|
|
1436
1641
|
const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
|
|
1437
1642
|
let skillState: SkillActiveState | null = null;
|
|
1643
|
+
let triageAdditionalContext: string | null = null;
|
|
1438
1644
|
|
|
1439
1645
|
const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
|
|
1440
1646
|
const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
|
|
1441
1647
|
const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
|
|
1442
|
-
|
|
1648
|
+
const currentSessionState = await readUsableSessionState(cwd);
|
|
1649
|
+
let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
1650
|
+
let resolvedNativeSessionId = nativeSessionId;
|
|
1443
1651
|
|
|
1444
1652
|
if (hookEventName === "SessionStart" && nativeSessionId) {
|
|
1445
1653
|
const sessionState = await reconcileNativeSessionStart(cwd, nativeSessionId, {
|
|
1446
1654
|
pid: options.sessionOwnerPid ?? resolveSessionOwnerPid(payload),
|
|
1447
1655
|
});
|
|
1448
1656
|
canonicalSessionId = safeString(sessionState.session_id).trim();
|
|
1657
|
+
resolvedNativeSessionId = safeString(sessionState.native_session_id).trim() || nativeSessionId;
|
|
1449
1658
|
} else if (!canonicalSessionId) {
|
|
1450
|
-
canonicalSessionId = safeString(
|
|
1659
|
+
canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
if (hookEventName === "Stop") {
|
|
1663
|
+
const stopCanonicalSessionId = await resolveInternalSessionIdForPayload(
|
|
1664
|
+
cwd,
|
|
1665
|
+
readPayloadSessionId(payload),
|
|
1666
|
+
);
|
|
1667
|
+
if (stopCanonicalSessionId) {
|
|
1668
|
+
canonicalSessionId = stopCanonicalSessionId;
|
|
1669
|
+
}
|
|
1670
|
+
if (canonicalSessionId && safeString(currentSessionState?.session_id).trim() === canonicalSessionId) {
|
|
1671
|
+
resolvedNativeSessionId =
|
|
1672
|
+
safeString(currentSessionState?.native_session_id).trim() || resolvedNativeSessionId;
|
|
1673
|
+
}
|
|
1451
1674
|
}
|
|
1452
1675
|
|
|
1453
1676
|
const eventSessionId = canonicalSessionId || nativeSessionId || undefined;
|
|
1454
1677
|
const sessionIdForState = canonicalSessionId || nativeSessionId;
|
|
1678
|
+
let outputJson: Record<string, unknown> | null = null;
|
|
1455
1679
|
|
|
1456
1680
|
if (hookEventName === "UserPromptSubmit") {
|
|
1457
1681
|
const prompt = readPromptText(payload);
|
|
@@ -1464,14 +1688,82 @@ export async function dispatchCodexNativeHook(
|
|
|
1464
1688
|
turnId,
|
|
1465
1689
|
});
|
|
1466
1690
|
}
|
|
1467
|
-
|
|
1691
|
+
// --- Triage classifier (advisory-only, non-keyword prompts) ---
|
|
1692
|
+
if (prompt && skillState === null) {
|
|
1693
|
+
try {
|
|
1694
|
+
if (readTriageConfig().enabled) {
|
|
1695
|
+
const normalized = prompt.trim().toLowerCase();
|
|
1696
|
+
const previous = readTriageState({ cwd, sessionId: sessionIdForState || null });
|
|
1697
|
+
const suppress = shouldSuppressFollowup({
|
|
1698
|
+
previous,
|
|
1699
|
+
currentPrompt: normalized,
|
|
1700
|
+
currentHasKeyword: false,
|
|
1701
|
+
});
|
|
1702
|
+
if (!suppress) {
|
|
1703
|
+
const decision = triagePrompt(prompt);
|
|
1704
|
+
const nowIso = new Date().toISOString();
|
|
1705
|
+
const effectiveTurnId = turnId || nowIso;
|
|
1706
|
+
if (decision.lane === "HEAVY") {
|
|
1707
|
+
triageAdditionalContext =
|
|
1708
|
+
"OMX native UserPromptSubmit triage detected a multi-step goal with no workflow keyword. This is advisory prompt-routing context only; it did not activate autopilot or initialize workflow state. Prefer the existing autopilot-style workflow if AGENTS.md/runtime conditions allow it, unless newer user context narrows or opts out.";
|
|
1709
|
+
const newState: TriageStateFile = {
|
|
1710
|
+
version: 1,
|
|
1711
|
+
last_triage: {
|
|
1712
|
+
lane: "HEAVY",
|
|
1713
|
+
destination: "autopilot",
|
|
1714
|
+
reason: decision.reason,
|
|
1715
|
+
prompt_signature: promptSignature(normalized),
|
|
1716
|
+
turn_id: effectiveTurnId,
|
|
1717
|
+
created_at: nowIso,
|
|
1718
|
+
},
|
|
1719
|
+
suppress_followup: true,
|
|
1720
|
+
};
|
|
1721
|
+
writeTriageState({ cwd, sessionId: sessionIdForState || null, state: newState });
|
|
1722
|
+
} else if (decision.lane === "LIGHT") {
|
|
1723
|
+
if (decision.destination === "explore") {
|
|
1724
|
+
triageAdditionalContext =
|
|
1725
|
+
"OMX native UserPromptSubmit triage detected a read-only/question-shaped request with no workflow keyword. This is advisory prompt-routing context only. Prefer the explore role surface rather than escalating to autopilot.";
|
|
1726
|
+
} else if (decision.destination === "executor") {
|
|
1727
|
+
triageAdditionalContext =
|
|
1728
|
+
"OMX native UserPromptSubmit triage detected a narrow edit-shaped request with no workflow keyword. This is advisory prompt-routing context only. Prefer the executor role surface rather than autopilot.";
|
|
1729
|
+
} else if (decision.destination === "designer") {
|
|
1730
|
+
triageAdditionalContext =
|
|
1731
|
+
"OMX native UserPromptSubmit triage detected a visual/style request with no workflow keyword. This is advisory prompt-routing context only. Prefer the designer role surface.";
|
|
1732
|
+
}
|
|
1733
|
+
if (triageAdditionalContext !== null) {
|
|
1734
|
+
const dest = decision.destination as "explore" | "executor" | "designer";
|
|
1735
|
+
const newState: TriageStateFile = {
|
|
1736
|
+
version: 1,
|
|
1737
|
+
last_triage: {
|
|
1738
|
+
lane: "LIGHT",
|
|
1739
|
+
destination: dest,
|
|
1740
|
+
reason: decision.reason,
|
|
1741
|
+
prompt_signature: promptSignature(normalized),
|
|
1742
|
+
turn_id: effectiveTurnId,
|
|
1743
|
+
created_at: nowIso,
|
|
1744
|
+
},
|
|
1745
|
+
suppress_followup: true,
|
|
1746
|
+
};
|
|
1747
|
+
writeTriageState({ cwd, sessionId: sessionIdForState || null, state: newState });
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
// lane === "PASS": no context, no state write
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
} catch {
|
|
1754
|
+
// Swallow all triage errors; never break the hook
|
|
1755
|
+
triageAdditionalContext = null;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
const reconcileHudForPromptSubmitFn = options.reconcileHudForPromptSubmitFn ?? reconcileHudForPromptSubmit;
|
|
1759
|
+
await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => {});
|
|
1468
1760
|
}
|
|
1469
1761
|
|
|
1470
1762
|
if (omxEventName) {
|
|
1471
|
-
const baseContext = buildBaseContext(cwd, payload, hookEventName
|
|
1472
|
-
if (
|
|
1473
|
-
baseContext.native_session_id =
|
|
1474
|
-
baseContext.codex_session_id =
|
|
1763
|
+
const baseContext = buildBaseContext(cwd, payload, hookEventName!, canonicalSessionId);
|
|
1764
|
+
if (resolvedNativeSessionId) {
|
|
1765
|
+
baseContext.native_session_id = resolvedNativeSessionId;
|
|
1766
|
+
baseContext.codex_session_id = resolvedNativeSessionId;
|
|
1475
1767
|
}
|
|
1476
1768
|
if (canonicalSessionId) {
|
|
1477
1769
|
baseContext.omx_session_id = canonicalSessionId;
|
|
@@ -1489,11 +1781,10 @@ export async function dispatchCodexNativeHook(
|
|
|
1489
1781
|
await dispatchHookEvent(event, { cwd });
|
|
1490
1782
|
}
|
|
1491
1783
|
|
|
1492
|
-
let outputJson: Record<string, unknown> | null = null;
|
|
1493
1784
|
if (hookEventName === "SessionStart" || hookEventName === "UserPromptSubmit") {
|
|
1494
1785
|
const additionalContext = hookEventName === "SessionStart"
|
|
1495
1786
|
? await buildSessionStartContext(cwd, canonicalSessionId || nativeSessionId)
|
|
1496
|
-
: buildAdditionalContextMessage(readPromptText(payload), skillState);
|
|
1787
|
+
: (buildAdditionalContextMessage(readPromptText(payload), skillState, cwd) ?? triageAdditionalContext);
|
|
1497
1788
|
if (additionalContext) {
|
|
1498
1789
|
outputJson = {
|
|
1499
1790
|
hookSpecificOutput: {
|
|
@@ -1526,6 +1817,14 @@ interface NativeHookCliReadResult {
|
|
|
1526
1817
|
parseError: Error | null;
|
|
1527
1818
|
}
|
|
1528
1819
|
|
|
1820
|
+
export function isCodexNativeHookMainModule(
|
|
1821
|
+
moduleUrl: string,
|
|
1822
|
+
argv1: string | undefined,
|
|
1823
|
+
): boolean {
|
|
1824
|
+
if (!argv1) return false;
|
|
1825
|
+
return moduleUrl === pathToFileURL(argv1).href;
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1529
1828
|
async function readStdinJson(): Promise<NativeHookCliReadResult> {
|
|
1530
1829
|
const chunks: Buffer[] = [];
|
|
1531
1830
|
for await (const chunk of process.stdin) {
|
|
@@ -1570,7 +1869,7 @@ export async function runCodexNativeHookCli(): Promise<void> {
|
|
|
1570
1869
|
}
|
|
1571
1870
|
}
|
|
1572
1871
|
|
|
1573
|
-
if (import.meta.url
|
|
1872
|
+
if (isCodexNativeHookMainModule(import.meta.url, process.argv[1])) {
|
|
1574
1873
|
runCodexNativeHookCli().catch((error) => {
|
|
1575
1874
|
process.stderr.write(
|
|
1576
1875
|
`[omx] codex-native-hook failed: ${
|