oh-my-codex 0.16.3 → 0.16.4
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__/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 +101 -6
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +131 -2
- package/dist/cli/__tests__/index.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 +2 -2
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +272 -26
- 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 +69 -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 +152 -17
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +9 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +135 -17
- 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/plugin-marketplace.d.ts +3 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +88 -0
- 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 +114 -44
- 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 +64 -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 +7 -0
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +70 -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 +2 -0
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +25 -3
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +11 -2
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +221 -123
- 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 +2 -2
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- 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__/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/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 +7 -5
- package/dist/hooks/keyword-detector.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__/state-paths.test.js +61 -0
- 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/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +23 -2
- 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 +57 -26
- 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 +220 -13
- 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.map +1 -1
- package/dist/scripts/codex-native-hook.js +133 -54
- 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.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/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 +124 -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 +44 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +197 -13
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/wiki/lifecycle.js +1 -1
- 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 +5 -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/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/ultragoal/SKILL.md +36 -3
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +21 -24
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
- 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/doctor/SKILL.md +2 -2
- package/skills/ecomode/SKILL.md +105 -1
- package/skills/frontend-ui-ux/SKILL.md +4 -26
- 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/swarm/SKILL.md +5 -3
- package/skills/tdd/SKILL.md +95 -1
- package/skills/ultragoal/SKILL.md +36 -3
- package/skills/ultraqa/SKILL.md +21 -24
- package/skills/ultrawork/SKILL.md +8 -8
- package/skills/web-clone/SKILL.md +348 -1
- package/skills/wiki/SKILL.md +13 -13
- package/src/scripts/__tests__/codex-native-hook.test.ts +231 -13
- package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
- package/src/scripts/codex-native-hook.ts +160 -43
- package/src/scripts/codex-native-pre-post.ts +4 -1
- package/src/scripts/notify-dispatcher.ts +40 -1
- package/src/scripts/notify-hook.ts +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify-dispatcher.test.d.ts","sourceRoot":"","sources":["../../../src/scripts/__tests__/notify-dispatcher.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
function runDispatcher(metadataPath) {
|
|
9
|
+
const dispatcherScript = join(process.cwd(), "dist", "scripts", "notify-dispatcher.js");
|
|
10
|
+
const result = spawnSync(process.execPath, [dispatcherScript, "--metadata", metadataPath, JSON.stringify({ type: "test" })], { encoding: "utf-8", windowsHide: true });
|
|
11
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
12
|
+
}
|
|
13
|
+
describe("notify dispatcher previousNotify guard", () => {
|
|
14
|
+
it("skips stale OMX-managed previousNotify dispatcher entries", () => {
|
|
15
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-stale-"));
|
|
16
|
+
try {
|
|
17
|
+
const oldPkgScripts = join(wd, "global", "oh-my-codex", "dist", "scripts");
|
|
18
|
+
mkdirSync(oldPkgScripts, { recursive: true });
|
|
19
|
+
const stalePreviousMarker = join(wd, "stale-previous-ran");
|
|
20
|
+
const omxMarker = join(wd, "omx-ran");
|
|
21
|
+
const staleDispatcher = join(oldPkgScripts, "notify-dispatcher.js");
|
|
22
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
23
|
+
writeFileSync(staleDispatcher, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(stalePreviousMarker)}, "ran");\n`);
|
|
24
|
+
writeFileSync(omxHook, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(omxMarker)}, "ran");\n`);
|
|
25
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
26
|
+
writeFileSync(metadataPath, JSON.stringify({
|
|
27
|
+
managedBy: "oh-my-codex",
|
|
28
|
+
version: 1,
|
|
29
|
+
previousNotify: [process.execPath, staleDispatcher, "--metadata", metadataPath],
|
|
30
|
+
omxNotify: [process.execPath, omxHook],
|
|
31
|
+
dispatcherNotify: [
|
|
32
|
+
process.execPath,
|
|
33
|
+
join(process.cwd(), "dist", "scripts", "notify-dispatcher.js"),
|
|
34
|
+
"--metadata",
|
|
35
|
+
metadataPath,
|
|
36
|
+
],
|
|
37
|
+
}));
|
|
38
|
+
runDispatcher(metadataPath);
|
|
39
|
+
assert.equal(existsSync(stalePreviousMarker), false);
|
|
40
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "ran");
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
rmSync(wd, { recursive: true, force: true });
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
it("skips stale OMX-managed previousNotify dispatcher entries behind node flags", () => {
|
|
47
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-flagged-stale-"));
|
|
48
|
+
try {
|
|
49
|
+
const oldPkgScripts = join(wd, "global", "oh-my-codex", "dist", "scripts");
|
|
50
|
+
mkdirSync(oldPkgScripts, { recursive: true });
|
|
51
|
+
const stalePreviousMarker = join(wd, "stale-previous-ran");
|
|
52
|
+
const omxMarker = join(wd, "omx-ran");
|
|
53
|
+
const staleDispatcher = join(oldPkgScripts, "notify-dispatcher.js");
|
|
54
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
55
|
+
writeFileSync(staleDispatcher, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(stalePreviousMarker)}, "ran");\n`);
|
|
56
|
+
writeFileSync(omxHook, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(omxMarker)}, "ran");\n`);
|
|
57
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
58
|
+
writeFileSync(metadataPath, JSON.stringify({
|
|
59
|
+
managedBy: "oh-my-codex",
|
|
60
|
+
version: 1,
|
|
61
|
+
previousNotify: [
|
|
62
|
+
process.execPath,
|
|
63
|
+
"--no-warnings",
|
|
64
|
+
staleDispatcher,
|
|
65
|
+
"--metadata",
|
|
66
|
+
metadataPath,
|
|
67
|
+
],
|
|
68
|
+
omxNotify: [process.execPath, omxHook],
|
|
69
|
+
}));
|
|
70
|
+
runDispatcher(metadataPath);
|
|
71
|
+
assert.equal(existsSync(stalePreviousMarker), false);
|
|
72
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "ran");
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
rmSync(wd, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
it("preserves and runs real user previousNotify entries", () => {
|
|
79
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-user-"));
|
|
80
|
+
try {
|
|
81
|
+
const userMarker = join(wd, "user-ran");
|
|
82
|
+
const omxMarker = join(wd, "omx-ran");
|
|
83
|
+
const userScript = join(wd, "user-notify.js");
|
|
84
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
85
|
+
writeFileSync(userScript, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(userMarker)}, "ran");\n`);
|
|
86
|
+
writeFileSync(omxHook, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(omxMarker)}, "ran");\n`);
|
|
87
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
88
|
+
writeFileSync(metadataPath, JSON.stringify({
|
|
89
|
+
managedBy: "oh-my-codex",
|
|
90
|
+
version: 1,
|
|
91
|
+
previousNotify: [process.execPath, userScript],
|
|
92
|
+
omxNotify: [process.execPath, omxHook],
|
|
93
|
+
}));
|
|
94
|
+
runDispatcher(metadataPath);
|
|
95
|
+
assert.equal(readFileSync(userMarker, "utf-8"), "ran");
|
|
96
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "ran");
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
rmSync(wd, { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
it("does not mistake real user notify arguments for managed entrypoints", () => {
|
|
103
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-user-arg-"));
|
|
104
|
+
try {
|
|
105
|
+
const userMarker = join(wd, "user-ran");
|
|
106
|
+
const userScript = join(wd, "user-notify.js");
|
|
107
|
+
writeFileSync(userScript, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(userMarker)}, process.argv.slice(2).join("\\n"));\n`);
|
|
108
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
109
|
+
writeFileSync(metadataPath, JSON.stringify({
|
|
110
|
+
managedBy: "oh-my-codex",
|
|
111
|
+
version: 1,
|
|
112
|
+
previousNotify: [
|
|
113
|
+
process.execPath,
|
|
114
|
+
userScript,
|
|
115
|
+
"/opt/homebrew/lib/node_modules/oh-my-codex/dist/scripts/notify-hook.js",
|
|
116
|
+
],
|
|
117
|
+
}));
|
|
118
|
+
runDispatcher(metadataPath);
|
|
119
|
+
assert.match(readFileSync(userMarker, "utf-8"), /notify-hook\.js/);
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
rmSync(wd, { recursive: true, force: true });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=notify-dispatcher.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify-dispatcher.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/notify-dispatcher.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AAsCA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AA4BtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AAsCA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AA4BtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AA6BlE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,MAAM,CAAC;AAEX,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,UAAU,yBAAyB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6BAA6B,CAAC,EAAE,OAAO,2BAA2B,CAAC;CACpE;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AA6PD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,kBAAkB,GAAG,IAAI,GACvC,MAAM,GAAG,IAAI,CAmBf;AA6XD,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IACP,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC,GACL,MAAM,GAAG,IAAI,CAuBf;AAwkED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CAkQnC;AAOD,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAGT;AA2ED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAuC3D"}
|
|
@@ -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
12
|
import { omxNotepadPath, omxProjectMemoryPath } 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";
|
|
@@ -381,15 +382,15 @@ async function readCanonicalTerminalRunStateForStop(cwd, sessionId, mode) {
|
|
|
381
382
|
const runRecord = runState;
|
|
382
383
|
return shouldHonorCanonicalTerminalRunState(runRecord, mode) ? runRecord : null;
|
|
383
384
|
}
|
|
384
|
-
async function isVisibleRalphActiveForSession(
|
|
385
|
-
const canonicalState = await
|
|
385
|
+
async function isVisibleRalphActiveForSession(stateDir, sessionId) {
|
|
386
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
386
387
|
if (!canonicalState)
|
|
387
388
|
return false;
|
|
388
389
|
return listActiveSkills(canonicalState).some((entry) => (entry.skill === "ralph"
|
|
389
390
|
&& matchesSkillStopContext(entry, canonicalState, sessionId, "")));
|
|
390
391
|
}
|
|
391
|
-
async function hasConsistentRalphSkillActivation(
|
|
392
|
-
const canonicalState = await
|
|
392
|
+
async function hasConsistentRalphSkillActivation(stateDir, sessionId) {
|
|
393
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
393
394
|
if (!canonicalState)
|
|
394
395
|
return true;
|
|
395
396
|
const initializedMode = safeString(canonicalState.initialized_mode).trim();
|
|
@@ -400,8 +401,63 @@ async function hasConsistentRalphSkillActivation(cwd, sessionId) {
|
|
|
400
401
|
return false;
|
|
401
402
|
return true;
|
|
402
403
|
}
|
|
403
|
-
async function
|
|
404
|
-
const
|
|
404
|
+
async function readRalphCompletionAuditBlockState(cwd, stateDir, preferredSessionId, ownerContext) {
|
|
405
|
+
const [rawSessionInfo, usableSessionInfo] = await Promise.all([
|
|
406
|
+
readSessionState(cwd),
|
|
407
|
+
readUsableSessionState(cwd),
|
|
408
|
+
]);
|
|
409
|
+
const currentOmxSessionId = safeString(usableSessionInfo?.session_id).trim();
|
|
410
|
+
const currentNativeSessionId = safeString(usableSessionInfo?.native_session_id).trim();
|
|
411
|
+
const staleCurrentSessionId = rawSessionInfo && !isSessionStateUsable(rawSessionInfo, cwd)
|
|
412
|
+
? safeString(rawSessionInfo.session_id).trim()
|
|
413
|
+
: "";
|
|
414
|
+
const sessionCandidates = [...new Set([
|
|
415
|
+
safeString(preferredSessionId).trim(),
|
|
416
|
+
currentOmxSessionId,
|
|
417
|
+
].filter(Boolean))];
|
|
418
|
+
const evaluateCandidate = (state, path, sessionId) => {
|
|
419
|
+
if (!state || state.mode && safeString(state.mode) !== "ralph")
|
|
420
|
+
return null;
|
|
421
|
+
if (!isRalphCompletePhase(state.current_phase ?? state.currentPhase))
|
|
422
|
+
return null;
|
|
423
|
+
if (activeRalphStateMatchesStopOwner(state, {
|
|
424
|
+
sessionId,
|
|
425
|
+
payloadSessionId: safeString(ownerContext?.payloadSessionId).trim(),
|
|
426
|
+
threadId: safeString(ownerContext?.threadId).trim(),
|
|
427
|
+
currentNativeSessionId,
|
|
428
|
+
tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
|
|
429
|
+
}) !== true)
|
|
430
|
+
return null;
|
|
431
|
+
const audit = evaluateRalphCompletionAuditEvidence(state, cwd);
|
|
432
|
+
return audit.complete ? null : { state, path, reason: audit.reason };
|
|
433
|
+
};
|
|
434
|
+
for (const sessionId of sessionCandidates) {
|
|
435
|
+
if (staleCurrentSessionId && sessionId === staleCurrentSessionId)
|
|
436
|
+
continue;
|
|
437
|
+
const sessionScopedPath = getStateFilePath("ralph-state.json", cwd, sessionId);
|
|
438
|
+
const result = evaluateCandidate(await readJsonIfExists(sessionScopedPath), sessionScopedPath, sessionId);
|
|
439
|
+
if (result)
|
|
440
|
+
return result;
|
|
441
|
+
}
|
|
442
|
+
if (sessionCandidates.length > 0)
|
|
443
|
+
return null;
|
|
444
|
+
const directPath = join(stateDir, "ralph-state.json");
|
|
445
|
+
return evaluateCandidate(await readJsonIfExists(directPath), directPath, "");
|
|
446
|
+
}
|
|
447
|
+
async function reopenRalphCompletionAuditBlock(block) {
|
|
448
|
+
const nowIso = new Date().toISOString();
|
|
449
|
+
const next = {
|
|
450
|
+
...block.state,
|
|
451
|
+
active: true,
|
|
452
|
+
current_phase: "verifying",
|
|
453
|
+
completion_audit_gate: "blocked",
|
|
454
|
+
completion_audit_missing_reason: block.reason,
|
|
455
|
+
completion_audit_blocked_at: nowIso,
|
|
456
|
+
};
|
|
457
|
+
delete next.completed_at;
|
|
458
|
+
await writeFile(block.path, JSON.stringify(next, null, 2));
|
|
459
|
+
}
|
|
460
|
+
async function readActiveRalphState(cwd, stateDir, preferredSessionId, ownerContext) {
|
|
405
461
|
const [rawSessionInfo, usableSessionInfo] = await Promise.all([
|
|
406
462
|
readSessionState(cwd),
|
|
407
463
|
readUsableSessionState(cwd),
|
|
@@ -429,7 +485,7 @@ async function readActiveRalphState(stateDir, preferredSessionId, ownerContext)
|
|
|
429
485
|
const sessionScoped = await readJsonIfExists(sessionScopedPath);
|
|
430
486
|
if (sessionScoped?.active === true
|
|
431
487
|
&& isRalphStartingPhase(sessionScoped)
|
|
432
|
-
&& !(await isVisibleRalphActiveForSession(
|
|
488
|
+
&& !(await isVisibleRalphActiveForSession(stateDir, sessionId))) {
|
|
433
489
|
continue;
|
|
434
490
|
}
|
|
435
491
|
if (sessionScoped?.active === true
|
|
@@ -441,7 +497,7 @@ async function readActiveRalphState(stateDir, preferredSessionId, ownerContext)
|
|
|
441
497
|
currentNativeSessionId,
|
|
442
498
|
tmuxPaneId: safeString(ownerContext?.tmuxPaneId).trim(),
|
|
443
499
|
})
|
|
444
|
-
&& await hasConsistentRalphSkillActivation(
|
|
500
|
+
&& await hasConsistentRalphSkillActivation(stateDir, sessionId)) {
|
|
445
501
|
return { state: sessionScoped, path: sessionScopedPath };
|
|
446
502
|
}
|
|
447
503
|
}
|
|
@@ -1030,6 +1086,9 @@ function buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessio
|
|
|
1030
1086
|
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
1087
|
};
|
|
1032
1088
|
}
|
|
1089
|
+
function buildSkillStateCliInstruction(mode, statePath) {
|
|
1090
|
+
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.`;
|
|
1091
|
+
}
|
|
1033
1092
|
function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(), payload) {
|
|
1034
1093
|
if (!prompt)
|
|
1035
1094
|
return null;
|
|
@@ -1089,7 +1148,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1089
1148
|
promptPriorityMessage,
|
|
1090
1149
|
ultragoalPromptActivationNote,
|
|
1091
1150
|
skillState.initialized_mode && skillState.initialized_state_path
|
|
1092
|
-
?
|
|
1151
|
+
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
1093
1152
|
: null,
|
|
1094
1153
|
teamDetected
|
|
1095
1154
|
? buildTeamRuntimeInstruction(cwd, payload)
|
|
@@ -1100,7 +1159,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1100
1159
|
}
|
|
1101
1160
|
if (teamDetected) {
|
|
1102
1161
|
const initializedStateMessage = skillState?.initialized_mode && skillState.initialized_state_path
|
|
1103
|
-
?
|
|
1162
|
+
? buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path)
|
|
1104
1163
|
: null;
|
|
1105
1164
|
return [
|
|
1106
1165
|
detectedKeywordMessage,
|
|
@@ -1126,7 +1185,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
|
|
|
1126
1185
|
? `planning preserved over simultaneous execution follow-up; deferred skills: ${deferredSkills.join(", ")}.`
|
|
1127
1186
|
: null,
|
|
1128
1187
|
promptPriorityMessage,
|
|
1129
|
-
|
|
1188
|
+
buildSkillStateCliInstruction(skillState.initialized_mode, skillState.initialized_state_path),
|
|
1130
1189
|
deepInterviewPromptActivationNote,
|
|
1131
1190
|
ultraworkPromptActivationNote,
|
|
1132
1191
|
ultragoalPromptActivationNote,
|
|
@@ -1164,7 +1223,7 @@ async function resolveTeamWorkerStopDecision(cwd) {
|
|
|
1164
1223
|
|| parseTeamWorkerEnv(safeString(process.env.OMX_TEAM_WORKER));
|
|
1165
1224
|
if (!workerContext)
|
|
1166
1225
|
return { kind: "unresolved", reason: "missing_worker_context" };
|
|
1167
|
-
const blockWorkerStop = (reasonCode, detail, stateDirForDecision =
|
|
1226
|
+
const blockWorkerStop = (reasonCode, detail, stateDirForDecision = getBaseStateDir(cwd)) => ({
|
|
1168
1227
|
kind: "blocked",
|
|
1169
1228
|
stateDir: stateDirForDecision,
|
|
1170
1229
|
workerContext,
|
|
@@ -1354,15 +1413,15 @@ async function buildGoalWorkflowReconciliationStopOutput(payload, cwd) {
|
|
|
1354
1413
|
systemMessage,
|
|
1355
1414
|
};
|
|
1356
1415
|
}
|
|
1357
|
-
async function readTeamModeStateForStop(cwd, sessionId) {
|
|
1416
|
+
async function readTeamModeStateForStop(cwd, stateDir, sessionId) {
|
|
1358
1417
|
const normalizedSessionId = safeString(sessionId).trim();
|
|
1359
1418
|
if (!normalizedSessionId) {
|
|
1360
1419
|
return await readModeState("team", cwd);
|
|
1361
1420
|
}
|
|
1362
|
-
const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId);
|
|
1421
|
+
const scopedState = await readStopSessionPinnedState("team-state.json", cwd, normalizedSessionId, stateDir);
|
|
1363
1422
|
if (scopedState)
|
|
1364
1423
|
return scopedState;
|
|
1365
|
-
const rootState = await readJsonIfExists(join(
|
|
1424
|
+
const rootState = await readJsonIfExists(join(stateDir, "team-state.json"));
|
|
1366
1425
|
if (rootState?.active !== true)
|
|
1367
1426
|
return null;
|
|
1368
1427
|
const ownerSessionId = safeString(rootState.session_id).trim();
|
|
@@ -1375,7 +1434,7 @@ async function buildTeamStopOutput(cwd, sessionId) {
|
|
|
1375
1434
|
if (await readCanonicalTerminalRunStateForStop(cwd, sessionId, "team")) {
|
|
1376
1435
|
return null;
|
|
1377
1436
|
}
|
|
1378
|
-
const teamState = await readTeamModeStateForStop(cwd, sessionId);
|
|
1437
|
+
const teamState = await readTeamModeStateForStop(cwd, getBaseStateDir(cwd), sessionId);
|
|
1379
1438
|
if (teamState?.active !== true)
|
|
1380
1439
|
return null;
|
|
1381
1440
|
const teamName = safeString(teamState.team_name).trim();
|
|
@@ -1425,10 +1484,10 @@ function hasReleaseReadinessMode(payload) {
|
|
|
1425
1484
|
const mode = safeString(payload.mode).trim().toLowerCase();
|
|
1426
1485
|
return mode === "release-readiness";
|
|
1427
1486
|
}
|
|
1428
|
-
async function hasReleaseReadinessStopMarker(cwd, sessionId, teamName) {
|
|
1487
|
+
async function hasReleaseReadinessStopMarker(cwd, stateDir, sessionId, teamName) {
|
|
1429
1488
|
if (!sessionId)
|
|
1430
1489
|
return false;
|
|
1431
|
-
const markerState = await readStopSessionPinnedState("release-readiness-state.json", cwd, sessionId);
|
|
1490
|
+
const markerState = await readStopSessionPinnedState("release-readiness-state.json", cwd, sessionId, stateDir);
|
|
1432
1491
|
if (markerState?.active !== true || markerState.stable_final_recommendation_emitted !== true) {
|
|
1433
1492
|
return false;
|
|
1434
1493
|
}
|
|
@@ -1463,8 +1522,10 @@ async function resolveInternalSessionIdForPayload(cwd, payloadSessionId) {
|
|
|
1463
1522
|
return canonicalSessionId;
|
|
1464
1523
|
return payloadSessionId;
|
|
1465
1524
|
}
|
|
1466
|
-
async function readStopSessionPinnedState(fileName, cwd, sessionId) {
|
|
1467
|
-
const statePath =
|
|
1525
|
+
async function readStopSessionPinnedState(fileName, cwd, sessionId, stateDir) {
|
|
1526
|
+
const statePath = stateDir && sessionId
|
|
1527
|
+
? join(stateDir, "sessions", sessionId, fileName)
|
|
1528
|
+
: getStateFilePath(fileName, cwd, sessionId || undefined);
|
|
1468
1529
|
return readJsonIfExists(statePath);
|
|
1469
1530
|
}
|
|
1470
1531
|
function matchesSkillStopContext(entry, state, sessionId, threadId) {
|
|
@@ -1499,8 +1560,8 @@ function modeStateMatchesSkillStopContext(state, cwd, sessionId) {
|
|
|
1499
1560
|
}
|
|
1500
1561
|
return true;
|
|
1501
1562
|
}
|
|
1502
|
-
async function readBlockingSkillForStop(cwd, sessionId, threadId, requiredSkill) {
|
|
1503
|
-
const canonicalState = await
|
|
1563
|
+
async function readBlockingSkillForStop(cwd, stateDir, sessionId, threadId, requiredSkill) {
|
|
1564
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
1504
1565
|
const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
|
|
1505
1566
|
const candidateSkills = requiredSkill
|
|
1506
1567
|
? [requiredSkill]
|
|
@@ -1509,7 +1570,7 @@ async function readBlockingSkillForStop(cwd, sessionId, threadId, requiredSkill)
|
|
|
1509
1570
|
const terminalRunState = await readCanonicalTerminalRunStateForStop(cwd, sessionId, skill);
|
|
1510
1571
|
if (terminalRunState)
|
|
1511
1572
|
continue;
|
|
1512
|
-
const modeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId);
|
|
1573
|
+
const modeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
|
|
1513
1574
|
if (!modeState || modeState.active !== true)
|
|
1514
1575
|
continue;
|
|
1515
1576
|
if (!modeStateMatchesSkillStopContext(modeState, cwd, sessionId))
|
|
@@ -1557,16 +1618,16 @@ function isTerminalOrInactiveModeState(state) {
|
|
|
1557
1618
|
const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
|
|
1558
1619
|
return phase !== "" && TERMINAL_MODE_PHASES.has(phase);
|
|
1559
1620
|
}
|
|
1560
|
-
async function readSessionScopedModeStateForRootSkill(cwd, skill, sessionIds) {
|
|
1621
|
+
async function readSessionScopedModeStateForRootSkill(cwd, stateDir, skill, sessionIds) {
|
|
1561
1622
|
for (const sessionId of sessionIds) {
|
|
1562
|
-
const state = await
|
|
1623
|
+
const state = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
|
|
1563
1624
|
if (state)
|
|
1564
1625
|
return state;
|
|
1565
1626
|
}
|
|
1566
1627
|
return null;
|
|
1567
1628
|
}
|
|
1568
|
-
async function reconcileStaleRootSkillActiveStateForStop(cwd, sessionId) {
|
|
1569
|
-
const { rootPath } =
|
|
1629
|
+
async function reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, sessionId) {
|
|
1630
|
+
const { rootPath } = getSkillActiveStatePathsForStateDir(stateDir);
|
|
1570
1631
|
const rootState = await readSkillActiveState(rootPath);
|
|
1571
1632
|
if (!rootState?.active)
|
|
1572
1633
|
return;
|
|
@@ -1593,7 +1654,7 @@ async function reconcileStaleRootSkillActiveStateForStop(cwd, sessionId) {
|
|
|
1593
1654
|
initializedSessionId,
|
|
1594
1655
|
safeString(rootState.session_id),
|
|
1595
1656
|
]);
|
|
1596
|
-
const modeState = await readSessionScopedModeStateForRootSkill(cwd, skill, candidateSessionIds);
|
|
1657
|
+
const modeState = await readSessionScopedModeStateForRootSkill(cwd, stateDir, skill, candidateSessionIds);
|
|
1597
1658
|
if (isTerminalOrInactiveModeState(modeState)) {
|
|
1598
1659
|
changed = true;
|
|
1599
1660
|
continue;
|
|
@@ -1652,17 +1713,17 @@ function buildRalplanContinuationStatus(blocker, activeSubagentCount) {
|
|
|
1652
1713
|
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
1714
|
};
|
|
1654
1715
|
}
|
|
1655
|
-
async function readStopAutoNudgePhase(cwd, sessionId, threadId) {
|
|
1716
|
+
async function readStopAutoNudgePhase(cwd, stateDir, sessionId, threadId) {
|
|
1656
1717
|
const normalizedSessionId = sessionId.trim();
|
|
1657
1718
|
if (normalizedSessionId) {
|
|
1658
|
-
const scopedModeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId);
|
|
1719
|
+
const scopedModeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId, stateDir);
|
|
1659
1720
|
if (scopedModeState?.active === true
|
|
1660
1721
|
&& safeString(scopedModeState.current_phase).trim().toLowerCase() === "intent-first") {
|
|
1661
1722
|
return "planning";
|
|
1662
1723
|
}
|
|
1663
1724
|
}
|
|
1664
1725
|
else {
|
|
1665
|
-
const rootModeState = await readJsonIfExists(join(
|
|
1726
|
+
const rootModeState = await readJsonIfExists(join(stateDir, "deep-interview-state.json"));
|
|
1666
1727
|
if (rootModeState?.active === true
|
|
1667
1728
|
&& safeString(rootModeState.current_phase).trim().toLowerCase() === "intent-first") {
|
|
1668
1729
|
return "planning";
|
|
@@ -1670,21 +1731,21 @@ async function readStopAutoNudgePhase(cwd, sessionId, threadId) {
|
|
|
1670
1731
|
}
|
|
1671
1732
|
if (!normalizedSessionId)
|
|
1672
1733
|
return "";
|
|
1673
|
-
const canonicalState = await
|
|
1734
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, normalizedSessionId);
|
|
1674
1735
|
const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
|
|
1675
1736
|
const deepInterview = visibleEntries.find((entry) => (entry.skill === "deep-interview"
|
|
1676
1737
|
&& matchesSkillStopContext(entry, canonicalState ?? {}, normalizedSessionId, threadId)));
|
|
1677
1738
|
if (!deepInterview)
|
|
1678
1739
|
return "";
|
|
1679
|
-
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId);
|
|
1740
|
+
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, normalizedSessionId, stateDir);
|
|
1680
1741
|
if (!modeState || modeState.active !== true)
|
|
1681
1742
|
return "";
|
|
1682
1743
|
const modePhase = safeString(modeState.current_phase).trim().toLowerCase();
|
|
1683
1744
|
return modePhase === "intent-first" ? "planning" : "";
|
|
1684
1745
|
}
|
|
1685
|
-
async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
|
|
1746
|
+
async function buildDeepInterviewQuestionStopOutput(cwd, stateDir, sessionId, threadId) {
|
|
1686
1747
|
await reconcileDeepInterviewQuestionEnforcementFromAnsweredRecords(cwd, sessionId);
|
|
1687
|
-
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId);
|
|
1748
|
+
const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId, stateDir);
|
|
1688
1749
|
if (!modeState)
|
|
1689
1750
|
return null;
|
|
1690
1751
|
const questionEnforcement = safeObject(modeState.question_enforcement);
|
|
@@ -1695,7 +1756,7 @@ async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
|
|
|
1695
1756
|
if (TERMINAL_MODE_PHASES.has(phase.toLowerCase()) || phase === "completing") {
|
|
1696
1757
|
return null;
|
|
1697
1758
|
}
|
|
1698
|
-
const canonicalState = await
|
|
1759
|
+
const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
|
|
1699
1760
|
if (canonicalState) {
|
|
1700
1761
|
const blocker = listActiveSkills(canonicalState).find((entry) => (entry.skill === "deep-interview"
|
|
1701
1762
|
&& matchesSkillStopContext(entry, canonicalState, sessionId, threadId)));
|
|
@@ -1836,8 +1897,8 @@ async function findCanonicalActiveTeamForSession(cwd, sessionId) {
|
|
|
1836
1897
|
}
|
|
1837
1898
|
return null;
|
|
1838
1899
|
}
|
|
1839
|
-
async function resolveActiveTeamNameForStop(cwd, sessionId) {
|
|
1840
|
-
const directState = await readTeamModeStateForStop(cwd, sessionId);
|
|
1900
|
+
async function resolveActiveTeamNameForStop(cwd, stateDir, sessionId) {
|
|
1901
|
+
const directState = await readTeamModeStateForStop(cwd, stateDir, sessionId);
|
|
1841
1902
|
const directTeamName = safeString(directState?.team_name).trim();
|
|
1842
1903
|
if (directState?.active === true && directTeamName)
|
|
1843
1904
|
return directTeamName;
|
|
@@ -1847,11 +1908,11 @@ async function resolveActiveTeamNameForStop(cwd, sessionId) {
|
|
|
1847
1908
|
async function maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateDir, sessionId) {
|
|
1848
1909
|
if (!sessionId)
|
|
1849
1910
|
return { matched: false, output: null };
|
|
1850
|
-
const teamName = await resolveActiveTeamNameForStop(cwd, sessionId);
|
|
1911
|
+
const teamName = await resolveActiveTeamNameForStop(cwd, stateDir, sessionId);
|
|
1851
1912
|
if (!teamName)
|
|
1852
1913
|
return { matched: false, output: null };
|
|
1853
1914
|
const explicitReleaseReadinessContext = hasReleaseReadinessMode(payload)
|
|
1854
|
-
|| await hasReleaseReadinessStopMarker(cwd, sessionId, teamName);
|
|
1915
|
+
|| await hasReleaseReadinessStopMarker(cwd, stateDir, sessionId, teamName);
|
|
1855
1916
|
if (!explicitReleaseReadinessContext) {
|
|
1856
1917
|
return { matched: false, output: null };
|
|
1857
1918
|
}
|
|
@@ -1873,8 +1934,8 @@ async function maybeBuildReleaseReadinessFinalizeStopOutput(payload, cwd, stateD
|
|
|
1873
1934
|
}, sessionId);
|
|
1874
1935
|
return { matched: true, output };
|
|
1875
1936
|
}
|
|
1876
|
-
async function buildSkillStopOutput(cwd, sessionId, threadId) {
|
|
1877
|
-
const blocker = await readBlockingSkillForStop(cwd, sessionId, threadId);
|
|
1937
|
+
async function buildSkillStopOutput(cwd, stateDir, sessionId, threadId) {
|
|
1938
|
+
const blocker = await readBlockingSkillForStop(cwd, stateDir, sessionId, threadId);
|
|
1878
1939
|
if (!blocker)
|
|
1879
1940
|
return null;
|
|
1880
1941
|
const subagentSummary = await readSubagentSessionSummary(cwd, sessionId).catch(() => null);
|
|
@@ -1983,18 +2044,33 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
1983
2044
|
const canonicalSessionId = await resolveInternalSessionIdForPayload(cwd, sessionId);
|
|
1984
2045
|
const threadId = readPayloadThreadId(payload);
|
|
1985
2046
|
if (canonicalSessionId) {
|
|
1986
|
-
await reconcileStaleRootSkillActiveStateForStop(cwd, canonicalSessionId);
|
|
2047
|
+
await reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, canonicalSessionId);
|
|
1987
2048
|
}
|
|
1988
2049
|
const execFollowupOutput = await buildExecFollowupStopOutput(cwd, canonicalSessionId);
|
|
1989
2050
|
if (execFollowupOutput)
|
|
1990
2051
|
return execFollowupOutput;
|
|
2052
|
+
const ralphOwnerContext = {
|
|
2053
|
+
payloadSessionId: sessionId,
|
|
2054
|
+
threadId,
|
|
2055
|
+
tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
|
|
2056
|
+
};
|
|
2057
|
+
const ralphCompletionAuditBlock = options.skipRalphStopBlock === true
|
|
2058
|
+
? null
|
|
2059
|
+
: await readRalphCompletionAuditBlockState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
|
|
2060
|
+
if (ralphCompletionAuditBlock) {
|
|
2061
|
+
await reopenRalphCompletionAuditBlock(ralphCompletionAuditBlock);
|
|
2062
|
+
const blockingPath = formatStopStatePath(cwd, ralphCompletionAuditBlock.path);
|
|
2063
|
+
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.`;
|
|
2064
|
+
return await returnPersistentStopBlock(payload, stateDir, "ralph-completion-audit-stop", `${blockingPath}|${ralphCompletionAuditBlock.reason}`, {
|
|
2065
|
+
decision: "block",
|
|
2066
|
+
reason: systemMessage,
|
|
2067
|
+
stopReason: `ralph_completion_audit_${ralphCompletionAuditBlock.reason}`,
|
|
2068
|
+
systemMessage,
|
|
2069
|
+
}, canonicalSessionId, { allowRepeatDuringStopHook: true });
|
|
2070
|
+
}
|
|
1991
2071
|
const ralphState = options.skipRalphStopBlock === true
|
|
1992
2072
|
? null
|
|
1993
|
-
: await readActiveRalphState(stateDir, canonicalSessionId,
|
|
1994
|
-
payloadSessionId: sessionId,
|
|
1995
|
-
threadId,
|
|
1996
|
-
tmuxPaneId: safeString(process.env.TMUX_PANE).trim(),
|
|
1997
|
-
});
|
|
2073
|
+
: await readActiveRalphState(cwd, stateDir, canonicalSessionId, ralphOwnerContext);
|
|
1998
2074
|
if (!ralphState) {
|
|
1999
2075
|
const autoresearchState = await readActiveAutoresearchState(cwd, canonicalSessionId);
|
|
2000
2076
|
if (autoresearchState) {
|
|
@@ -2047,7 +2123,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2047
2123
|
return await returnPersistentStopBlock(payload, stateDir, "team-stop", safeString(teamOutput.stopReason), teamOutput, canonicalSessionId);
|
|
2048
2124
|
}
|
|
2049
2125
|
if (canonicalSessionId) {
|
|
2050
|
-
const deepInterviewQuestionOutput = await buildDeepInterviewQuestionStopOutput(cwd, canonicalSessionId, threadId);
|
|
2126
|
+
const deepInterviewQuestionOutput = await buildDeepInterviewQuestionStopOutput(cwd, stateDir, canonicalSessionId, threadId);
|
|
2051
2127
|
if (deepInterviewQuestionOutput) {
|
|
2052
2128
|
return await returnPersistentStopBlock(payload, stateDir, "deep-interview-question-stop", deepInterviewQuestionOutput.obligationId, deepInterviewQuestionOutput.output, canonicalSessionId);
|
|
2053
2129
|
}
|
|
@@ -2060,7 +2136,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2060
2136
|
if (repeatedCanonicalTeamOutput)
|
|
2061
2137
|
return repeatedCanonicalTeamOutput;
|
|
2062
2138
|
}
|
|
2063
|
-
const skillOutput = await buildSkillStopOutput(cwd, canonicalSessionId, threadId);
|
|
2139
|
+
const skillOutput = await buildSkillStopOutput(cwd, stateDir, canonicalSessionId, threadId);
|
|
2064
2140
|
if (skillOutput) {
|
|
2065
2141
|
return await returnPersistentStopBlock(payload, stateDir, "skill-stop", safeString(skillOutput.stopReason), skillOutput, canonicalSessionId);
|
|
2066
2142
|
}
|
|
@@ -2071,7 +2147,7 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2071
2147
|
return await returnPersistentStopBlock(payload, stateDir, "goal-workflow-reconciliation-stop", safeString(goalWorkflowStopOutput.stopReason), goalWorkflowStopOutput, canonicalSessionId, { allowRepeatDuringStopHook: true });
|
|
2072
2148
|
}
|
|
2073
2149
|
const autoNudgeConfig = await loadAutoNudgeConfig();
|
|
2074
|
-
const autoNudgePhase = await readStopAutoNudgePhase(cwd, canonicalSessionId, threadId);
|
|
2150
|
+
const autoNudgePhase = await readStopAutoNudgePhase(cwd, stateDir, canonicalSessionId, threadId);
|
|
2075
2151
|
if (autoNudgeConfig.enabled
|
|
2076
2152
|
&& detectNativeStopStallPattern(lastAssistantMessage, autoNudgeConfig.patterns, autoNudgePhase)) {
|
|
2077
2153
|
const effectiveResponse = resolveEffectiveAutoNudgeResponse(autoNudgeConfig.response);
|
|
@@ -2109,7 +2185,9 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
|
|
|
2109
2185
|
export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
2110
2186
|
const hookEventName = readHookEventName(payload);
|
|
2111
2187
|
const cwd = options.cwd ?? (safeString(payload.cwd).trim() || process.cwd());
|
|
2112
|
-
|
|
2188
|
+
// Native hooks must use the same authoritative runtime state root as HUD/MCP
|
|
2189
|
+
// when boxed/team roots are active; do not bypass it with cwd/.omx/state.
|
|
2190
|
+
const stateDir = getBaseStateDir(cwd);
|
|
2113
2191
|
await mkdir(stateDir, { recursive: true });
|
|
2114
2192
|
const omxEventName = mapCodexHookEventToOmxEvent(hookEventName);
|
|
2115
2193
|
let skillState = null;
|
|
@@ -2179,6 +2257,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
|
|
|
2179
2257
|
if (prompt && !isSubagentPromptSubmit) {
|
|
2180
2258
|
skillState = buildNativeOutsideTmuxTeamPromptBlockState(prompt, cwd, payload, sessionIdForState, threadId || undefined, turnId || undefined) ?? await recordSkillActivation({
|
|
2181
2259
|
stateDir,
|
|
2260
|
+
sourceCwd: cwd,
|
|
2182
2261
|
text: prompt,
|
|
2183
2262
|
sessionId: sessionIdForState,
|
|
2184
2263
|
threadId,
|