oh-my-codex 0.14.0 → 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +14 -8
  4. package/crates/omx-explore/src/main.rs +94 -1
  5. package/crates/omx-sparkshell/src/codex_bridge.rs +59 -12
  6. package/crates/omx-sparkshell/tests/execution.rs +48 -0
  7. package/dist/cli/__tests__/explore.test.js +33 -1
  8. package/dist/cli/__tests__/explore.test.js.map +1 -1
  9. package/dist/cli/__tests__/index.test.js +11 -2
  10. package/dist/cli/__tests__/index.test.js.map +1 -1
  11. package/dist/cli/__tests__/package-bin-contract.test.js +5 -0
  12. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  13. package/dist/cli/__tests__/question.test.js +139 -25
  14. package/dist/cli/__tests__/question.test.js.map +1 -1
  15. package/dist/cli/__tests__/session-scoped-runtime.test.js +30 -0
  16. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  17. package/dist/cli/__tests__/setup-agents-overwrite.test.js +32 -7
  18. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  19. package/dist/cli/__tests__/setup-refresh.test.js +8 -6
  20. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  21. package/dist/cli/__tests__/sparkshell-cli.test.js +23 -0
  22. package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
  23. package/dist/cli/__tests__/uninstall.test.js +65 -5
  24. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  25. package/dist/cli/__tests__/update.test.js +360 -26
  26. package/dist/cli/__tests__/update.test.js.map +1 -1
  27. package/dist/cli/explore.d.ts.map +1 -1
  28. package/dist/cli/explore.js +18 -3
  29. package/dist/cli/explore.js.map +1 -1
  30. package/dist/cli/index.d.ts +2 -1
  31. package/dist/cli/index.d.ts.map +1 -1
  32. package/dist/cli/index.js +7 -2
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/setup.d.ts.map +1 -1
  35. package/dist/cli/setup.js +25 -3
  36. package/dist/cli/setup.js.map +1 -1
  37. package/dist/cli/sparkshell.d.ts.map +1 -1
  38. package/dist/cli/sparkshell.js +11 -1
  39. package/dist/cli/sparkshell.js.map +1 -1
  40. package/dist/cli/team.d.ts.map +1 -1
  41. package/dist/cli/team.js +159 -394
  42. package/dist/cli/team.js.map +1 -1
  43. package/dist/cli/uninstall.d.ts.map +1 -1
  44. package/dist/cli/uninstall.js +3 -1
  45. package/dist/cli/uninstall.js.map +1 -1
  46. package/dist/cli/update.d.ts +37 -9
  47. package/dist/cli/update.d.ts.map +1 -1
  48. package/dist/cli/update.js +204 -26
  49. package/dist/cli/update.js.map +1 -1
  50. package/dist/config/__tests__/generator-idempotent.test.js +51 -14
  51. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  52. package/dist/config/__tests__/generator-notify.test.js +35 -10
  53. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  54. package/dist/config/generator.d.ts +1 -0
  55. package/dist/config/generator.d.ts.map +1 -1
  56. package/dist/config/generator.js +61 -7
  57. package/dist/config/generator.js.map +1 -1
  58. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts +2 -0
  59. package/dist/hooks/__tests__/code-review-skill-contract.test.d.ts.map +1 -0
  60. package/dist/hooks/__tests__/code-review-skill-contract.test.js +56 -0
  61. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -0
  62. package/dist/hooks/__tests__/deep-interview-contract.test.js +31 -0
  63. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  64. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts +2 -0
  65. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.d.ts.map +1 -0
  66. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js +43 -0
  67. package/dist/hooks/__tests__/explicit-terminal-stop-docs-contract.test.js.map +1 -0
  68. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts +2 -0
  69. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.d.ts.map +1 -0
  70. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js +38 -0
  71. package/dist/hooks/__tests__/explicit-terminal-stop-model-docs-contract.test.js.map +1 -0
  72. package/dist/hooks/__tests__/keyword-detector.test.js +108 -0
  73. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  74. package/dist/hooks/__tests__/prompt-guidance-test-helpers.d.ts.map +1 -1
  75. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js +16 -1
  76. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
  77. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  78. package/dist/hooks/keyword-detector.js +34 -8
  79. package/dist/hooks/keyword-detector.js.map +1 -1
  80. package/dist/mcp/__tests__/bootstrap.test.js +7 -25
  81. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  82. package/dist/mcp/__tests__/server-lifecycle.test.js +60 -0
  83. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
  84. package/dist/mcp/__tests__/state-server.test.js +177 -0
  85. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  86. package/dist/mcp/bootstrap.d.ts.map +1 -1
  87. package/dist/mcp/bootstrap.js +36 -18
  88. package/dist/mcp/bootstrap.js.map +1 -1
  89. package/dist/mcp/state-server.d.ts +17 -0
  90. package/dist/mcp/state-server.d.ts.map +1 -1
  91. package/dist/mcp/state-server.js +55 -1
  92. package/dist/mcp/state-server.js.map +1 -1
  93. package/dist/notifications/__tests__/index.test.js +0 -3
  94. package/dist/notifications/__tests__/index.test.js.map +1 -1
  95. package/dist/notifications/__tests__/session-status.test.js +90 -0
  96. package/dist/notifications/__tests__/session-status.test.js.map +1 -1
  97. package/dist/notifications/session-status.d.ts +2 -0
  98. package/dist/notifications/session-status.d.ts.map +1 -1
  99. package/dist/notifications/session-status.js +19 -4
  100. package/dist/notifications/session-status.js.map +1 -1
  101. package/dist/question/__tests__/deep-interview.test.js +44 -0
  102. package/dist/question/__tests__/deep-interview.test.js.map +1 -1
  103. package/dist/question/__tests__/renderer.test.js +192 -12
  104. package/dist/question/__tests__/renderer.test.js.map +1 -1
  105. package/dist/question/__tests__/state.test.js +21 -1
  106. package/dist/question/__tests__/state.test.js.map +1 -1
  107. package/dist/question/deep-interview.d.ts +3 -0
  108. package/dist/question/deep-interview.d.ts.map +1 -1
  109. package/dist/question/deep-interview.js +18 -1
  110. package/dist/question/deep-interview.js.map +1 -1
  111. package/dist/question/renderer.d.ts +4 -2
  112. package/dist/question/renderer.d.ts.map +1 -1
  113. package/dist/question/renderer.js +87 -18
  114. package/dist/question/renderer.js.map +1 -1
  115. package/dist/runtime/__tests__/run-outcome.test.js +38 -0
  116. package/dist/runtime/__tests__/run-outcome.test.js.map +1 -1
  117. package/dist/runtime/__tests__/run-state.test.d.ts +2 -0
  118. package/dist/runtime/__tests__/run-state.test.d.ts.map +1 -0
  119. package/dist/runtime/__tests__/run-state.test.js +37 -0
  120. package/dist/runtime/__tests__/run-state.test.js.map +1 -0
  121. package/dist/runtime/run-loop.d.ts +5 -1
  122. package/dist/runtime/run-loop.d.ts.map +1 -1
  123. package/dist/runtime/run-loop.js +8 -3
  124. package/dist/runtime/run-loop.js.map +1 -1
  125. package/dist/runtime/run-outcome.d.ts +18 -0
  126. package/dist/runtime/run-outcome.d.ts.map +1 -1
  127. package/dist/runtime/run-outcome.js +156 -7
  128. package/dist/runtime/run-outcome.js.map +1 -1
  129. package/dist/runtime/run-state.d.ts +5 -1
  130. package/dist/runtime/run-state.d.ts.map +1 -1
  131. package/dist/runtime/run-state.js +13 -3
  132. package/dist/runtime/run-state.js.map +1 -1
  133. package/dist/runtime/terminal-lifecycle.d.ts +11 -0
  134. package/dist/runtime/terminal-lifecycle.d.ts.map +1 -0
  135. package/dist/runtime/terminal-lifecycle.js +52 -0
  136. package/dist/runtime/terminal-lifecycle.js.map +1 -0
  137. package/dist/scripts/__tests__/codex-native-hook.test.js +370 -56
  138. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  139. package/dist/scripts/__tests__/postinstall.test.d.ts +2 -0
  140. package/dist/scripts/__tests__/postinstall.test.d.ts.map +1 -0
  141. package/dist/scripts/__tests__/postinstall.test.js +178 -0
  142. package/dist/scripts/__tests__/postinstall.test.js.map +1 -0
  143. package/dist/scripts/codex-native-hook.d.ts +1 -0
  144. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  145. package/dist/scripts/codex-native-hook.js +115 -56
  146. package/dist/scripts/codex-native-hook.js.map +1 -1
  147. package/dist/scripts/postinstall.d.ts +22 -0
  148. package/dist/scripts/postinstall.d.ts.map +1 -0
  149. package/dist/scripts/postinstall.js +105 -0
  150. package/dist/scripts/postinstall.js.map +1 -0
  151. package/dist/state/__tests__/operations.test.js +60 -0
  152. package/dist/state/__tests__/operations.test.js.map +1 -1
  153. package/dist/state/operations.d.ts.map +1 -1
  154. package/dist/state/operations.js +18 -1
  155. package/dist/state/operations.js.map +1 -1
  156. package/dist/team/__tests__/role-router.test.js +6 -0
  157. package/dist/team/__tests__/role-router.test.js.map +1 -1
  158. package/dist/team/__tests__/runtime.test.js +108 -2
  159. package/dist/team/__tests__/runtime.test.js.map +1 -1
  160. package/dist/team/runtime.d.ts.map +1 -1
  161. package/dist/team/runtime.js +18 -4
  162. package/dist/team/runtime.js.map +1 -1
  163. package/dist/utils/__tests__/dep-versions.test.js +25 -8
  164. package/dist/utils/__tests__/dep-versions.test.js.map +1 -1
  165. package/dist/utils/__tests__/paths.test.js +45 -0
  166. package/dist/utils/__tests__/paths.test.js.map +1 -1
  167. package/dist/utils/paths.d.ts +2 -0
  168. package/dist/utils/paths.d.ts.map +1 -1
  169. package/dist/utils/paths.js +22 -7
  170. package/dist/utils/paths.js.map +1 -1
  171. package/dist/verification/__tests__/ci-rust-gates.test.js +1 -1
  172. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  173. package/package.json +3 -2
  174. package/prompts/architect.md +4 -0
  175. package/prompts/code-reviewer.md +3 -0
  176. package/skills/code-review/SKILL.md +94 -28
  177. package/skills/deep-interview/SKILL.md +91 -0
  178. package/src/scripts/__tests__/codex-native-hook.test.ts +468 -64
  179. package/src/scripts/__tests__/postinstall.test.ts +210 -0
  180. package/src/scripts/codex-native-hook.ts +136 -53
  181. package/src/scripts/postinstall-bootstrap.js +23 -0
  182. package/src/scripts/postinstall.ts +161 -0
  183. package/templates/AGENTS.md +1 -1
  184. package/templates/model-instructions/explore-lightweight-AGENTS.md +11 -0
  185. package/templates/model-instructions/sparkshell-lightweight-AGENTS.md +10 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=postinstall.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postinstall.test.d.ts","sourceRoot":"","sources":["../../../src/scripts/__tests__/postinstall.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,178 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { describe, it } from "node:test";
