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,11 +2,12 @@ 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 { listActiveSkills, readVisibleSkillActiveState, } from "../state/skill-active.js";
|
|
7
8
|
import { readSubagentSessionSummary } from "../subagents/tracker.js";
|
|
8
9
|
import { resolveCanonicalTeamStateRoot } from "../team/state-root.js";
|
|
9
|
-
import { readUsableSessionState, reconcileNativeSessionStart } from "../hooks/session.js";
|
|
10
|
+
import { isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
|
|
10
11
|
import { appendTeamEvent, readTeamLeaderAttention, readTeamManifestV2, readTeamPhase, writeTeamLeaderAttention, writeTeamPhase, } from "../team/state.js";
|
|
11
12
|
import { omxNotepadPath, omxProjectMemoryPath } from "../utils/paths.js";
|
|
12
13
|
import { getStateFilePath, getStatePath } from "../mcp/state-paths.js";
|
|
@@ -16,8 +17,15 @@ import { buildNativePostToolUseOutput, buildNativePreToolUseOutput, detectMcpTra
|
|
|
16
17
|
import { buildNativeHookEvent, } from "../hooks/extensibility/events.js";
|
|
17
18
|
import { dispatchHookEvent } from "../hooks/extensibility/dispatcher.js";
|
|
18
19
|
import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
|
|
20
|
+
import { shellEscapeSingle } from "../hud/tmux.js";
|
|
19
21
|
import { onSessionStart as buildWikiSessionStartContext } from "../wiki/lifecycle.js";
|
|
20
|
-
|
|
22
|
+
import { readAutoresearchCompletionStatus, readAutoresearchModeState } from "../autoresearch/skill-validation.js";
|
|
23
|
+
import { shouldContinueRun } from "../runtime/run-loop.js";
|
|
24
|
+
import { triagePrompt } from "../hooks/triage-heuristic.js";
|
|
25
|
+
import { readTriageConfig } from "../hooks/triage-config.js";
|
|
26
|
+
import { readTriageState, writeTriageState, shouldSuppressFollowup, promptSignature, } from "../hooks/triage-state.js";
|
|
27
|
+
import { isPendingDeepInterviewQuestionEnforcement } from "../question/deep-interview.js";
|
|
28
|
+
import { resolveOmxCliEntryPath } from "../utils/paths.js";
|
|
21
29
|
const TERMINAL_MODE_PHASES = new Set(["complete", "failed", "cancelled"]);
|
|
22
30
|
const SKILL_STOP_BLOCKERS = new Set(["ralplan"]);
|
|
23
31
|
const TEAM_TERMINAL_TASK_STATUSES = new Set(["completed", "failed"]);
|
|
@@ -29,6 +37,18 @@ const STABLE_FINAL_RECOMMENDATION_PATTERNS = [
|
|
|
29
37
|
/^\s*decision\s*:\s*(?:yes|no|ship|hold|release|do not release|proceed|do not proceed)\b[^\n\r]*/im,
|
|
30
38
|
];
|
|
31
39
|
const RELEASE_READINESS_FINALIZE_SYSTEM_MESSAGE = "OMX release-readiness detected a stable final recommendation with no active worker tasks; emit one concise final decision summary and finalize.";
|
|
40
|
+
const EXECUTION_HANDOFF_PATTERNS = [
|
|
41
|
+
/^(?:好|好的|行|可以|那就|那现在)?[,,\s]*(?:开始|继续|直接)\s*(?:执行|优化|实现|修改|修复)(?=$|\s|[,,。.!!??])/u,
|
|
42
|
+
/(?:按照|按|基于)(?:这个|上述|当前)?\s*(?:plan|计划|方案).{0,16}(?:开始|继续|直接)?\s*(?:执行|优化|实现|修改|修复)/u,
|
|
43
|
+
/(?:不用|别|不要).{0,6}讨论/u,
|
|
44
|
+
/\b(?:start|begin|go ahead(?: and)?|proceed(?: now)?)\s+(?:to\s+)?(?:implement|execute|apply|fix)\b/i,
|
|
45
|
+
/\b(?:according to|based on)\s+(?:the|this|that)\s+plan\b.{0,20}\b(?:start|begin|proceed(?: now)?|go ahead(?: and)?)\b/i,
|
|
46
|
+
];
|
|
47
|
+
const SHORT_FOLLOWUP_PRIORITY_PATTERNS = [
|
|
48
|
+
/^(?:继续|接着|然后|那就|那现在|还有(?:一个)?问题|这些优化都做了么|这些都做了么|现在呢|本轮|当前轮|这一轮)/u,
|
|
49
|
+
/(?:按照|按|基于)(?:这个|上述|当前)?(?:plan|计划|方案)/u,
|
|
50
|
+
/\b(?:follow up|latest request|this turn|current turn|newest request)\b/i,
|
|
51
|
+
];
|
|
32
52
|
function safeString(value) {
|
|
33
53
|
return typeof value === "string" ? value : "";
|
|
34
54
|
}
|
|
@@ -45,6 +65,34 @@ function safePositiveInteger(value) {
|
|
|
45
65
|
}
|
|
46
66
|
return null;
|
|
47
67
|
}
|
|
68
|
+
function normalizePromptSignalText(text) {
|
|
69
|
+
return text.trim().replace(/\s+/g, " ");
|
|
70
|
+
}
|
|
71
|
+
function looksLikeExecutionHandoffPrompt(prompt) {
|
|
72
|
+
const normalized = normalizePromptSignalText(prompt);
|
|
73
|
+
if (!normalized)
|
|
74
|
+
return false;
|
|
75
|
+
return EXECUTION_HANDOFF_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
76
|
+
}
|
|
77
|
+
function looksLikeShortFollowupPrompt(prompt) {
|
|
78
|
+
const normalized = normalizePromptSignalText(prompt);
|
|
79
|
+
if (!normalized)
|
|
80
|
+
return false;
|
|
81
|
+
if (looksLikeExecutionHandoffPrompt(normalized))
|
|
82
|
+
return true;
|
|
83
|
+
if (normalized.length > 240)
|
|
84
|
+
return false;
|
|
85
|
+
return SHORT_FOLLOWUP_PRIORITY_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
86
|
+
}
|
|
87
|
+
function buildPromptPriorityMessage(prompt) {
|
|
88
|
+
if (looksLikeExecutionHandoffPrompt(prompt)) {
|
|
89
|
+
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.";
|
|
90
|
+
}
|
|
91
|
+
if (looksLikeShortFollowupPrompt(prompt)) {
|
|
92
|
+
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.";
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
48
96
|
function readHookEventName(payload) {
|
|
49
97
|
const raw = safeString(payload.hook_event_name
|
|
50
98
|
?? payload.hookEventName
|
|
@@ -88,24 +136,31 @@ function readPromptText(payload) {
|
|
|
88
136
|
}
|
|
89
137
|
return "";
|
|
90
138
|
}
|
|
91
|
-
function sanitizePayloadForHookContext(payload, hookEventName) {
|
|
92
|
-
if (hookEventName !== "UserPromptSubmit")
|
|
93
|
-
return payload;
|
|
139
|
+
function sanitizePayloadForHookContext(payload, hookEventName, canonicalSessionId = "") {
|
|
94
140
|
const sanitized = { ...payload };
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
141
|
+
if (hookEventName === "UserPromptSubmit") {
|
|
142
|
+
delete sanitized.prompt;
|
|
143
|
+
delete sanitized.input;
|
|
144
|
+
delete sanitized.user_prompt;
|
|
145
|
+
delete sanitized.userPrompt;
|
|
146
|
+
delete sanitized.text;
|
|
147
|
+
return sanitized;
|
|
148
|
+
}
|
|
149
|
+
if (hookEventName === "Stop") {
|
|
150
|
+
delete sanitized.stop_hook_active;
|
|
151
|
+
delete sanitized.stopHookActive;
|
|
152
|
+
delete sanitized.sessionId;
|
|
153
|
+
sanitized.session_id = canonicalSessionId.trim() || safeString(payload.session_id ?? payload.sessionId).trim();
|
|
154
|
+
}
|
|
100
155
|
return sanitized;
|
|
101
156
|
}
|
|
102
|
-
function buildBaseContext(cwd, payload, hookEventName) {
|
|
157
|
+
function buildBaseContext(cwd, payload, hookEventName, canonicalSessionId = "") {
|
|
103
158
|
return {
|
|
104
159
|
cwd,
|
|
105
160
|
project_path: cwd,
|
|
106
161
|
transcript_path: safeString(payload.transcript_path ?? payload.transcriptPath) || null,
|
|
107
162
|
source: safeString(payload.source),
|
|
108
|
-
payload: sanitizePayloadForHookContext(payload, hookEventName),
|
|
163
|
+
payload: sanitizePayloadForHookContext(payload, hookEventName, canonicalSessionId),
|
|
109
164
|
};
|
|
110
165
|
}
|
|
111
166
|
async function readJsonIfExists(path) {
|
|
@@ -126,39 +181,49 @@ function formatPhase(value, fallback = "active") {
|
|
|
126
181
|
const phase = safeString(value).trim();
|
|
127
182
|
return phase || fallback;
|
|
128
183
|
}
|
|
184
|
+
async function readActiveAutoresearchState(cwd, sessionId) {
|
|
185
|
+
const normalizedSessionId = sessionId?.trim() || undefined;
|
|
186
|
+
if (!normalizedSessionId)
|
|
187
|
+
return null;
|
|
188
|
+
const state = await readAutoresearchModeState(cwd, normalizedSessionId);
|
|
189
|
+
if (state?.active !== true)
|
|
190
|
+
return null;
|
|
191
|
+
if (!isNonTerminalPhase(state.current_phase ?? state.currentPhase ?? 'executing'))
|
|
192
|
+
return null;
|
|
193
|
+
return state;
|
|
194
|
+
}
|
|
129
195
|
async function readActiveRalphState(stateDir, preferredSessionId) {
|
|
130
|
-
const
|
|
131
|
-
const
|
|
196
|
+
const cwd = resolve(stateDir, "..", "..");
|
|
197
|
+
const [rawSessionInfo, usableSessionInfo] = await Promise.all([
|
|
198
|
+
readSessionState(cwd),
|
|
199
|
+
readUsableSessionState(cwd),
|
|
200
|
+
]);
|
|
201
|
+
const currentOmxSessionId = safeString(usableSessionInfo?.session_id).trim();
|
|
202
|
+
const staleCurrentSessionId = rawSessionInfo && !isSessionStateUsable(rawSessionInfo, cwd)
|
|
203
|
+
? safeString(rawSessionInfo.session_id).trim()
|
|
204
|
+
: "";
|
|
132
205
|
const sessionCandidates = [...new Set([
|
|
133
206
|
safeString(preferredSessionId).trim(),
|
|
134
207
|
currentOmxSessionId,
|
|
135
208
|
].filter(Boolean))];
|
|
209
|
+
// Ralph Stop stays authoritative-scope-only once the Stop payload is session-bound.
|
|
210
|
+
// That is intentionally stricter than generic state MCP reads: do not scan sibling
|
|
211
|
+
// session scopes or fall back to root when a current/explicit session is in play.
|
|
136
212
|
for (const sessionId of sessionCandidates) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
213
|
+
if (staleCurrentSessionId && sessionId === staleCurrentSessionId) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const sessionScoped = await readStopSessionPinnedState("ralph-state.json", cwd, sessionId);
|
|
217
|
+
if (sessionScoped?.active === true && shouldContinueRun(sessionScoped)) {
|
|
140
218
|
return sessionScoped;
|
|
141
219
|
}
|
|
142
220
|
}
|
|
143
221
|
if (sessionCandidates.length > 0)
|
|
144
222
|
return null;
|
|
145
223
|
const direct = await readJsonIfExists(join(stateDir, "ralph-state.json"));
|
|
146
|
-
if (direct?.active === true &&
|
|
224
|
+
if (direct?.active === true && shouldContinueRun(direct)) {
|
|
147
225
|
return direct;
|
|
148
226
|
}
|
|
149
|
-
const sessionsRoot = join(stateDir, "sessions");
|
|
150
|
-
if (!existsSync(sessionsRoot))
|
|
151
|
-
return null;
|
|
152
|
-
const entries = await readdir(sessionsRoot, { withFileTypes: true }).catch(() => []);
|
|
153
|
-
for (const entry of entries) {
|
|
154
|
-
if (!entry.isDirectory())
|
|
155
|
-
continue;
|
|
156
|
-
const candidate = await readJsonIfExists(join(sessionsRoot, entry.name, "ralph-state.json"));
|
|
157
|
-
if (candidate?.active === true
|
|
158
|
-
&& !TERMINAL_RALPH_PHASES.has(safeString(candidate.current_phase).trim().toLowerCase())) {
|
|
159
|
-
return candidate;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
227
|
return null;
|
|
163
228
|
}
|
|
164
229
|
function readParentPid(pid) {
|
|
@@ -249,38 +314,60 @@ function resolveSessionOwnerPid(payload) {
|
|
|
249
314
|
return resolved;
|
|
250
315
|
return process.pid;
|
|
251
316
|
}
|
|
252
|
-
|
|
253
|
-
let repoRoot = "";
|
|
317
|
+
function tryReadGitValue(cwd, args) {
|
|
254
318
|
try {
|
|
255
|
-
|
|
319
|
+
const value = execFileSync("git", args, {
|
|
256
320
|
cwd,
|
|
257
321
|
encoding: "utf-8",
|
|
258
322
|
stdio: ["ignore", "pipe", "ignore"],
|
|
259
323
|
windowsHide: true,
|
|
260
324
|
}).trim();
|
|
325
|
+
return value || null;
|
|
261
326
|
}
|
|
262
327
|
catch {
|
|
263
|
-
return
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function isPathIgnoredByGit(cwd, path) {
|
|
332
|
+
try {
|
|
333
|
+
execFileSync("git", ["check-ignore", "-q", path], {
|
|
334
|
+
cwd,
|
|
335
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
336
|
+
windowsHide: true,
|
|
337
|
+
});
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
return false;
|
|
264
342
|
}
|
|
343
|
+
}
|
|
344
|
+
async function ensureOmxLocalIgnoreEntry(cwd) {
|
|
345
|
+
const repoRoot = tryReadGitValue(cwd, ["rev-parse", "--show-toplevel"]);
|
|
265
346
|
if (!repoRoot)
|
|
266
347
|
return { changed: false };
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
348
|
+
if (isPathIgnoredByGit(repoRoot, ".omx/")) {
|
|
349
|
+
return { changed: false };
|
|
350
|
+
}
|
|
351
|
+
const excludePathValue = tryReadGitValue(repoRoot, ["rev-parse", "--git-path", "info/exclude"]);
|
|
352
|
+
if (!excludePathValue)
|
|
353
|
+
return { changed: false };
|
|
354
|
+
const excludePath = resolve(repoRoot, excludePathValue);
|
|
355
|
+
const existing = existsSync(excludePath)
|
|
356
|
+
? await readFile(excludePath, "utf-8")
|
|
270
357
|
: "";
|
|
271
358
|
const lines = existing.split(/\r?\n/).map((line) => line.trim());
|
|
272
359
|
if (lines.includes(".omx/")) {
|
|
273
|
-
return { changed: false,
|
|
360
|
+
return { changed: false, excludePath };
|
|
274
361
|
}
|
|
275
362
|
const next = `${existing}${existing.endsWith("\n") || existing.length === 0 ? "" : "\n"}.omx/\n`;
|
|
276
|
-
await writeFile(
|
|
277
|
-
return { changed: true,
|
|
363
|
+
await writeFile(excludePath, next);
|
|
364
|
+
return { changed: true, excludePath };
|
|
278
365
|
}
|
|
279
366
|
async function buildSessionStartContext(cwd, sessionId) {
|
|
280
367
|
const sections = [];
|
|
281
|
-
const
|
|
282
|
-
if (
|
|
283
|
-
sections.push(`Added .omx/ to ${
|
|
368
|
+
const localIgnoreResult = await ensureOmxLocalIgnoreEntry(cwd);
|
|
369
|
+
if (localIgnoreResult.changed) {
|
|
370
|
+
sections.push(`Added .omx/ to ${localIgnoreResult.excludePath} to keep local OMX state out of source control without mutating tracked repo ignores.`);
|
|
284
371
|
}
|
|
285
372
|
const modeSummaries = [];
|
|
286
373
|
for (const mode of ["ralph", "autopilot", "ultrawork", "ultraqa", "ralplan", "deep-interview", "team"]) {
|
|
@@ -366,13 +453,19 @@ async function buildSessionStartContext(cwd, sessionId) {
|
|
|
366
453
|
}
|
|
367
454
|
return sections.length > 0 ? sections.join("\n\n") : null;
|
|
368
455
|
}
|
|
369
|
-
function
|
|
456
|
+
function buildDeepInterviewQuestionBridgeInstruction(cwd) {
|
|
457
|
+
const omxBin = resolveOmxCliEntryPath({ cwd }) || process.argv[1] || "omx";
|
|
458
|
+
const bridgeCommand = `${shellEscapeSingle(process.execPath)} ${shellEscapeSingle(omxBin)} question`;
|
|
459
|
+
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.`;
|
|
460
|
+
}
|
|
461
|
+
function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd()) {
|
|
370
462
|
if (!prompt)
|
|
371
463
|
return null;
|
|
464
|
+
const promptPriorityMessage = buildPromptPriorityMessage(prompt);
|
|
372
465
|
const matches = detectKeywords(prompt);
|
|
373
466
|
const match = detectPrimaryKeyword(prompt);
|
|
374
467
|
if (!match)
|
|
375
|
-
return
|
|
468
|
+
return promptPriorityMessage;
|
|
376
469
|
const detectedKeywordMessage = matches.length > 1
|
|
377
470
|
? `OMX native UserPromptSubmit detected workflow keywords ${matches.map((entry) => `"${entry.keyword}" -> ${entry.skill}`).join(", ")}.`
|
|
378
471
|
: `OMX native UserPromptSubmit detected workflow keyword "${match.keyword}" -> ${match.skill}.`;
|
|
@@ -386,6 +479,9 @@ function buildAdditionalContextMessage(prompt, skillState) {
|
|
|
386
479
|
const ralphPromptActivationNote = skillState?.initialized_mode === "ralph"
|
|
387
480
|
? "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."
|
|
388
481
|
: null;
|
|
482
|
+
const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
|
|
483
|
+
? buildDeepInterviewQuestionBridgeInstruction(cwd)
|
|
484
|
+
: null;
|
|
389
485
|
const combinedTransitionMessage = (() => {
|
|
390
486
|
if (!skillState?.transition_message)
|
|
391
487
|
return null;
|
|
@@ -400,6 +496,7 @@ function buildAdditionalContextMessage(prompt, skillState) {
|
|
|
400
496
|
return [
|
|
401
497
|
`OMX native UserPromptSubmit denied workflow keyword "${match.keyword}" -> ${match.skill}.`,
|
|
402
498
|
skillState.transition_error,
|
|
499
|
+
promptPriorityMessage,
|
|
403
500
|
'Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.',
|
|
404
501
|
].join(' ');
|
|
405
502
|
}
|
|
@@ -411,6 +508,7 @@ function buildAdditionalContextMessage(prompt, skillState) {
|
|
|
411
508
|
deferredSkills.length > 0
|
|
412
509
|
? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
|
|
413
510
|
: null,
|
|
511
|
+
promptPriorityMessage,
|
|
414
512
|
skillState.initialized_mode && skillState.initialized_state_path
|
|
415
513
|
? `skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`
|
|
416
514
|
: null,
|
|
@@ -431,7 +529,9 @@ function buildAdditionalContextMessage(prompt, skillState) {
|
|
|
431
529
|
deferredSkills.length > 0
|
|
432
530
|
? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
|
|
433
531
|
: null,
|
|
532
|
+
promptPriorityMessage,
|
|
434
533
|
initializedStateMessage,
|
|
534
|
+
deepInterviewPromptActivationNote,
|
|
435
535
|
"Use the durable OMX team runtime via `omx team ...` for coordinated execution; do not replace it with in-process fanout.",
|
|
436
536
|
"If you need runtime syntax, run `omx team --help` yourself.",
|
|
437
537
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
@@ -444,12 +544,14 @@ function buildAdditionalContextMessage(prompt, skillState) {
|
|
|
444
544
|
deferredSkills.length > 0
|
|
445
545
|
? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
|
|
446
546
|
: null,
|
|
547
|
+
promptPriorityMessage,
|
|
447
548
|
`skill: ${skillState.initialized_mode} activated and initial state initialized at ${skillState.initialized_state_path}; write subsequent updates via omx_state MCP.`,
|
|
549
|
+
deepInterviewPromptActivationNote,
|
|
448
550
|
ralphPromptActivationNote,
|
|
449
551
|
"Follow AGENTS.md routing and preserve workflow transition and planning-safety rules.",
|
|
450
552
|
].join(" ");
|
|
451
553
|
}
|
|
452
|
-
return
|
|
554
|
+
return [detectedKeywordMessage, promptPriorityMessage, "Follow AGENTS.md routing and preserve workflow transition and planning-safety rules."].filter(Boolean).join(" ");
|
|
453
555
|
}
|
|
454
556
|
function parseTeamWorkerEnv(rawValue) {
|
|
455
557
|
const match = /^([a-z0-9][a-z0-9-]{0,29})\/(worker-\d+)$/.exec(rawValue.trim());
|
|
@@ -549,7 +651,7 @@ async function buildModeBasedStopOutput(mode, cwd, sessionId) {
|
|
|
549
651
|
const state = sessionId
|
|
550
652
|
? await readModeStateForSession(mode, sessionId, cwd)
|
|
551
653
|
: await readModeState(mode, cwd);
|
|
552
|
-
if (state
|
|
654
|
+
if (!state || !shouldContinueRun(state))
|
|
553
655
|
return null;
|
|
554
656
|
const phase = formatPhase(state.current_phase);
|
|
555
657
|
return {
|
|
@@ -737,6 +839,42 @@ async function readStopAutoNudgePhase(cwd, sessionId, threadId) {
|
|
|
737
839
|
const modePhase = safeString(modeState.current_phase).trim().toLowerCase();
|
|
738
840
|
return modePhase === "intent-first" ? "planning" : "";
|
|
739
841
|
}
|
|
842
|
+
async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
|
|
843
|
+
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId);
|
|
844
|
+
if (!modeState)
|
|
845
|
+
return null;
|
|
846
|
+
const questionEnforcement = safeObject(modeState.question_enforcement);
|
|
847
|
+
const hasPendingQuestionObligation = isPendingDeepInterviewQuestionEnforcement(questionEnforcement);
|
|
848
|
+
if (modeState.active !== true && !hasPendingQuestionObligation)
|
|
849
|
+
return null;
|
|
850
|
+
const phase = formatPhase(modeState.current_phase, "planning");
|
|
851
|
+
if (TERMINAL_MODE_PHASES.has(phase.toLowerCase()) || phase === "completing") {
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
854
|
+
const canonicalState = await readVisibleSkillActiveState(cwd, sessionId);
|
|
855
|
+
if (canonicalState) {
|
|
856
|
+
const blocker = listActiveSkills(canonicalState).find((entry) => (entry.skill === "deep-interview"
|
|
857
|
+
&& matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
|
|
858
|
+
if (!blocker)
|
|
859
|
+
return null;
|
|
860
|
+
}
|
|
861
|
+
if (!hasPendingQuestionObligation) {
|
|
862
|
+
return null;
|
|
863
|
+
}
|
|
864
|
+
const obligationId = safeString(questionEnforcement.obligation_id).trim();
|
|
865
|
+
if (!obligationId)
|
|
866
|
+
return null;
|
|
867
|
+
const systemMessage = `OMX deep-interview is still active (phase: ${phase}) and requires a structured question via omx question before stopping.`;
|
|
868
|
+
return {
|
|
869
|
+
obligationId,
|
|
870
|
+
output: {
|
|
871
|
+
decision: "block",
|
|
872
|
+
reason: `Deep interview is still active (phase: ${phase}) and has a pending structured question obligation; use \`omx question\` before stopping.`,
|
|
873
|
+
stopReason: "deep_interview_question_required",
|
|
874
|
+
systemMessage,
|
|
875
|
+
},
|
|
876
|
+
};
|
|
877
|
+
}
|
|
740
878
|
function resolveRepeatableStopSessionId(payload, canonicalSessionId) {
|
|
741
879
|
return canonicalSessionId?.trim() || readPayloadSessionId(payload) || "";
|
|
742
880
|
}
|
|
@@ -807,8 +945,8 @@ async function maybeReturnRepeatableStopOutput(payload, stateDir, signature, out
|
|
|
807
945
|
await persistNativeStopSignature(stateDir, payload, signature, canonicalSessionId);
|
|
808
946
|
return output;
|
|
809
947
|
}
|
|
810
|
-
async function returnPersistentStopBlock(payload, stateDir, signatureKind, signatureValue, output, canonicalSessionId) {
|
|
811
|
-
return await maybeReturnRepeatableStopOutput(payload, stateDir, buildRepeatableStopSignature(payload, signatureKind, signatureValue, canonicalSessionId), output, canonicalSessionId,
|
|
948
|
+
async function returnPersistentStopBlock(payload, stateDir, signatureKind, signatureValue, output, canonicalSessionId, options = { allowRepeatDuringStopHook: true }) {
|
|
949
|
+
return await maybeReturnRepeatableStopOutput(payload, stateDir, buildRepeatableStopSignature(payload, signatureKind, signatureValue, canonicalSessionId), output, canonicalSessionId, options);
|
|
812
950
|
}
|
|
813
951
|
async function findCanonicalActiveTeamForSession(cwd, sessionId) {
|
|
814
952
|
if (!sessionId.trim())
|
|
@@ -979,6 +1117,20 @@ async function buildStopHookOutput(payload, cwd, stateDir) {
|
|
|
979
1117
|
const threadId = readPayloadThreadId(payload);
|
|
980
1118
|
const ralphState = await readActiveRalphState(stateDir, canonicalSessionId);
|
|
981
1119
|
if (!ralphState) {
|
|
1120
|
+
const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
|
|
1121
|
+
if (autoresearchState) {
|
|
1122
|
+
const completion = await readAutoresearchCompletionStatus(cwd, canonicalSessionId.trim());
|
|
1123
|
+
if (!completion.complete) {
|
|
1124
|
+
const currentPhase = safeString(autoresearchState.current_phase ?? autoresearchState.currentPhase).trim() || 'executing';
|
|
1125
|
+
const systemMessage = `OMX autoresearch is still active (phase: ${currentPhase}); continue until validator evidence is complete before stopping.`;
|
|
1126
|
+
return await maybeReturnRepeatableStopOutput(payload, stateDir, buildRepeatableStopSignature(payload, 'autoresearch-stop', `${currentPhase}|${completion.reason}`, canonicalSessionId), {
|
|
1127
|
+
decision: 'block',
|
|
1128
|
+
reason: systemMessage,
|
|
1129
|
+
stopReason: `autoresearch_${currentPhase}`,
|
|
1130
|
+
systemMessage,
|
|
1131
|
+
}, canonicalSessionId, { allowRepeatDuringStopHook: true });
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
982
1134
|
const teamWorkerOutput = await buildTeamWorkerStopOutput(cwd);
|
|
983
1135
|
if (hasTeamWorkerContext() && teamWorkerOutput)
|
|
984
1136
|
return teamWorkerOutput;
|
|
@@ -988,7 +1140,7 @@ async function buildStopHookOutput(payload, cwd, stateDir) {
|
|
|
988
1140
|
}
|
|
989
1141
|
const ultraworkOutput = await buildModeBasedStopOutput("ultrawork", cwd, canonicalSessionId);
|
|
990
1142
|
if (ultraworkOutput) {
|
|
991
|
-
return await returnPersistentStopBlock(payload, stateDir, "ultrawork-stop", safeString(ultraworkOutput.stopReason), ultraworkOutput, canonicalSessionId);
|
|
1143
|
+
return await returnPersistentStopBlock(payload, stateDir, "ultrawork-stop", safeString(ultraworkOutput.stopReason), ultraworkOutput, canonicalSessionId, { allowRepeatDuringStopHook: false });
|
|
992
1144
|
}
|
|
993
1145
|
const ultraqaOutput = await buildModeBasedStopOutput("ultraqa", cwd, canonicalSessionId);
|
|
994
1146
|
if (ultraqaOutput) {
|
|
@@ -1002,6 +1154,10 @@ async function buildStopHookOutput(payload, cwd, stateDir) {
|
|
|
1002
1154
|
return await returnPersistentStopBlock(payload, stateDir, "team-stop", safeString(teamOutput.stopReason), teamOutput, canonicalSessionId);
|
|
1003
1155
|
}
|
|
1004
1156
|
if (canonicalSessionId) {
|
|
1157
|
+
const deepInterviewQuestionOutput = await buildDeepInterviewQuestionStopOutput(cwd, canonicalSessionId, threadId);
|
|
1158
|
+
if (deepInterviewQuestionOutput) {
|
|
1159
|
+
return await returnPersistentStopBlock(payload, stateDir, "deep-interview-question-stop", deepInterviewQuestionOutput.obligationId, deepInterviewQuestionOutput.output, canonicalSessionId);
|
|
1160
|
+
}
|
|
1005
1161
|
const canonicalTeam = await findCanonicalActiveTeamForSession(cwd, canonicalSessionId);
|
|
1006
1162
|
if (canonicalTeam) {
|
|
1007
1163
|
const canonicalTeamOutput = buildTeamStopOutputForPhase(canonicalTeam.teamName, canonicalTeam.phase);
|
|
@@ -1046,21 +1202,36 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
1046
1202
|
await mkdir(stateDir, { recursive: true });
|
|
1047
1203
|
const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
|
|
1048
1204
|
let skillState = null;
|
|
1205
|
+
let triageAdditionalContext = null;
|
|
1049
1206
|
const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
|
|
1050
1207
|
const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
|
|
1051
1208
|
const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
|
|
1052
|
-
|
|
1209
|
+
const currentSessionState = await readUsableSessionState(cwd);
|
|
1210
|
+
let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
1211
|
+
let resolvedNativeSessionId = nativeSessionId;
|
|
1053
1212
|
if (hookEventName === "SessionStart" && nativeSessionId) {
|
|
1054
1213
|
const sessionState = await reconcileNativeSessionStart(cwd, nativeSessionId, {
|
|
1055
1214
|
pid: options.sessionOwnerPid ?? resolveSessionOwnerPid(payload),
|
|
1056
1215
|
});
|
|
1057
1216
|
canonicalSessionId = safeString(sessionState.session_id).trim();
|
|
1217
|
+
resolvedNativeSessionId = safeString(sessionState.native_session_id).trim() || nativeSessionId;
|
|
1058
1218
|
}
|
|
1059
1219
|
else if (!canonicalSessionId) {
|
|
1060
|
-
canonicalSessionId = safeString(
|
|
1220
|
+
canonicalSessionId = safeString(currentSessionState?.session_id).trim();
|
|
1221
|
+
}
|
|
1222
|
+
if (hookEventName === "Stop") {
|
|
1223
|
+
const stopCanonicalSessionId = await resolveInternalSessionIdForPayload(cwd, readPayloadSessionId(payload));
|
|
1224
|
+
if (stopCanonicalSessionId) {
|
|
1225
|
+
canonicalSessionId = stopCanonicalSessionId;
|
|
1226
|
+
}
|
|
1227
|
+
if (canonicalSessionId && safeString(currentSessionState?.session_id).trim() === canonicalSessionId) {
|
|
1228
|
+
resolvedNativeSessionId =
|
|
1229
|
+
safeString(currentSessionState?.native_session_id).trim() || resolvedNativeSessionId;
|
|
1230
|
+
}
|
|
1061
1231
|
}
|
|
1062
1232
|
const eventSessionId = canonicalSessionId || nativeSessionId || undefined;
|
|
1063
1233
|
const sessionIdForState = canonicalSessionId || nativeSessionId;
|
|
1234
|
+
let outputJson = null;
|
|
1064
1235
|
if (hookEventName === "UserPromptSubmit") {
|
|
1065
1236
|
const prompt = readPromptText(payload);
|
|
1066
1237
|
if (prompt) {
|
|
@@ -1072,13 +1243,85 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
1072
1243
|
turnId,
|
|
1073
1244
|
});
|
|
1074
1245
|
}
|
|
1075
|
-
|
|
1246
|
+
// --- Triage classifier (advisory-only, non-keyword prompts) ---
|
|
1247
|
+
if (prompt && skillState === null) {
|
|
1248
|
+
try {
|
|
1249
|
+
if (readTriageConfig().enabled) {
|
|
1250
|
+
const normalized = prompt.trim().toLowerCase();
|
|
1251
|
+
const previous = readTriageState({ cwd, sessionId: sessionIdForState || null });
|
|
1252
|
+
const suppress = shouldSuppressFollowup({
|
|
1253
|
+
previous,
|
|
1254
|
+
currentPrompt: normalized,
|
|
1255
|
+
currentHasKeyword: false,
|
|
1256
|
+
});
|
|
1257
|
+
if (!suppress) {
|
|
1258
|
+
const decision = triagePrompt(prompt);
|
|
1259
|
+
const nowIso = new Date().toISOString();
|
|
1260
|
+
const effectiveTurnId = turnId || nowIso;
|
|
1261
|
+
if (decision.lane === "HEAVY") {
|
|
1262
|
+
triageAdditionalContext =
|
|
1263
|
+
"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.";
|
|
1264
|
+
const newState = {
|
|
1265
|
+
version: 1,
|
|
1266
|
+
last_triage: {
|
|
1267
|
+
lane: "HEAVY",
|
|
1268
|
+
destination: "autopilot",
|
|
1269
|
+
reason: decision.reason,
|
|
1270
|
+
prompt_signature: promptSignature(normalized),
|
|
1271
|
+
turn_id: effectiveTurnId,
|
|
1272
|
+
created_at: nowIso,
|
|
1273
|
+
},
|
|
1274
|
+
suppress_followup: true,
|
|
1275
|
+
};
|
|
1276
|
+
writeTriageState({ cwd, sessionId: sessionIdForState || null, state: newState });
|
|
1277
|
+
}
|
|
1278
|
+
else if (decision.lane === "LIGHT") {
|
|
1279
|
+
if (decision.destination === "explore") {
|
|
1280
|
+
triageAdditionalContext =
|
|
1281
|
+
"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.";
|
|
1282
|
+
}
|
|
1283
|
+
else if (decision.destination === "executor") {
|
|
1284
|
+
triageAdditionalContext =
|
|
1285
|
+
"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.";
|
|
1286
|
+
}
|
|
1287
|
+
else if (decision.destination === "designer") {
|
|
1288
|
+
triageAdditionalContext =
|
|
1289
|
+
"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.";
|
|
1290
|
+
}
|
|
1291
|
+
if (triageAdditionalContext !== null) {
|
|
1292
|
+
const dest = decision.destination;
|
|
1293
|
+
const newState = {
|
|
1294
|
+
version: 1,
|
|
1295
|
+
last_triage: {
|
|
1296
|
+
lane: "LIGHT",
|
|
1297
|
+
destination: dest,
|
|
1298
|
+
reason: decision.reason,
|
|
1299
|
+
prompt_signature: promptSignature(normalized),
|
|
1300
|
+
turn_id: effectiveTurnId,
|
|
1301
|
+
created_at: nowIso,
|
|
1302
|
+
},
|
|
1303
|
+
suppress_followup: true,
|
|
1304
|
+
};
|
|
1305
|
+
writeTriageState({ cwd, sessionId: sessionIdForState || null, state: newState });
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
// lane === "PASS": no context, no state write
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
catch {
|
|
1313
|
+
// Swallow all triage errors; never break the hook
|
|
1314
|
+
triageAdditionalContext = null;
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
const reconcileHudForPromptSubmitFn = options.reconcileHudForPromptSubmitFn ?? reconcileHudForPromptSubmit;
|
|
1318
|
+
await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => { });
|
|
1076
1319
|
}
|
|
1077
1320
|
if (omxEventName) {
|
|
1078
|
-
const baseContext = buildBaseContext(cwd, payload, hookEventName);
|
|
1079
|
-
if (
|
|
1080
|
-
baseContext.native_session_id =
|
|
1081
|
-
baseContext.codex_session_id =
|
|
1321
|
+
const baseContext = buildBaseContext(cwd, payload, hookEventName, canonicalSessionId);
|
|
1322
|
+
if (resolvedNativeSessionId) {
|
|
1323
|
+
baseContext.native_session_id = resolvedNativeSessionId;
|
|
1324
|
+
baseContext.codex_session_id = resolvedNativeSessionId;
|
|
1082
1325
|
}
|
|
1083
1326
|
if (canonicalSessionId) {
|
|
1084
1327
|
baseContext.omx_session_id = canonicalSessionId;
|
|
@@ -1091,11 +1334,10 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
1091
1334
|
});
|
|
1092
1335
|
await dispatchHookEvent(event, { cwd });
|
|
1093
1336
|
}
|
|
1094
|
-
let outputJson = null;
|
|
1095
1337
|
if (hookEventName === "SessionStart" || hookEventName === "UserPromptSubmit") {
|
|
1096
1338
|
const additionalContext = hookEventName === "SessionStart"
|
|
1097
1339
|
? await buildSessionStartContext(cwd, canonicalSessionId || nativeSessionId)
|
|
1098
|
-
: buildAdditionalContextMessage(readPromptText(payload), skillState);
|
|
1340
|
+
: (buildAdditionalContextMessage(readPromptText(payload), skillState, cwd) ?? triageAdditionalContext);
|
|
1099
1341
|
if (additionalContext) {
|
|
1100
1342
|
outputJson = {
|
|
1101
1343
|
hookSpecificOutput: {
|
|
@@ -1124,6 +1366,11 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
1124
1366
|
outputJson,
|
|
1125
1367
|
};
|
|
1126
1368
|
}
|
|
1369
|
+
export function isCodexNativeHookMainModule(moduleUrl, argv1) {
|
|
1370
|
+
if (!argv1)
|
|
1371
|
+
return false;
|
|
1372
|
+
return moduleUrl === pathToFileURL(argv1).href;
|
|
1373
|
+
}
|
|
1127
1374
|
async function readStdinJson() {
|
|
1128
1375
|
const chunks = [];
|
|
1129
1376
|
for await (const chunk of process.stdin) {
|
|
@@ -1164,7 +1411,7 @@ export async function runCodexNativeHookCli() {
|
|
|
1164
1411
|
process.stdout.write(`${JSON.stringify(result.outputJson)}\n`);
|
|
1165
1412
|
}
|
|
1166
1413
|
}
|
|
1167
|
-
if (import.meta.url
|
|
1414
|
+
if (isCodexNativeHookMainModule(import.meta.url, process.argv[1])) {
|
|
1168
1415
|
runCodexNativeHookCli().catch((error) => {
|
|
1169
1416
|
process.stderr.write(`[omx] codex-native-hook failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
1170
1417
|
process.exitCode = 1;
|