oh-my-codex 0.16.3 → 0.17.0
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 +3 -3
- package/dist/catalog/__tests__/generator.test.js +2 -0
- package/dist/catalog/__tests__/generator.test.js.map +1 -1
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +9 -0
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
- package/dist/cli/__tests__/cleanup.test.js +27 -0
- package/dist/cli/__tests__/cleanup.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +7 -5
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +175 -7
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +147 -12
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-serve.test.js +4 -0
- package/dist/cli/__tests__/mcp-serve.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +2 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +47 -0
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +10 -5
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +299 -27
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +85 -3
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +1 -1
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +108 -0
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +91 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +54 -8
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/cleanup.d.ts.map +1 -1
- package/dist/cli/cleanup.js +8 -4
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/codex-feature-probe.d.ts +9 -0
- package/dist/cli/codex-feature-probe.d.ts.map +1 -0
- package/dist/cli/codex-feature-probe.js +28 -0
- package/dist/cli/codex-feature-probe.js.map +1 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +214 -23
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +17 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +152 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.js +8 -8
- package/dist/cli/mcp-parity.js.map +1 -1
- package/dist/cli/mcp-serve.d.ts.map +1 -1
- package/dist/cli/mcp-serve.js +4 -0
- package/dist/cli/mcp-serve.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +23 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +203 -1
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +21 -0
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +4 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +7 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +5 -3
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +140 -51
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +70 -5
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +2 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +12 -3
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/config/__tests__/codex-feature-flags.test.d.ts +2 -0
- package/dist/config/__tests__/codex-feature-flags.test.d.ts.map +1 -0
- package/dist/config/__tests__/codex-feature-flags.test.js +35 -0
- package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -0
- package/dist/config/__tests__/codex-hooks.test.js +143 -9
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +85 -9
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +116 -11
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/wiki-config-contract.test.js +6 -3
- package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
- package/dist/config/codex-feature-flags.d.ts +21 -0
- package/dist/config/codex-feature-flags.d.ts.map +1 -0
- package/dist/config/codex-feature-flags.js +56 -0
- package/dist/config/codex-feature-flags.js.map +1 -0
- package/dist/config/codex-hooks.d.ts +14 -13
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +108 -8
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +15 -3
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +233 -129
- package/dist/config/generator.js.map +1 -1
- package/dist/config/omx-first-party-mcp.d.ts +3 -1
- package/dist/config/omx-first-party-mcp.d.ts.map +1 -1
- package/dist/config/omx-first-party-mcp.js +9 -2
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- package/dist/hooks/__tests__/design-skill.test.d.ts +2 -0
- package/dist/hooks/__tests__/design-skill.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/design-skill.test.js +55 -0
- package/dist/hooks/__tests__/design-skill.test.js.map +1 -0
- package/dist/hooks/__tests__/keyword-detector.test.js +92 -2
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +125 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +265 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts +2 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +84 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -0
- package/dist/hooks/__tests__/skill-guidance-contract.test.js +41 -0
- package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +2 -2
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +1 -0
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +12 -6
- 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 +2 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +47 -2
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +164 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +4 -5
- package/dist/hud/state.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +3 -0
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/hermes-bridge.test.d.ts +2 -0
- package/dist/mcp/__tests__/hermes-bridge.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/hermes-bridge.test.js +374 -0
- package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -0
- package/dist/mcp/__tests__/state-paths.test.js +155 -11
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +166 -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 +2 -0
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/hermes-bridge.d.ts +81 -0
- package/dist/mcp/hermes-bridge.d.ts.map +1 -0
- package/dist/mcp/hermes-bridge.js +400 -0
- package/dist/mcp/hermes-bridge.js.map +1 -0
- package/dist/mcp/hermes-server.d.ts +269 -0
- package/dist/mcp/hermes-server.d.ts.map +1 -0
- package/dist/mcp/hermes-server.js +121 -0
- package/dist/mcp/hermes-server.js.map +1 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +64 -11
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +22 -0
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/__tests__/base-tmux-pane.test.js +88 -27
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +5 -0
- package/dist/modes/base.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts +2 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts.map +1 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +316 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts +2 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts.map +1 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js +481 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js.map +1 -0
- package/dist/planning/__tests__/artifacts.test.js +533 -4
- package/dist/planning/__tests__/artifacts.test.js.map +1 -1
- package/dist/planning/__tests__/context-pack-status.test.js +524 -0
- package/dist/planning/__tests__/context-pack-status.test.js.map +1 -1
- package/dist/planning/__tests__/markdown-structure.test.d.ts +2 -0
- package/dist/planning/__tests__/markdown-structure.test.d.ts.map +1 -0
- package/dist/planning/__tests__/markdown-structure.test.js +459 -0
- package/dist/planning/__tests__/markdown-structure.test.js.map +1 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +523 -1
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -1
- package/dist/planning/artifacts.d.ts +1 -1
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +227 -28
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/planning/context-pack-status.d.ts +25 -0
- package/dist/planning/context-pack-status.d.ts.map +1 -1
- package/dist/planning/context-pack-status.js +272 -31
- package/dist/planning/context-pack-status.js.map +1 -1
- package/dist/planning/markdown-structure.d.ts +20 -0
- package/dist/planning/markdown-structure.d.ts.map +1 -0
- package/dist/planning/markdown-structure.js +137 -0
- package/dist/planning/markdown-structure.js.map +1 -0
- package/dist/ralph/__tests__/completion-audit.test.d.ts +2 -0
- package/dist/ralph/__tests__/completion-audit.test.d.ts.map +1 -0
- package/dist/ralph/__tests__/completion-audit.test.js +121 -0
- package/dist/ralph/__tests__/completion-audit.test.js.map +1 -0
- package/dist/ralph/completion-audit.d.ts +8 -0
- package/dist/ralph/completion-audit.d.ts.map +1 -0
- package/dist/ralph/completion-audit.js +99 -0
- package/dist/ralph/completion-audit.js.map +1 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js +407 -15
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js +126 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +177 -71
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +4 -2
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/notify-dispatcher.js +30 -1
- package/dist/scripts/notify-dispatcher.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +91 -2
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +3 -1
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +102 -27
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/mode-state-context.d.ts +2 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +21 -0
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +9 -3
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +7 -0
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +25 -8
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts +1 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +22 -15
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.js +3 -3
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js +39 -0
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +5 -0
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +497 -2
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js +1 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +8 -0
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/approved-execution.d.ts.map +1 -1
- package/dist/team/approved-execution.js +3 -0
- package/dist/team/approved-execution.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +43 -0
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +4 -0
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +2 -6
- package/dist/team/state.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +245 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +21 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +52 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +301 -15
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/utils/__tests__/paths.test.js +31 -1
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/paths.d.ts +6 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +18 -0
- package/dist/utils/paths.js.map +1 -1
- package/dist/wiki/lifecycle.js +4 -4
- package/dist/wiki/lifecycle.js.map +1 -1
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/.mcp.json +13 -5
- package/plugins/oh-my-codex/skills/analyze/SKILL.md +0 -2
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -3
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +5 -7
- package/plugins/oh-my-codex/skills/design/SKILL.md +180 -0
- package/plugins/oh-my-codex/skills/doctor/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/plan/SKILL.md +3 -6
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +9 -10
- package/plugins/oh-my-codex/skills/skill/SKILL.md +2 -1
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +36 -3
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +175 -64
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
- package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/wiki/SKILL.md +13 -13
- package/skills/analyze/SKILL.md +0 -2
- package/skills/ask-claude/SKILL.md +5 -3
- package/skills/ask-gemini/SKILL.md +5 -3
- package/skills/autopilot/SKILL.md +2 -2
- package/skills/code-review/SKILL.md +1 -3
- package/skills/deep-interview/SKILL.md +5 -7
- package/skills/design/SKILL.md +180 -0
- package/skills/doctor/SKILL.md +2 -2
- package/skills/ecomode/SKILL.md +105 -1
- package/skills/frontend-ui-ux/SKILL.md +6 -24
- package/skills/git-master/SKILL.md +2 -4
- package/skills/omx-setup/SKILL.md +3 -3
- package/skills/pipeline/SKILL.md +3 -3
- package/skills/plan/SKILL.md +3 -6
- package/skills/ralph/SKILL.md +9 -10
- package/skills/skill/SKILL.md +2 -1
- package/skills/swarm/SKILL.md +5 -3
- package/skills/tdd/SKILL.md +95 -1
- package/skills/ultragoal/SKILL.md +36 -3
- package/skills/ultraqa/SKILL.md +175 -64
- package/skills/ultrawork/SKILL.md +8 -8
- package/skills/visual-ralph/SKILL.md +2 -2
- package/skills/web-clone/SKILL.md +348 -1
- package/skills/wiki/SKILL.md +13 -13
- package/src/scripts/__tests__/codex-native-hook.test.ts +437 -14
- package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
- package/src/scripts/codex-native-hook.ts +205 -61
- package/src/scripts/codex-native-pre-post.ts +4 -1
- package/src/scripts/notify-dispatcher.ts +40 -1
- package/src/scripts/notify-hook/tmux-injection.ts +110 -3
- package/src/scripts/notify-hook.ts +3 -1
- package/templates/catalog-manifest.json +9 -2
|
@@ -4,14 +4,14 @@ import { appendFile, mkdir, readFile, readdir, writeFile } from "fs/promises";
|
|
|
4
4
|
import { extname, join, relative, resolve } from "path";
|
|
5
5
|
import { pathToFileURL } from "url";
|
|
6
6
|
import { readModeState, readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
|
|
7
|
-
import { extractSessionIdFromInitializedStatePath,
|
|
7
|
+
import { extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
|
|
8
8
|
import { readSubagentSessionSummary, recordSubagentTurnForSession, } from "../subagents/tracker.js";
|
|
9
9
|
import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
|
|
10
10
|
import { appendToLog, isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
|
|
11
11
|
import { appendTeamEvent, readTeamLeaderAttention, readTeamManifestV2, readTeamPhase, writeTeamLeaderAttention, writeTeamPhase, } from "../team/state.js";
|
|
12
|
-
import { omxNotepadPath,
|
|
12
|
+
import { omxNotepadPath, resolveProjectMemoryPath } from "../utils/paths.js";
|
|
13
13
|
import { findGitLayout } from "../utils/git-layout.js";
|
|
14
|
-
import { getStateFilePath, getStatePath } from "../mcp/state-paths.js";
|
|
14
|
+
import { getBaseStateDir, getStateFilePath, getStatePath } from "../mcp/state-paths.js";
|
|
15
15
|
import { detectKeywords, detectPrimaryKeyword, recordSkillActivation, } from "../hooks/keyword-detector.js";
|
|
16
16
|
import { detectNativeStopStallPattern, loadAutoNudgeConfig, normalizeAutoNudgeSignatureText, resolveEffectiveAutoNudgeResponse, } from "./notify-hook/auto-nudge.js";
|
|
17
17
|
import { SLOPPY_FALLBACK_GROUNDING_PATTERNS, SLOPPY_FALLBACK_IMPLEMENTATION_CONTEXT_PATTERNS, SLOPPY_FALLBACK_PHRASE_PATTERNS, buildNativePostToolUseOutput, buildNativePreToolUseOutput, detectMcpTransportFailure, hasAnyPattern, } from "./codex-native-pre-post.js";
|
|
@@ -24,6 +24,7 @@ import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
|
|
|
24
24
|
import { onPreCompact as buildWikiPreCompactContext, onSessionStart as buildWikiSessionStartContext, } from "../wiki/lifecycle.js";
|
|
25
25
|
import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
|
|
26
26
|
import { readRunState } from "../runtime/run-state.js";
|
|
27
|
+
import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
|
|
27
28
|
import { getRunContinuationSnapshot, shouldContinueRun } from "../runtime/run-loop.js";
|
|
28
29
|
import { triagePrompt } from "../hooks/triage-heuristic.js";
|
|
29
30
|
import { readTriageConfig } from "../hooks/triage-config.js";
|
|
@@ -62,6 +63,12 @@ function safeString(value) {
|
|
|
62
63
|
function safeObject(value) {
|
|
63
64
|
return value && typeof value === "object" ? value : {};
|
|
64
65
|
}
|
|
66
|
+
function safeContextSnippet(value, maxLength = 300) {
|
|
67
|
+
const text = safeString(value).replace(/\s+/g, " ").trim();
|
|
68
|
+
if (text.length <= maxLength)
|
|
69
|
+
return text;
|
|
70
|
+
return `${text.slice(0, maxLength - 1).trimEnd()}…`;
|
|
71
|
+
}
|
|
65
72
|
function readBoundedFirstLineSync(path) {
|
|
66
73
|
const fd = openSync(path, "r");
|
|
67
74
|
try {
|
|
@@ -381,15 +388,15 @@ async function readCanonicalTerminalRunStateForStop(cwd, sessionId, mode) {
|
|
|
381
388
|
const runRecord = runState;
|
|
382
389
|
return shouldHonorCanonicalTerminalRunState(runRecord, mode) ? runRecord : null;
|
|
383
390
|
}
|
|
384
|
-
async function isVisibleRalphActiveForSession(
|
|
385
|
-
const canonicalState = await
|
|
391
|
+
async function isVisibleRalphActiveForSession(stateDir, sessionId) {
|
|
392
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
386
393
|
if (!canonicalState)
|
|
387
394
|
return false;
|
|
388
395
|
return listActiveSkills(canonicalState).some((entry) => (entry.skill === "ralph"
|
|
389
396
|
&& matchesSkillStopContext(entry, canonicalState, sessionId, "")));
|
|
390
397
|
}
|
|
391
|
-
async function hasConsistentRalphSkillActivation(
|
|
392
|
-
const canonicalState = await
|
|
398
|
+
async function hasConsistentRalphSkillActivation(stateDir, sessionId) {
|
|
399
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
393
400
|
if (!canonicalState)
|
|
394
401
|
return true;
|
|
395
402
|
const initializedMode = safeString(canonicalState.initialized_mode).trim();
|
|
@@ -400,8 +407,63 @@ async function hasConsistentRalphSkillActivation(cwd, sessionId) {
|
|
|
400
407
|
return false;
|
|
401
408
|
return true;
|
|
402
409
|
}
|
|
403
|
-
async function
|
|
404
|
-
const
|
|
410
|
+
async function readRalphCompletionAuditBlockState(cwd, stateDir, preferredSessionId, ownerContext) {
|
|
411
|
+
const [rawSessionInfo, usableSessionInfo] = await Promise.all([
|
|
412
|
+
readSessionState(cwd),
|
|
413
|
+
readUsableSessionState(cwd),
|
|
414
|
+
]);
|
|
415
|
+
const currentOmxSessionId = safeString(usableSessionInfo?.session_id).trim();
|
|
416
|
+
const currentNativeSessionId = safeString(usableSessionInfo?.native_session_id).trim();
|
|
417
|
+
const staleCurrentSessionId = rawSessionInfo && !isSessionStateUsable(rawSessionInfo, cwd)
|
|
418
|
+
? safeString(rawSessionInfo.session_id).trim()
|
|
419
|
+
: "";
|
|
420
|
+
const sessionCandidates = [...new Set([
|
|
421
|
+
safeString(preferredSessionId).trim(),
|
|
422
|
+
currentOmxSessionId,
|
|
423
|
+
].filter(Boolean))];
|
|
424
|
+
const evaluateCandidate = (state, path, sessionId) => {
|
|
425
|
+
if (!state || state.mode && safeString(state.mode) !== "ralph")
|
|
426
|
+
return null;
|
|
427
|
+
if (!isRalphCompletePhase(state.current_phase ?? state.currentPhase))
|
|
428
|
+
return null;
|
|
429
|
+
if (activeRalphStateMatchesStopOwner(state, {
|
|
430
|
+
sessionId,
|
|
431
|
+
payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
|
|
432
|
+
threadId: safeString(ownerContext?.threadId).trim(),
|
|
433
|
+
currentNativeSessionId,
|
|
434
|
+
tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
|
|
435
|
+
}) !== true)
|
|
436
|
+
return null;
|
|
437
|
+
const audit = evaluateRalphCompletionAuditEvidence(state, cwd);
|
|
438
|
+
return audit.complete ? null : { state, path, reason: audit.reason };
|
|
439
|
+
};
|
|
440
|
+
for (const sessionId of sessionCandidates) {
|
|
441
|
+
if (staleCurrentSessionId && sessionId === staleCurrentSessionId)
|
|
442
|
+
continue;
|
|
443
|
+
const sessionScopedPath = getStateFilePath("ralph-state.json", cwd, sessionId);
|
|
444
|
+
const result = evaluateCandidate(await readJsonIfExists(sessionScopedPath), sessionScopedPath, sessionId);
|
|
445
|
+
if (result)
|
|
446
|
+
return result;
|
|
447
|
+
}
|
|
448
|
+
if (sessionCandidates.length > 0)
|
|
449
|
+
return null;
|
|
450
|
+
const directPath = join(stateDir, "ralph-state.json");
|
|
451
|
+
return evaluateCandidate(await readJsonIfExists(directPath), directPath, "");
|
|
452
|
+
}
|
|
453
|
+
async function reopenRalphCompletionAuditBlock(block) {
|
|
454
|
+
const nowIso = new Date().toISOString();
|
|
455
|
+
const next = {
|
|
456
|
+
...block.state,
|
|
457
|
+
active: true,
|
|
458
|
+
current_phase: "verifying",
|
|
459
|
+
completion_audit_gate: "blocked",
|
|
460
|
+
completion_audit_missing_reason: block.reason,
|
|
461
|
+
completion_audit_blocked_at: nowIso,
|
|
462
|
+
};
|
|
463
|
+
delete next.completed_at;
|
|
464
|
+
await writeFile(block.path, JSON.stringify(next, null, 2));
|
|
465
|
+
}
|
|
466
|
+
async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerContext) {
|
|
405
467
|
const [rawSessionInfo, usableSessionInfo] = await Promise.all([
|
|
406
468
|
readSessionState(cwd),
|
|
407
469
|
readUsableSessionState(cwd),
|
|
@@ -429,7 +491,7 @@ async function readActiveRalphState(stateDir, preferredSessionId, ownerContext)
|
|
|
429
491
|
const sessionScoped = await readJsonIfExists(sessionScopedPath);
|
|
430
492
|
if (sessionScoped?.active === true
|
|
431
493
|
&& isRalphStartingPhase(sessionScoped)
|
|
432
|
-
&& !(await isVisibleRalphActiveForSession(
|
|
494
|
+
&& !(await isVisibleRalphActiveForSession(stateDir, sessionId))) {
|
|
433
495
|
continue;
|
|
434
496
|
}
|
|
435
497
|
if (sessionScoped?.active === true
|
|
@@ -441,7 +503,7 @@ async function readActiveRalphState(stateDir, preferredSessionId, ownerContext)
|
|
|
441
503
|
currentNativeSessionId,
|
|
442
504
|
tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
|
|
443
505
|
})
|
|
444
|
-
&& await hasConsistentRalphSkillActivation(
|
|
506
|
+
&& await hasConsistentRalphSkillActivation(stateDir, sessionId)) {
|
|
445
507
|
return { state: sessionScoped, path: sessionScopedPath };
|
|
446
508
|
}
|
|
447
509
|
}
|
|
@@ -818,14 +880,17 @@ async function buildSessionStartContext(cwd, sessionId, options = {}) {
|
|
|
818
880
|
if (modeSummaries.length > 0) {
|
|
819
881
|
sections.push(["[Active OMX modes]", ...modeSummaries].join("\n"));
|
|
820
882
|
}
|
|
821
|
-
const
|
|
822
|
-
|
|
883
|
+
const projectMemoryPath = resolveProjectMemoryPath(cwd);
|
|
884
|
+
const projectMemory = projectMemoryPath ? await readJsonIfExists(projectMemoryPath) : null;
|
|
885
|
+
if (projectMemory && projectMemoryPath) {
|
|
823
886
|
const directives = Array.isArray(projectMemory.directives) ? projectMemory.directives : [];
|
|
824
887
|
const notes = Array.isArray(projectMemory.notes) ? projectMemory.notes : [];
|
|
825
|
-
const techStack =
|
|
826
|
-
const conventions =
|
|
827
|
-
const build =
|
|
888
|
+
const techStack = safeContextSnippet(projectMemory.techStack);
|
|
889
|
+
const conventions = safeContextSnippet(projectMemory.conventions);
|
|
890
|
+
const build = safeContextSnippet(projectMemory.build);
|
|
828
891
|
const summary = [];
|
|
892
|
+
const relativeMemoryPath = relative(cwd, projectMemoryPath).replace(/\\/g, "/");
|
|
893
|
+
summary.push(`- source: ${relativeMemoryPath === "project-memory.json" ? "project-memory.json" : ".omx/project-memory.json"}`);
|
|
829
894
|
if (techStack)
|
|
830
895
|
summary.push(`- stack: ${techStack}`);
|
|
831
896
|
if (conventions)
|
|
@@ -834,17 +899,17 @@ async function buildSessionStartContext(cwd, sessionId, options = {}) {
|
|
|
834
899
|
summary.push(`- build: ${build}`);
|
|
835
900
|
if (directives.length > 0) {
|
|
836
901
|
const firstDirective = directives[0];
|
|
837
|
-
const directive =
|
|
902
|
+
const directive = safeContextSnippet(firstDirective.directive);
|
|
838
903
|
if (directive)
|
|
839
904
|
summary.push(`- directive: ${directive}`);
|
|
840
905
|
}
|
|
841
906
|
if (notes.length > 0) {
|
|
842
907
|
const firstNote = notes[0];
|
|
843
|
-
const note =
|
|
908
|
+
const note = safeContextSnippet(firstNote.content);
|
|
844
909
|
if (note)
|
|
845
910
|
summary.push(`- note: ${note}`);
|
|
846
911
|
}
|
|
847
|
-
if (summary.length >
|
|
912
|
+
if (summary.length > 1) {
|
|
848
913
|
sections.push(["[Project memory]", ...summary].join("\n"));
|
|
849
914
|
}
|
|
850
915
|
}
|
|
@@ -1030,6 +1095,9 @@ function buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessio
|
|
|
1030
1095
|
transition_error: "Codex App/native outside-tmux sessions cannot activate the tmux-only `team` workflow directly. Launch OMX CLI from an attached tmux shell first, then run `omx team ...` there.",
|
|
1031
1096
|
};
|
|
1032
1097
|
}
|
|
1098
|
+
function buildSkillStateCliInstruction(mode, statePath) {
|
|
1099
|
+
return `skill: ${mode} activated and initial state initialized at ${statePath}; use CLI-first state updates via \`omx state write/read/clear --input '<json>' --json\`; use omx_state MCP only when explicit MCP compatibility is enabled.`;
|
|
1100
|
+
}
|
|
1033
1101
|
function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(), payload) {
|
|
1034
1102
|
if (!prompt)
|
|
1035
1103
|
return null;
|
|
@@ -1089,7 +1157,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1089
1157
|
promptPriorityMessage,
|
|
1090
1158
|
ultragoalPromptActivationNote,
|
|
1091
1159
|
skillState.initialized_mode && skillState.initialized_state_path
|
|
1092
|
-
?
|
|
1160
|
+
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
1093
1161
|
: null,
|
|
1094
1162
|
teamDetected
|
|
1095
1163
|
? buildTeamRuntimeInstruction(cwd, payload)
|
|
@@ -1100,7 +1168,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1100
1168
|
}
|
|
1101
1169
|
if (teamDetected) {
|
|
1102
1170
|
const initializedStateMessage = skillState?.initialized_mode && skillState.initialized_state_path
|
|
1103
|
-
?
|
|
1171
|
+
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
1104
1172
|
: null;
|
|
1105
1173
|
return [
|
|
1106
1174
|
detectedKeywordMessage,
|
|
@@ -1126,7 +1194,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1126
1194
|
? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
|
|
1127
1195
|
: null,
|
|
1128
1196
|
promptPriorityMessage,
|
|
1129
|
-
|
|
1197
|
+
buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path),
|
|
1130
1198
|
deepInterviewPromptActivationNote,
|
|
1131
1199
|
ultraworkPromptActivationNote,
|
|
1132
1200
|
ultragoalPromptActivationNote,
|
|
@@ -1164,7 +1232,7 @@ async function resolveTeamWorkerStopDecision(cwd) {
|
|
|
1164
1232
|
|| parseTeamWorkerEnv(safeString(process.env.OMX_TEAM_WORKER));
|
|
1165
1233
|
if (!workerContext)
|
|
1166
1234
|
return { kind: "unresolved", reason: "missing_worker_context" };
|
|
1167
|
-
const blockWorkerStop = (reasonCode, detail, stateDirForDecision =
|
|
1235
|
+
const blockWorkerStop = (reasonCode, detail, stateDirForDecision = getBaseStateDir(cwd)) => ({
|
|
1168
1236
|
kind: "blocked",
|
|
1169
1237
|
stateDir: stateDirForDecision,
|
|
1170
1238
|
workerContext,
|
|
@@ -1281,19 +1349,32 @@ async function buildModeBasedStopOutput(mode, cwd, sessionId) {
|
|
|
1281
1349
|
systemMessage: `OMX ${mode} is still active (phase: ${phase}).`,
|
|
1282
1350
|
};
|
|
1283
1351
|
}
|
|
1284
|
-
function looksLikeGoalCompletionPrompt(text) {
|
|
1285
|
-
return /\
|
|
1286
|
-
|| /\
|
|
1287
|
-
|| /\
|
|
1352
|
+
export function looksLikeGoalCompletionPrompt(text) {
|
|
1353
|
+
return /\bupdate_goal\s*\(/i.test(text)
|
|
1354
|
+
|| /\bomx\s+(?:ultragoal|performance-goal|autoresearch-goal)\s+(?:checkpoint|complete)\b/i.test(text)
|
|
1355
|
+
|| /\b(?:complete|checkpoint|finish|close|mark)\b.{0,80}\b(?:goal|ultragoal|performance[-\s]goal|autoresearch[-\s]goal)\b/i.test(text)
|
|
1356
|
+
|| /\b(?:ultragoal|performance[-\s]goal|autoresearch[-\s]goal)\b.{0,80}\b(?:complete|checkpoint|finish|close|mark)\b/i.test(text)
|
|
1357
|
+
|| /(?:^|[.!?]\s+)(?:the\s+)?goal\s+(?:is\s+|now\s+|has\s+been\s+)?(?:complete|completed|finished|closed)(?:\s*(?:[.!?]|$)|\s*[:;]\s*\S|\s*[—–-]\s*\S)/i.test(text);
|
|
1288
1358
|
}
|
|
1289
1359
|
async function findActiveGoalWorkflowReconciliationRequirement(cwd) {
|
|
1290
1360
|
const ultragoal = await readJsonIfExists(join(cwd, ".omx", "ultragoal", "goals.json"));
|
|
1361
|
+
const aggregateCompletion = safeObject(ultragoal?.aggregateCompletion);
|
|
1362
|
+
const aggregateProductComplete = safeString(aggregateCompletion.status) === "complete";
|
|
1291
1363
|
const ultragoals = Array.isArray(ultragoal?.goals) ? ultragoal.goals.map(safeObject) : [];
|
|
1292
|
-
const activeUltragoal =
|
|
1364
|
+
const activeUltragoal = aggregateProductComplete
|
|
1365
|
+
? undefined
|
|
1366
|
+
: ultragoals.find((goal) => safeString(goal.status) === "in_progress" || safeString(goal.id) === safeString(ultragoal?.activeGoalId));
|
|
1293
1367
|
if (activeUltragoal) {
|
|
1368
|
+
const goalId = safeString(activeUltragoal.id) || "<goal-id>";
|
|
1294
1369
|
return {
|
|
1295
1370
|
workflow: "ultragoal",
|
|
1296
|
-
command: `omx ultragoal checkpoint --goal-id ${
|
|
1371
|
+
command: `omx ultragoal checkpoint --goal-id ${goalId} --status complete --codex-goal-json '<get_goal JSON or path>' --evidence '<evidence>'`,
|
|
1372
|
+
remediation: [
|
|
1373
|
+
`If get_goal returns a completed task-scoped objective for the same aggregate ultragoal plan, checkpoint ${goalId} with evidence naming ${goalId} plus .omx/ultragoal/goals.json or ledger.jsonl and pass final quality-gate JSON; OMX will reconcile the completed planned scope without mutating Codex goal state.`,
|
|
1374
|
+
`If get_goal instead returns a different completed legacy objective and complete checkpointing fails, do not repeat --status complete in this thread.`,
|
|
1375
|
+
`Record the non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goalId} --status blocked --codex-goal-json '<different completed get_goal JSON or path>' --evidence '<completed legacy Codex goal blocks create_goal in this thread>'.`,
|
|
1376
|
+
"Then continue this ultragoal from a fresh Codex thread in the same repo/worktree and create the intended goal there.",
|
|
1377
|
+
].join(" "),
|
|
1297
1378
|
};
|
|
1298
1379
|
}
|
|
1299
1380
|
const performanceRoot = join(cwd, ".omx", "goals", "performance");
|
|
@@ -1337,7 +1418,8 @@ async function buildGoalWorkflowReconciliationPromptWarning(cwd, prompt) {
|
|
|
1337
1418
|
`OMX ${requirement.workflow} goal workflow requires Codex goal snapshot reconciliation before completion.`,
|
|
1338
1419
|
"Call get_goal, pass the resulting JSON or a path with --codex-goal-json, and do not rely on hooks or shell commands to mutate Codex-owned goal state.",
|
|
1339
1420
|
`Required command shape: ${requirement.command}.`,
|
|
1340
|
-
|
|
1421
|
+
requirement.remediation,
|
|
1422
|
+
].filter(Boolean).join(" ");
|
|
1341
1423
|
}
|
|
1342
1424
|
async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
|
|
1343
1425
|
const lastAssistantMessage = safeString(payload.last_assistant_message ?? payload.lastAssistantMessage);
|
|
@@ -1346,7 +1428,11 @@ async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
|
|
|
1346
1428
|
const requirement = await findActiveGoalWorkflowReconciliationRequirement(cwd);
|
|
1347
1429
|
if (!requirement)
|
|
1348
1430
|
return null;
|
|
1349
|
-
const systemMessage =
|
|
1431
|
+
const systemMessage = [
|
|
1432
|
+
`OMX ${requirement.workflow} requires get_goal snapshot reconciliation before completion; call get_goal and pass --codex-goal-json to ${requirement.command}.`,
|
|
1433
|
+
requirement.remediation,
|
|
1434
|
+
"Hooks must not mutate Codex goal state.",
|
|
1435
|
+
].filter(Boolean).join(" ");
|
|
1350
1436
|
return {
|
|
1351
1437
|
decision: "block",
|
|
1352
1438
|
reason: systemMessage,
|
|
@@ -1354,15 +1440,15 @@ async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
|
|
|
1354
1440
|
systemMessage,
|
|
1355
1441
|
};
|
|
1356
1442
|
}
|
|
1357
|
-
async function readTeamModeStateForStop(cwd, sessionId) {
|
|
1443
|
+
async function readTeamModeStateForStop(cwd, stateDir, sessionId) {
|
|
1358
1444
|
const normalizedSessionId = safeString(sessionId).trim();
|
|
1359
1445
|
if (!normalizedSessionId) {
|
|
1360
1446
|
return await readModeState("team", cwd);
|
|
1361
1447
|
}
|
|
1362
|
-
const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId);
|
|
1448
|
+
const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId, stateDir);
|
|
1363
1449
|
if (scopedState)
|
|
1364
1450
|
return scopedState;
|
|
1365
|
-
const rootState = await readJsonIfExists(join(
|
|
1451
|
+
const rootState = await readJsonIfExists(join(stateDir, "team-state.json"));
|
|
1366
1452
|
if (rootState?.active !== true)
|
|
1367
1453
|
return null;
|
|
1368
1454
|
const ownerSessionId = safeString(rootState.session_id).trim();
|
|
@@ -1375,7 +1461,7 @@ async function buildTeamStopOutput(cwd, sessionId) {
|
|
|
1375
1461
|
if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, "team")) {
|
|
1376
1462
|
return null;
|
|
1377
1463
|
}
|
|
1378
|
-
const teamState = await readTeamModeStateForStop(cwd, sessionId);
|
|
1464
|
+
const teamState = await readTeamModeStateForStop(cwd, getBaseStateDir(cwd), sessionId);
|
|
1379
1465
|
if (teamState?.active !== true)
|
|
1380
1466
|
return null;
|
|
1381
1467
|
const teamName = safeString(teamState.team_name).trim();
|
|
@@ -1425,10 +1511,10 @@ function hasReleaseReadinessMode(payload) {
|
|
|
1425
1511
|
const mode = safeString(payload.mode).trim().toLowerCase();
|
|
1426
1512
|
return mode === "release-readiness";
|
|
1427
1513
|
}
|
|
1428
|
-
async function hasReleaseReadinessStopMarker(cwd, sessionId, teamName) {
|
|
1514
|
+
async function hasReleaseReadinessStopMarker(cwd, stateDir, sessionId, teamName) {
|
|
1429
1515
|
if (!sessionId)
|
|
1430
1516
|
return false;
|
|
1431
|
-
const markerState = await readStopSessionPinnedState("release-readiness-state.json", cwd, sessionId);
|
|
1517
|
+
const markerState = await readStopSessionPinnedState("release-readiness-state.json", cwd, sessionId, stateDir);
|
|
1432
1518
|
if (markerState?.active !== true || markerState.stable_final_recommendation_emitted !== true) {
|
|
1433
1519
|
return false;
|
|
1434
1520
|
}
|
|
@@ -1463,8 +1549,10 @@ async function resolveInternalSessionIdForPayload(cwd, payloadSessionId) {
|
|
|
1463
1549
|
return canonicalSessionId;
|
|
1464
1550
|
return payloadSessionId;
|
|
1465
1551
|
}
|
|
1466
|
-
async function readStopSessionPinnedState(fileName, cwd, sessionId) {
|
|
1467
|
-
const statePath =
|
|
1552
|
+
async function readStopSessionPinnedState(fileName, cwd, sessionId, stateDir) {
|
|
1553
|
+
const statePath = stateDir && sessionId
|
|
1554
|
+
? join(stateDir, "sessions", sessionId, fileName)
|
|
1555
|
+
: getStateFilePath(fileName, cwd, sessionId || undefined);
|
|
1468
1556
|
return readJsonIfExists(statePath);
|
|
1469
1557
|
}
|
|
1470
1558
|
function matchesSkillStopContext(entry, state, sessionId, threadId) {
|
|
@@ -1499,8 +1587,8 @@ function modeStateMatchesSkillStopContext(state, cwd, sessionId) {
|
|
|
1499
1587
|
}
|
|
1500
1588
|
return true;
|
|
1501
1589
|
}
|
|
1502
|
-
async function readBlockingSkillForStop(cwd, sessionId, threadId, requiredSkill) {
|
|
1503
|
-
const canonicalState = await
|
|
1590
|
+
async function readBlockingSkillForStop(cwd, stateDir, sessionId, threadId, requiredSkill) {
|
|
1591
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
1504
1592
|
const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
|
|
1505
1593
|
const candidateSkills = requiredSkill
|
|
1506
1594
|
? [requiredSkill]
|
|
@@ -1509,7 +1597,7 @@ async function readBlockingSkillForStop(cwd, sessionId, threadId, requiredSkill)
|
|
|
1509
1597
|
const terminalRunState = await readCanonicalTerminalRunStateForStop(cwd, sessionId, skill);
|
|
1510
1598
|
if (terminalRunState)
|
|
1511
1599
|
continue;
|
|
1512
|
-
const modeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId);
|
|
1600
|
+
const modeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
|
|
1513
1601
|
if (!modeState || modeState.active !== true)
|
|
1514
1602
|
continue;
|
|
1515
1603
|
if (!modeStateMatchesSkillStopContext(modeState, cwd, sessionId))
|
|
@@ -1557,16 +1645,16 @@ function isTerminalOrInactiveModeState(state) {
|
|
|
1557
1645
|
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
1558
1646
|
return phase !== "" && TERMINAL_MODE_PHASES.has(phase);
|
|
1559
1647
|
}
|
|
1560
|
-
async function readSessionScopedModeStateForRootSkill(cwd, skill, sessionIds) {
|
|
1648
|
+
async function readSessionScopedModeStateForRootSkill(cwd, stateDir, skill, sessionIds) {
|
|
1561
1649
|
for (const sessionId of sessionIds) {
|
|
1562
|
-
const state = await
|
|
1650
|
+
const state = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
|
|
1563
1651
|
if (state)
|
|
1564
1652
|
return state;
|
|
1565
1653
|
}
|
|
1566
1654
|
return null;
|
|
1567
1655
|
}
|
|
1568
|
-
async function reconcileStaleRootSkillActiveStateForStop(cwd, sessionId) {
|
|
1569
|
-
const { rootPath } =
|
|
1656
|
+
async function reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, sessionId) {
|
|
1657
|
+
const { rootPath } = getSkillActiveStatePathsForStateDir(stateDir);
|
|
1570
1658
|
const rootState = await readSkillActiveState(rootPath);
|
|
1571
1659
|
if (!rootState?.active)
|
|
1572
1660
|
return;
|
|
@@ -1593,7 +1681,7 @@ async function reconcileStaleRootSkillActiveStateForStop(cwd, sessionId) {
|
|
|
1593
1681
|
initializedSessionId,
|
|
1594
1682
|
safeString(rootState.session_id),
|
|
1595
1683
|
]);
|
|
1596
|
-
const modeState = await readSessionScopedModeStateForRootSkill(cwd, skill, candidateSessionIds);
|
|
1684
|
+
const modeState = await readSessionScopedModeStateForRootSkill(cwd, stateDir, skill, candidateSessionIds);
|
|
1597
1685
|
if (isTerminalOrInactiveModeState(modeState)) {
|
|
1598
1686
|
changed = true;
|
|
1599
1687
|
continue;
|
|
@@ -1652,17 +1740,17 @@ function buildRalplanContinuationStatus(blocker, activeSubagentCount) {
|
|
|
1652
1740
|
systemMessage: `OMX ralplan status: continue_from_artifact at phase ${phase}; continue from the current ralplan artifact and finish by stating whether ralplan is complete, paused for review, waiting for input, or still continuing.`,
|
|
1653
1741
|
};
|
|
1654
1742
|
}
|
|
1655
|
-
async function readStopAutoNudgePhase(cwd, sessionId, threadId) {
|
|
1743
|
+
async function readStopAutoNudgePhase(cwd, stateDir, sessionId, threadId) {
|
|
1656
1744
|
const normalizedSessionId = sessionId.trim();
|
|
1657
1745
|
if (normalizedSessionId) {
|
|
1658
|
-
const scopedModeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId);
|
|
1746
|
+
const scopedModeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId, stateDir);
|
|
1659
1747
|
if (scopedModeState?.active === true
|
|
1660
1748
|
&& safeString(scopedModeState.current_phase).trim().toLowerCase() === "intent-first") {
|
|
1661
1749
|
return "planning";
|
|
1662
1750
|
}
|
|
1663
1751
|
}
|
|
1664
1752
|
else {
|
|
1665
|
-
const rootModeState = await readJsonIfExists(join(
|
|
1753
|
+
const rootModeState = await readJsonIfExists(join(stateDir, "deep-interview-state.json"));
|
|
1666
1754
|
if (rootModeState?.active === true
|
|
1667
1755
|
&& safeString(rootModeState.current_phase).trim().toLowerCase() === "intent-first") {
|
|
1668
1756
|
return "planning";
|
|
@@ -1670,21 +1758,21 @@ async function readStopAutoNudgePhase(cwd, sessionId, threadId) {
|
|
|
1670
1758
|
}
|
|
1671
1759
|
if (!normalizedSessionId)
|
|
1672
1760
|
return "";
|
|
1673
|
-
const canonicalState = await
|
|
1761
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, normalizedSessionId);
|
|
1674
1762
|
const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
|
|
1675
1763
|
const deepInterview = visibleEntries.find((entry) => (entry.skill === "deep-interview"
|
|
1676
1764
|
&& matchesSkillStopContext(entry, canonicalState ?? {}, normalizedSessionId, threadId)));
|
|
1677
1765
|
if (!deepInterview)
|
|
1678
1766
|
return "";
|
|
1679
|
-
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId);
|
|
1767
|
+
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId, stateDir);
|
|
1680
1768
|
if (!modeState || modeState.active !== true)
|
|
1681
1769
|
return "";
|
|
1682
1770
|
const modePhase = safeString(modeState.current_phase).trim().toLowerCase();
|
|
1683
1771
|
return modePhase === "intent-first" ? "planning" : "";
|
|
1684
1772
|
}
|
|
1685
|
-
async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
|
|
1773
|
+
async function buildDeepInterviewQuestionStopOutput(cwd, stateDir, sessionId, threadId) {
|
|
1686
1774
|
await reconcileDeepInterviewQuestionEnforcementFromAnsweredRecords(cwd, sessionId);
|
|
1687
|
-
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId);
|
|
1775
|
+
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId, stateDir);
|
|
1688
1776
|
if (!modeState)
|
|
1689
1777
|
return null;
|
|
1690
1778
|
const questionEnforcement = safeObject(modeState.question_enforcement);
|
|
@@ -1695,7 +1783,7 @@ async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
|
|
|
1695
1783
|
if (TERMINAL_MODE_PHASES.has(phase.toLowerCase()) || phase === "completing") {
|
|
1696
1784
|
return null;
|
|
1697
1785
|
}
|
|
1698
|
-
const canonicalState = await
|
|
1786
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
1699
1787
|
if (canonicalState) {
|
|
1700
1788
|
const blocker = listActiveSkills(canonicalState).find((entry) => (entry.skill === "deep-interview"
|
|
1701
1789
|
&& matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
|
|
@@ -1836,8 +1924,8 @@ async function findCanonicalActiveTeamForSession(cwd, sessionId) {
|
|
|
1836
1924
|
}
|
|
1837
1925
|
return null;
|
|
1838
1926
|
}
|
|
1839
|
-
async function resolveActiveTeamNameForStop(cwd, sessionId) {
|
|
1840
|
-
const directState = await readTeamModeStateForStop(cwd, sessionId);
|
|
1927
|
+
async function resolveActiveTeamNameForStop(cwd, stateDir, sessionId) {
|
|
1928
|
+
const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId);
|
|
1841
1929
|
const directTeamName = safeString(directState?.team_name).trim();
|
|
1842
1930
|
if (directState?.active === true && directTeamName)
|
|
1843
1931
|
return directTeamName;
|
|
@@ -1847,11 +1935,11 @@ async function resolveActiveTeamNameForStop(cwd, sessionId) {
|
|
|
1847
1935
|
async function maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateDir, sessionId) {
|
|
1848
1936
|
if (!sessionId)
|
|
1849
1937
|
return { matched: false, output: null };
|
|
1850
|
-
const teamName = await resolveActiveTeamNameForStop(cwd, sessionId);
|
|
1938
|
+
const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId);
|
|
1851
1939
|
if (!teamName)
|
|
1852
1940
|
return { matched: false, output: null };
|
|
1853
1941
|
const explicitReleaseReadinessContext = hasReleaseReadinessMode(payload)
|
|
1854
|
-
|| await hasReleaseReadinessStopMarker(cwd, sessionId, teamName);
|
|
1942
|
+
|| await hasReleaseReadinessStopMarker(cwd, stateDir, sessionId, teamName);
|
|
1855
1943
|
if (!explicitReleaseReadinessContext) {
|
|
1856
1944
|
return { matched: false, output: null };
|
|
1857
1945
|
}
|
|
@@ -1873,8 +1961,8 @@ async function maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateD
|
|
|
1873
1961
|
}, sessionId);
|
|
1874
1962
|
return { matched: true, output };
|
|
1875
1963
|
}
|
|
1876
|
-
async function buildSkillStopOutput(cwd, sessionId, threadId) {
|
|
1877
|
-
const blocker = await readBlockingSkillForStop(cwd, sessionId, threadId);
|
|
1964
|
+
async function buildSkillStopOutput(cwd, stateDir, sessionId, threadId) {
|
|
1965
|
+
const blocker = await readBlockingSkillForStop(cwd, stateDir, sessionId, threadId);
|
|
1878
1966
|
if (!blocker)
|
|
1879
1967
|
return null;
|
|
1880
1968
|
const subagentSummary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
|
|
@@ -1983,18 +2071,33 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
1983
2071
|
const canonicalSessionId = await resolveInternalSessionIdForPayload(cwd, sessionId);
|
|
1984
2072
|
const threadId = readPayloadThreadId(payload);
|
|
1985
2073
|
if (canonicalSessionId) {
|
|
1986
|
-
await reconcileStaleRootSkillActiveStateForStop(cwd, canonicalSessionId);
|
|
2074
|
+
await reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, canonicalSessionId);
|
|
1987
2075
|
}
|
|
1988
2076
|
const execFollowupOutput = await buildExecFollowupStopOutput(cwd, canonicalSessionId);
|
|
1989
2077
|
if (execFollowupOutput)
|
|
1990
2078
|
return execFollowupOutput;
|
|
2079
|
+
const ralphOwnerContext = {
|
|
2080
|
+
payloadSessionId: sessionId,
|
|
2081
|
+
threadId,
|
|
2082
|
+
tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
|
|
2083
|
+
};
|
|
2084
|
+
const ralphCompletionAuditBlock = options.skipRalphStopBlock === true
|
|
2085
|
+
? null
|
|
2086
|
+
: await readRalphCompletionAuditBlockState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
|
|
2087
|
+
if (ralphCompletionAuditBlock) {
|
|
2088
|
+
await reopenRalphCompletionAuditBlock(ralphCompletionAuditBlock);
|
|
2089
|
+
const blockingPath = formatStopStatePath(cwd, ralphCompletionAuditBlock.path);
|
|
2090
|
+
const systemMessage = `OMX Ralph completion audit is missing required evidence (${ralphCompletionAuditBlock.reason}; state: ${blockingPath}); continue verification, record a prompt-to-artifact checklist plus verification evidence, and do not report complete yet.`;
|
|
2091
|
+
return await returnPersistentStopBlock(payload, stateDir, "ralph-completion-audit-stop", `${blockingPath}|${ralphCompletionAuditBlock.reason}`, {
|
|
2092
|
+
decision: "block",
|
|
2093
|
+
reason: systemMessage,
|
|
2094
|
+
stopReason: `ralph_completion_audit_${ralphCompletionAuditBlock.reason}`,
|
|
2095
|
+
systemMessage,
|
|
2096
|
+
}, canonicalSessionId, { allowRepeatDuringStopHook: true });
|
|
2097
|
+
}
|
|
1991
2098
|
const ralphState = options.skipRalphStopBlock === true
|
|
1992
2099
|
? null
|
|
1993
|
-
: await readActiveRalphState(stateDir, canonicalSessionId,
|
|
1994
|
-
payloadSessionId: sessionId,
|
|
1995
|
-
threadId,
|
|
1996
|
-
tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
|
|
1997
|
-
});
|
|
2100
|
+
: await readActiveRalphState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
|
|
1998
2101
|
if (!ralphState) {
|
|
1999
2102
|
const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
|
|
2000
2103
|
if (autoresearchState) {
|
|
@@ -2047,7 +2150,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2047
2150
|
return await returnPersistentStopBlock(payload, stateDir, "team-stop", safeString(teamOutput.stopReason), teamOutput, canonicalSessionId);
|
|
2048
2151
|
}
|
|
2049
2152
|
if (canonicalSessionId) {
|
|
2050
|
-
const deepInterviewQuestionOutput = await buildDeepInterviewQuestionStopOutput(cwd, canonicalSessionId, threadId);
|
|
2153
|
+
const deepInterviewQuestionOutput = await buildDeepInterviewQuestionStopOutput(cwd, stateDir, canonicalSessionId, threadId);
|
|
2051
2154
|
if (deepInterviewQuestionOutput) {
|
|
2052
2155
|
return await returnPersistentStopBlock(payload, stateDir, "deep-interview-question-stop", deepInterviewQuestionOutput.obligationId, deepInterviewQuestionOutput.output, canonicalSessionId);
|
|
2053
2156
|
}
|
|
@@ -2060,7 +2163,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2060
2163
|
if (repeatedCanonicalTeamOutput)
|
|
2061
2164
|
return repeatedCanonicalTeamOutput;
|
|
2062
2165
|
}
|
|
2063
|
-
const skillOutput = await buildSkillStopOutput(cwd, canonicalSessionId, threadId);
|
|
2166
|
+
const skillOutput = await buildSkillStopOutput(cwd, stateDir, canonicalSessionId, threadId);
|
|
2064
2167
|
if (skillOutput) {
|
|
2065
2168
|
return await returnPersistentStopBlock(payload, stateDir, "skill-stop", safeString(skillOutput.stopReason), skillOutput, canonicalSessionId);
|
|
2066
2169
|
}
|
|
@@ -2071,7 +2174,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2071
2174
|
return await returnPersistentStopBlock(payload, stateDir, "goal-workflow-reconciliation-stop", safeString(goalWorkflowStopOutput.stopReason), goalWorkflowStopOutput, canonicalSessionId, { allowRepeatDuringStopHook: true });
|
|
2072
2175
|
}
|
|
2073
2176
|
const autoNudgeConfig = await loadAutoNudgeConfig();
|
|
2074
|
-
const autoNudgePhase = await readStopAutoNudgePhase(cwd, canonicalSessionId, threadId);
|
|
2177
|
+
const autoNudgePhase = await readStopAutoNudgePhase(cwd, stateDir, canonicalSessionId, threadId);
|
|
2075
2178
|
if (autoNudgeConfig.enabled
|
|
2076
2179
|
&& detectNativeStopStallPattern(lastAssistantMessage, autoNudgeConfig.patterns, autoNudgePhase)) {
|
|
2077
2180
|
const effectiveResponse = resolveEffectiveAutoNudgeResponse(autoNudgeConfig.response);
|
|
@@ -2109,7 +2212,9 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2109
2212
|
export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
2110
2213
|
const hookEventName = readHookEventName(payload);
|
|
2111
2214
|
const cwd = options.cwd ?? (safeString(payload.cwd).trim() || process.cwd());
|
|
2112
|
-
|
|
2215
|
+
// Native hooks must use the same authoritative runtime state root as HUD/MCP
|
|
2216
|
+
// when boxed/team roots are active; do not bypass it with cwd/.omx/state.
|
|
2217
|
+
const stateDir = getBaseStateDir(cwd);
|
|
2113
2218
|
await mkdir(stateDir, { recursive: true });
|
|
2114
2219
|
const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
|
|
2115
2220
|
let skillState = null;
|
|
@@ -2179,6 +2284,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2179
2284
|
if (prompt && !isSubagentPromptSubmit) {
|
|
2180
2285
|
skillState = buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessionIdForState, threadId || undefined, turnId || undefined) ?? await recordSkillActivation({
|
|
2181
2286
|
stateDir,
|
|
2287
|
+
sourceCwd: cwd,
|
|
2182
2288
|
text: prompt,
|
|
2183
2289
|
sessionId: sessionIdForState,
|
|
2184
2290
|
threadId,
|