6
+ import { writeUserInstallStamp } from "../../cli/update.js";
7
+ import { isGlobalInstallLifecycle, runPostinstall, } from "../postinstall.js";
8
+ describe("isGlobalInstallLifecycle", () => {
9
+ it("accepts npm_config_global=true", () => {
10
+ assert.equal(isGlobalInstallLifecycle({ npm_config_global: "true" }), true);
11
+ });
12
+ it("accepts npm_config_location=global", () => {
13
+ assert.equal(isGlobalInstallLifecycle({ npm_config_location: "global" }), true);
14
+ });
15
+ it("rejects local installs", () => {
16
+ assert.equal(isGlobalInstallLifecycle({ npm_config_global: "false" }), false);
17
+ });
18
+ });
19
+ describe("runPostinstall", () => {
20
+ it("runs interactive setup only for bumped global installs", async () => {
21
+ const root = await mkdtemp(join(tmpdir(), "omx-postinstall-"));
22
+ const stampPath = join(root, ".codex", ".omx", "install-state.json");
23
+ const logs = [];
24
+ let setupCalls = 0;
25
+ try {
26
+ const result = await runPostinstall({
27
+ env: { npm_config_global: "true" },
28
+ getCurrentVersion: async () => "0.14.1",
29
+ isInteractive: () => true,
30
+ log: (message) => logs.push(message),
31
+ readStamp: async () => ({
32
+ installed_version: "0.14.0",
33
+ setup_completed_version: "0.14.0",
34
+ updated_at: "2026-04-20T00:00:00.000Z",
35
+ }),
36
+ runSetup: async () => {
37
+ setupCalls += 1;
38
+ },
39
+ writeStamp: async (stamp) => writeUserInstallStamp(stamp, stampPath),
40
+ });
41
+ assert.equal(result.status, "setup-ran");
42
+ assert.equal(setupCalls, 1);
43
+ assert.match(logs.join("\n"), /Launching interactive setup/);
44
+ const stamp = JSON.parse(await readFile(stampPath, "utf-8"));
45
+ assert.equal(stamp.installed_version, "0.14.1");
46
+ assert.equal(stamp.setup_completed_version, "0.14.1");
47
+ }
48
+ finally {
49
+ await rm(root, { recursive: true, force: true });
50
+ }
51
+ });
52
+ it("records the installed version and prints a hint when no TTY is available", async () => {
53
+ const root = await mkdtemp(join(tmpdir(), "omx-postinstall-"));
54
+ const stampPath = join(root, ".codex", ".omx", "install-state.json");
55
+ const logs = [];
56
+ let setupCalls = 0;
57
+ try {
58
+ const result = await runPostinstall({
59
+ env: { npm_config_global: "true" },
60
+ getCurrentVersion: async () => "0.14.1",
61
+ isInteractive: () => false,
62
+ log: (message) => logs.push(message),
63
+ readStamp: async () => ({
64
+ installed_version: "0.14.0",
65
+ setup_completed_version: "0.14.0",
66
+ updated_at: "2026-04-20T00:00:00.000Z",
67
+ }),
68
+ runSetup: async () => {
69
+ setupCalls += 1;
70
+ },
71
+ writeStamp: async (stamp) => writeUserInstallStamp(stamp, stampPath),
72
+ });
73
+ assert.equal(result.status, "hinted");
74
+ assert.equal(setupCalls, 0);
75
+ assert.match(logs.join("\n"), /Run `omx setup` \(interactive\) or `omx update`/);
76
+ const stamp = JSON.parse(await readFile(stampPath, "utf-8"));
77
+ assert.equal(stamp.installed_version, "0.14.1");
78
+ assert.equal(stamp.setup_completed_version, "0.14.0");
79
+ }
80
+ finally {
81
+ await rm(root, { recursive: true, force: true });
82
+ }
83
+ });
84
+ it("skips local installs", async () => {
85
+ let setupCalls = 0;
86
+ const result = await runPostinstall({
87
+ env: { npm_config_global: "false" },
88
+ getCurrentVersion: async () => "0.14.1",
89
+ isInteractive: () => true,
90
+ runSetup: async () => {
91
+ setupCalls += 1;
92
+ },
93
+ });
94
+ assert.equal(result.status, "noop-local");
95
+ assert.equal(setupCalls, 0);
96
+ });
97
+ it("does not rerun setup when the installed version matches the saved stamp", async () => {
98
+ let setupCalls = 0;
99
+ const result = await runPostinstall({
100
+ env: { npm_config_global: "true" },
101
+ getCurrentVersion: async () => "0.14.1",
102
+ isInteractive: () => true,
103
+ readStamp: async () => ({
104
+ installed_version: "0.14.1",
105
+ setup_completed_version: "0.14.1",
106
+ updated_at: "2026-04-20T00:00:00.000Z",
107
+ }),
108
+ runSetup: async () => {
109
+ setupCalls += 1;
110
+ },
111
+ });
112
+ assert.equal(result.status, "noop-same-version");
113
+ assert.equal(setupCalls, 0);
114
+ });
115
+ it("warns and exits cleanly when setup fails", async () => {
116
+ const warnings = [];
117
+ const result = await runPostinstall({
118
+ env: { npm_config_global: "true" },
119
+ getCurrentVersion: async () => "0.14.1",
120
+ isInteractive: () => true,
121
+ readStamp: async () => ({
122
+ installed_version: "0.14.0",
123
+ setup_completed_version: "0.14.0",
124
+ updated_at: "2026-04-20T00:00:00.000Z",
125
+ }),
126
+ runSetup: async () => {
127
+ throw new Error("boom");
128
+ },
129
+ warn: (message) => warnings.push(message),
130
+ writeStamp: async () => { },
131
+ });
132
+ assert.equal(result.status, "setup-failed");
133
+ assert.match(warnings.join("\n"), /non-fatal error: boom/);
134
+ });
135
+ it("runs interactive setup from the npm install prefix instead of the package dir or INIT_CWD", async () => {
136
+ const installRoot = await mkdtemp(join(tmpdir(), "omx-postinstall-install-root-"));
137
+ const packageRoot = await mkdtemp(join(tmpdir(), "omx-postinstall-package-root-"));
138
+ const initCwd = await mkdtemp(join(tmpdir(), "omx-postinstall-init-cwd-"));
139
+ const originalCwd = process.cwd();
140
+ const scopeFile = join(installRoot, ".omx", "setup-scope.json");
141
+ const packageScopeFile = join(packageRoot, ".omx", "setup-scope.json");
142
+ const initCwdScopeFile = join(initCwd, ".omx", "setup-scope.json");
143
+ try {
144
+ process.chdir(packageRoot);
145
+ const result = await runPostinstall({
146
+ env: {
147
+ npm_config_global: "true",
148
+ npm_config_prefix: installRoot,
149
+ INIT_CWD: initCwd,
150
+ },
151
+ getCurrentVersion: async () => "0.14.1",
152
+ isInteractive: () => true,
153
+ readStamp: async () => ({
154
+ installed_version: "0.14.0",
155
+ setup_completed_version: "0.14.0",
156
+ updated_at: "2026-04-20T00:00:00.000Z",
157
+ }),
158
+ runSetup: async () => {
159
+ await mkdir(join(process.cwd(), ".omx"), { recursive: true });
160
+ await writeFile(join(process.cwd(), ".omx", "setup-scope.json"), JSON.stringify({ scope: "project" }));
161
+ },
162
+ writeStamp: async () => { },
163
+ });
164
+ assert.equal(result.status, "setup-ran");
165
+ assert.equal(process.cwd(), packageRoot);
166
+ assert.equal(JSON.parse(await readFile(scopeFile, "utf-8")).scope, "project");
167
+ await assert.rejects(() => readFile(packageScopeFile, "utf-8"));
168
+ await assert.rejects(() => readFile(initCwdScopeFile, "utf-8"));
169
+ }
170
+ finally {
171
+ process.chdir(originalCwd);
172
+ await rm(installRoot, { recursive: true, force: true });
173
+ await rm(packageRoot, { recursive: true, force: true });
174
+ await rm(initCwd, { recursive: true, force: true });
175
+ }
176
+ });
177
+ });
178
+ //# sourceMappingURL=postinstall.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postinstall.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/postinstall.test.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,7 @@ export declare function resolveSessionOwnerPidFromAncestry(startPid: number, opt
19
19
  readProcessCommand?: (pid: number) => string;
20
20
  }): number | null;
21
21
  export declare function dispatchCodexNativeHook(payload: CodexHookPayload, options?: NativeHookDispatchOptions): Promise<NativeHookDispatchResult>;
22
+ export declare function isCodexNativeHookMainModule(moduleUrl: string, argv1: string | undefined): boolean;
22
23
  export declare function runCodexNativeHookCli(): Promise<void>;
23
24
  export {};
24
25
  //# sourceMappingURL=codex-native-hook.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AAsBA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAiBtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAelE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,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;AA2FD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,kBAAkB,GAAG,IAAI,GACvC,MAAM,GAAG,IAAI,CAef;AAqKD,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;AAwqCD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CAiKnC;AA8BD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmB3D"}
1
+ {"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AA4BA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAiBtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAiBlE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,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;AA2FD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,kBAAkB,GAAG,IAAI,GACvC,MAAM,GAAG,IAAI,CAef;AAiLD,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;AA8sCD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CAkLnC;AAOD,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAGT;AAyBD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmB3D"}
@@ -2,11 +2,12 @@ import { execFileSync } from "child_process";
2
2
  import { existsSync, readFileSync } from "fs";
3
3
  import { mkdir, readFile, readdir, writeFile } from "fs/promises";
4
4
  import { join, resolve } from "path";
5
+ import { pathToFileURL } from "url";
5
6
  import { readModeState, readModeStateForSession, updateModeState } from "../modes/base.js";
6
7
  import { listActiveSkills, readVisibleSkillActiveState, } from "../state/skill-active.js";
7
8
  import { readSubagentSessionSummary } from "../subagents/tracker.js";
8
9
  import { resolveCanonicalTeamStateRoot } from "../team/state-root.js";
9
- import { readUsableSessionState, reconcileNativeSessionStart } from "../hooks/session.js";
10
+ import { isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
10
11
  import { appendTeamEvent, readTeamLeaderAttention, readTeamManifestV2, readTeamPhase, writeTeamLeaderAttention, writeTeamPhase, } from "../team/state.js";
11
12
  import { omxNotepadPath, omxProjectMemoryPath } from "../utils/paths.js";
12
13
  import { getStateFilePath, getStatePath } from "../mcp/state-paths.js";
@@ -16,6 +17,7 @@ import { buildNativePostToolUseOutput, buildNativePreToolUseOutput, detectMcpTra
16
17
  import { buildNativeHookEvent, } from "../hooks/extensibility/events.js";
17
18
  import { dispatchHookEvent } from "../hooks/extensibility/dispatcher.js";
18
19
  import { reconcileHudForPromptSubmit } from "../hud/reconcile.js";
20
+ import { shellEscapeSingle } from "../hud/tmux.js";
19
21
  import { onSessionStart as buildWikiSessionStartContext } from "../wiki/lifecycle.js";
20
22
  import { readAutoresearchCompletionStatus, readAutoresearchModeState } from "../autoresearch/skill-validation.js";
21
23
  import { shouldContinueRun } from "../runtime/run-loop.js";
@@ -23,6 +25,7 @@ import { triagePrompt } from "../hooks/triage-heuristic.js";
23
25
  import { readTriageConfig } from "../hooks/triage-config.js";
24
26
  import { readTriageState, writeTriageState, shouldSuppressFollowup, promptSignature, } from "../hooks/triage-state.js";
25
27
  import { isPendingDeepInterviewQuestionEnforcement } from "../question/deep-interview.js";
28
+ import { resolveOmxCliEntryPath } from "../utils/paths.js";
26
29
  const TERMINAL_MODE_PHASES = new Set(["complete", "failed", "cancelled"]);
27
30
  const SKILL_STOP_BLOCKERS = new Set(["ralplan"]);
28
31
  const TEAM_TERMINAL_TASK_STATUSES = new Set(["completed", "failed"]);
@@ -133,24 +136,31 @@ function readPromptText(payload) {
133
136
  }
134
137
  return "";
135
138
  }
136
- function sanitizePayloadForHookContext(payload, hookEventName) {
137
- if (hookEventName !== "UserPromptSubmit")
138
- return payload;
139
+ function sanitizePayloadForHookContext(payload, hookEventName, canonicalSessionId = "") {
139
140
  const sanitized = { ...payload };
140
- delete sanitized.prompt;
141
- delete sanitized.input;
142
- delete sanitized.user_prompt;
143
- delete sanitized.userPrompt;
144
- delete sanitized.text;
141
+ if (hookEventName === "UserPromptSubmit") {
142
+ delete sanitized.prompt;
143
+ delete sanitized.input;
144
+ delete sanitized.user_prompt;
145
+ delete sanitized.userPrompt;
146
+ delete sanitized.text;
147
+ return sanitized;
148
+ }
149
+ if (hookEventName === "Stop") {
150
+ delete sanitized.stop_hook_active;
151
+ delete sanitized.stopHookActive;
152
+ delete sanitized.sessionId;
153
+ sanitized.session_id = canonicalSessionId.trim() || safeString(payload.session_id ?? payload.sessionId).trim();
154
+ }
145
155
  return sanitized;
146
156
  }
147
- function buildBaseContext(cwd, payload, hookEventName) {
157
+ function buildBaseContext(cwd, payload, hookEventName, canonicalSessionId = "") {
148
158
  return {
149
159
  cwd,
150
160
  project_path: cwd,
151
161
  transcript_path: safeString(payload.transcript_path ?? payload.transcriptPath) || null,
152
162
  source: safeString(payload.source),
153
- payload: sanitizePayloadForHookContext(payload, hookEventName),
163
+ payload: sanitizePayloadForHookContext(payload, hookEventName, canonicalSessionId),
154
164
  };
155
165
  }
156
166
  async function readJsonIfExists(path) {
@@ -183,14 +193,27 @@ async function readActiveAutoresearchState(cwd, sessionId) {
183
193
  return state;
184
194
  }
185
195
  async function readActiveRalphState(stateDir, preferredSessionId) {
186
- const sessionInfo = await readUsableSessionState(resolve(stateDir, "..", ".."));
187
- const currentOmxSessionId = safeString(sessionInfo?.session_id).trim();
196
+ const cwd = resolve(stateDir, "..", "..");
197
+ const [rawSessionInfo, usableSessionInfo] = await Promise.all([
198
+ readSessionState(cwd),
199
+ readUsableSessionState(cwd),
200
+ ]);
201
+ const currentOmxSessionId = safeString(usableSessionInfo?.session_id).trim();
202
+ const staleCurrentSessionId = rawSessionInfo && !isSessionStateUsable(rawSessionInfo, cwd)
203
+ ? safeString(rawSessionInfo.session_id).trim()
204
+ : "";
188
205
  const sessionCandidates = [...new Set([
189
206
  safeString(preferredSessionId).trim(),
190
207
  currentOmxSessionId,
191
208
  ].filter(Boolean))];
209
+ // Ralph Stop stays authoritative-scope-only once the Stop payload is session-bound.
210
+ // That is intentionally stricter than generic state MCP reads: do not scan sibling
211
+ // session scopes or fall back to root when a current/explicit session is in play.
192
212
  for (const sessionId of sessionCandidates) {
193
- const sessionScoped = await readJsonIfExists(join(stateDir, "sessions", sessionId, "ralph-state.json"));
213
+ if (staleCurrentSessionId && sessionId === staleCurrentSessionId) {
214
+ continue;
215
+ }
216
+ const sessionScoped = await readStopSessionPinnedState("ralph-state.json", cwd, sessionId);
194
217
  if (sessionScoped?.active === true && shouldContinueRun(sessionScoped)) {
195
218
  return sessionScoped;
196
219
  }
@@ -201,18 +224,6 @@ async function readActiveRalphState(stateDir, preferredSessionId) {
201
224
  if (direct?.active === true && shouldContinueRun(direct)) {
202
225
  return direct;
203
226
  }
204
- const sessionsRoot = join(stateDir, "sessions");
205
- if (!existsSync(sessionsRoot))
206
- return null;
207
- const entries = await readdir(sessionsRoot, { withFileTypes: true }).catch(() => []);
208
- for (const entry of entries) {
209
- if (!entry.isDirectory())
210
- continue;
211
- const candidate = await readJsonIfExists(join(sessionsRoot, entry.name, "ralph-state.json"));
212
- if (candidate?.active === true && shouldContinueRun(candidate)) {
213
- return candidate;
214
- }
215
- }
216
227
  return null;
217
228
  }
218
229
  function readParentPid(pid) {
@@ -303,38 +314,60 @@ function resolveSessionOwnerPid(payload) {
303
314
  return resolved;
304
315
  return process.pid;
305
316
  }
306
- async function ensureOmxGitignoreEntry(cwd) {
307
- let repoRoot = "";
317
+ function tryReadGitValue(cwd, args) {
308
318
  try {
309
- repoRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], {
319
+ const value = execFileSync("git", args, {
310
320
  cwd,
311
321
  encoding: "utf-8",
312
322
  stdio: ["ignore", "pipe", "ignore"],
313
323
  windowsHide: true,
314
324
  }).trim();
325
+ return value || null;
315
326
  }
316
327
  catch {
317
- return { changed: false };
328
+ return null;
329
+ }
330
+ }
331
+ function isPathIgnoredByGit(cwd, path) {
332
+ try {
333
+ execFileSync("git", ["check-ignore", "-q", path], {
334
+ cwd,
335
+ stdio: ["ignore", "ignore", "ignore"],
336
+ windowsHide: true,
337
+ });
338
+ return true;
318
339
  }
340
+ catch {
341
+ return false;
342
+ }
343
+ }
344
+ async function ensureOmxLocalIgnoreEntry(cwd) {
345
+ const repoRoot = tryReadGitValue(cwd, ["rev-parse", "--show-toplevel"]);
319
346
  if (!repoRoot)
320
347
  return { changed: false };
321
- const gitignorePath = join(repoRoot, ".gitignore");
322
- const existing = existsSync(gitignorePath)
323
- ? await readFile(gitignorePath, "utf-8")
348
+ if (isPathIgnoredByGit(repoRoot, ".omx/")) {
349
+ return { changed: false };
350
+ }
351
+ const excludePathValue = tryReadGitValue(repoRoot, ["rev-parse", "--git-path", "info/exclude"]);
352
+ if (!excludePathValue)
353
+ return { changed: false };
354
+ const excludePath = resolve(repoRoot, excludePathValue);
355
+ const existing = existsSync(excludePath)
356
+ ? await readFile(excludePath, "utf-8")
324
357
  : "";
325
358
  const lines = existing.split(/\r?\n/).map((line) => line.trim());
326
359
  if (lines.includes(".omx/")) {
327
- return { changed: false, gitignorePath };
360
+ return { changed: false, excludePath };
328
361
  }
329
362
  const next = `${existing}${existing.endsWith("\n") || existing.length === 0 ? "" : "\n"}.omx/\n`;
330
- await writeFile(gitignorePath, next);
331
- return { changed: true, gitignorePath };
363
+ await writeFile(excludePath, next);
364
+ return { changed: true, excludePath };
332
365
  }
333
366
  async function buildSessionStartContext(cwd, sessionId) {
334
367
  const sections = [];
335
- const gitignoreResult = await ensureOmxGitignoreEntry(cwd);
336
- if (gitignoreResult.changed) {
337
- sections.push(`Added .omx/ to ${gitignoreResult.gitignorePath} to keep local OMX state out of source control.`);
368
+ const localIgnoreResult = await ensureOmxLocalIgnoreEntry(cwd);
369
+ if (localIgnoreResult.changed) {
370
+ sections.push(`Added .omx/ to ${localIgnoreResult.excludePath} to keep local OMX state out of source control without mutating tracked repo ignores.`);
338
371
  }
339
372
  const modeSummaries = [];
340
373
  for (const mode of ["ralph", "autopilot", "ultrawork", "ultraqa", "ralplan", "deep-interview", "team"]) {
@@ -420,7 +453,12 @@ async function buildSessionStartContext(cwd, sessionId) {
420
453
  }
421
454
  return sections.length > 0 ? sections.join("\n\n") : null;
422
455
  }
423
- function buildAdditionalContextMessage(prompt, skillState) {
456
+ function buildDeepInterviewQuestionBridgeInstruction(cwd) {
457
+ const omxBin = resolveOmxCliEntryPath({ cwd }) || process.argv[1] || "omx";
458
+ const bridgeCommand = `${shellEscapeSingle(process.execPath)} ${shellEscapeSingle(omxBin)} question`;
459
+ return `Deep-interview must ask each interview round via \`omx question\`; do not fall back to \`request_user_input\` or plain-text questioning. After starting \`omx question\` in a background terminal, wait for that terminal to finish and read the JSON answer before continuing the interview. If bare \`omx question\` is unavailable in this reused session, use the current-session CLI bridge command: \`${bridgeCommand}\`. Stop remains blocked while a deep-interview question obligation is pending.`;
460
+ }
461
+ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd()) {
424
462
  if (!prompt)
425
463
  return null;
426
464
  const promptPriorityMessage = buildPromptPriorityMessage(prompt);
@@ -442,7 +480,7 @@ function buildAdditionalContextMessage(prompt, skillState) {
442
480
  ? "Prompt-side `$ralph` activation seeds Ralph workflow state only; it does not invoke `omx ralph`. Use `omx ralph --prd ...` only when you explicitly want the PRD-gated CLI startup path."
443
481
  : null;
444
482
  const deepInterviewPromptActivationNote = skillState?.initialized_mode === "deep-interview"
445
- ? "Deep-interview must ask each interview round via `omx question`; do not fall back to `request_user_input` or plain-text questioning. Stop remains blocked while a deep-interview question obligation is pending."
483
+ ? buildDeepInterviewQuestionBridgeInstruction(cwd)
446
484
  : null;
447
485
  const combinedTransitionMessage = (() => {
448
486
  if (!skillState?.transition_message)
@@ -803,7 +841,11 @@ async function readStopAutoNudgePhase(cwd, sessionId, threadId) {
803
841
  }
804
842
  async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
805
843
  const modeState = await readStopSessionPinnedState("deep-interview-state.json", cwd, sessionId);
806
- if (!modeState || modeState.active !== true)
844
+ if (!modeState)
845
+ return null;
846
+ const questionEnforcement = safeObject(modeState.question_enforcement);
847
+ const hasPendingQuestionObligation = isPendingDeepInterviewQuestionEnforcement(questionEnforcement);
848
+ if (modeState.active !== true && !hasPendingQuestionObligation)
807
849
  return null;
808
850
  const phase = formatPhase(modeState.current_phase, "planning");
809
851
  if (TERMINAL_MODE_PHASES.has(phase.toLowerCase()) || phase === "completing") {
@@ -816,8 +858,7 @@ async function buildDeepInterviewQuestionStopOutput(cwd, sessionId, threadId) {
816
858
  if (!blocker)
817
859
  return null;
818
860
  }
819
- const questionEnforcement = safeObject(modeState.question_enforcement);
820
- if (!isPendingDeepInterviewQuestionEnforcement(questionEnforcement)) {
861
+ if (!hasPendingQuestionObligation) {
821
862
  return null;
822
863
  }
823
864
  const obligationId = safeString(questionEnforcement.obligation_id).trim();
@@ -904,8 +945,8 @@ async function maybeReturnRepeatableStopOutput(payload, stateDir, signature, out
904
945
  await persistNativeStopSignature(stateDir, payload, signature, canonicalSessionId);
905
946
  return output;
906
947
  }
907
- async function returnPersistentStopBlock(payload, stateDir, signatureKind, signatureValue, output, canonicalSessionId) {
908
- return await maybeReturnRepeatableStopOutput(payload, stateDir, buildRepeatableStopSignature(payload, signatureKind, signatureValue, canonicalSessionId), output, canonicalSessionId, { allowRepeatDuringStopHook: true });
948
+ async function returnPersistentStopBlock(payload, stateDir, signatureKind, signatureValue, output, canonicalSessionId, options = { allowRepeatDuringStopHook: true }) {
949
+ return await maybeReturnRepeatableStopOutput(payload, stateDir, buildRepeatableStopSignature(payload, signatureKind, signatureValue, canonicalSessionId), output, canonicalSessionId, options);
909
950
  }
910
951
  async function findCanonicalActiveTeamForSession(cwd, sessionId) {
911
952
  if (!sessionId.trim())
@@ -1099,7 +1140,7 @@ async function buildStopHookOutput(payload, cwd, stateDir) {
1099
1140
  }
1100
1141
  const ultraworkOutput = await buildModeBasedStopOutput("ultrawork", cwd, canonicalSessionId);
1101
1142
  if (ultraworkOutput) {
1102
- return await returnPersistentStopBlock(payload, stateDir, "ultrawork-stop", safeString(ultraworkOutput.stopReason), ultraworkOutput, canonicalSessionId);
1143
+ return await returnPersistentStopBlock(payload, stateDir, "ultrawork-stop", safeString(ultraworkOutput.stopReason), ultraworkOutput, canonicalSessionId, { allowRepeatDuringStopHook: false });
1103
1144
  }
1104
1145
  const ultraqaOutput = await buildModeBasedStopOutput("ultraqa", cwd, canonicalSessionId);
1105
1146
  if (ultraqaOutput) {
@@ -1165,18 +1206,32 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1165
1206
  const nativeSessionId = safeString(payload.session_id ?? payload.sessionId).trim();
1166
1207
  const threadId = safeString(payload.thread_id ?? payload.threadId).trim();
1167
1208
  const turnId = safeString(payload.turn_id ?? payload.turnId).trim();
1168
- let canonicalSessionId = safeString((await readUsableSessionState(cwd))?.session_id).trim();
1209
+ const currentSessionState = await readUsableSessionState(cwd);
1210
+ let canonicalSessionId = safeString(currentSessionState?.session_id).trim();
1211
+ let resolvedNativeSessionId = nativeSessionId;
1169
1212
  if (hookEventName === "SessionStart" && nativeSessionId) {
1170
1213
  const sessionState = await reconcileNativeSessionStart(cwd, nativeSessionId, {
1171
1214
  pid: options.sessionOwnerPid ?? resolveSessionOwnerPid(payload),
1172
1215
  });
1173
1216
  canonicalSessionId = safeString(sessionState.session_id).trim();
1217
+ resolvedNativeSessionId = safeString(sessionState.native_session_id).trim() || nativeSessionId;
1174
1218
  }
1175
1219
  else if (!canonicalSessionId) {
1176
- canonicalSessionId = safeString((await readUsableSessionState(cwd))?.session_id).trim();
1220
+ canonicalSessionId = safeString(currentSessionState?.session_id).trim();
1221
+ }
1222
+ if (hookEventName === "Stop") {
1223
+ const stopCanonicalSessionId = await resolveInternalSessionIdForPayload(cwd, readPayloadSessionId(payload));
1224
+ if (stopCanonicalSessionId) {
1225
+ canonicalSessionId = stopCanonicalSessionId;
1226
+ }
1227
+ if (canonicalSessionId && safeString(currentSessionState?.session_id).trim() === canonicalSessionId) {
1228
+ resolvedNativeSessionId =
1229
+ safeString(currentSessionState?.native_session_id).trim() || resolvedNativeSessionId;
1230
+ }
1177
1231
  }
1178
1232
  const eventSessionId = canonicalSessionId || nativeSessionId || undefined;
1179
1233
  const sessionIdForState = canonicalSessionId || nativeSessionId;
1234
+ let outputJson = null;
1180
1235
  if (hookEventName === "UserPromptSubmit") {
1181
1236
  const prompt = readPromptText(payload);
1182
1237
  if (prompt) {
@@ -1263,10 +1318,10 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1263
1318
  await reconcileHudForPromptSubmitFn(cwd, { sessionId: canonicalSessionId || sessionIdForState || undefined }).catch(() => { });
1264
1319
  }
1265
1320
  if (omxEventName) {
1266
- const baseContext = buildBaseContext(cwd, payload, hookEventName);
1267
- if (nativeSessionId) {
1268
- baseContext.native_session_id = nativeSessionId;
1269
- baseContext.codex_session_id = nativeSessionId;
1321
+ const baseContext = buildBaseContext(cwd, payload, hookEventName, canonicalSessionId);
1322
+ if (resolvedNativeSessionId) {
1323
+ baseContext.native_session_id = resolvedNativeSessionId;
1324
+ baseContext.codex_session_id = resolvedNativeSessionId;
1270
1325
  }
1271
1326
  if (canonicalSessionId) {
1272
1327
  baseContext.omx_session_id = canonicalSessionId;
@@ -1279,11 +1334,10 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1279
1334
  });
1280
1335
  await dispatchHookEvent(event, { cwd });
1281
1336
  }
1282
- let outputJson = null;
1283
1337
  if (hookEventName === "SessionStart" || hookEventName === "UserPromptSubmit") {
1284
1338
  const additionalContext = hookEventName === "SessionStart"
1285
1339
  ? await buildSessionStartContext(cwd, canonicalSessionId || nativeSessionId)
1286
- : (buildAdditionalContextMessage(readPromptText(payload), skillState) ?? triageAdditionalContext);
1340
+ : (buildAdditionalContextMessage(readPromptText(payload), skillState, cwd) ?? triageAdditionalContext);
1287
1341
  if (additionalContext) {
1288
1342
  outputJson = {
1289
1343
  hookSpecificOutput: {
@@ -1312,6 +1366,11 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
1312
1366
  outputJson,
1313
1367
  };
1314
1368
  }
1369
+ export function isCodexNativeHookMainModule(moduleUrl, argv1) {
1370
+ if (!argv1)
1371
+ return false;
1372
+ return moduleUrl === pathToFileURL(argv1).href;
1373
+ }
1315
1374
  async function readStdinJson() {
1316
1375
  const chunks = [];
1317
1376
  for await (const chunk of process.stdin) {
@@ -1352,7 +1411,7 @@ export async function runCodexNativeHookCli() {
1352
1411
  process.stdout.write(`${JSON.stringify(result.outputJson)}\n`);
1353
1412
  }
1354
1413
  }
1355
- if (import.meta.url === `file://${process.argv[1]}`) {
1414
+ if (isCodexNativeHookMainModule(import.meta.url, process.argv[1])) {
1356
1415
  runCodexNativeHookCli().catch((error) => {
1357
1416
  process.stderr.write(`[omx] codex-native-hook failed: ${error instanceof Error ? error.message : String(error)}\n`);
1358
1417
  process.exitCode = 1;