oh-my-codex 0.10.2 → 0.10.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.
Files changed (293) hide show
  1. package/Cargo.lock +2 -2
  2. package/Cargo.toml +1 -1
  3. package/README.de.md +4 -4
  4. package/README.es.md +4 -4
  5. package/README.fr.md +4 -4
  6. package/README.it.md +4 -4
  7. package/README.ja.md +4 -4
  8. package/README.ko.md +4 -4
  9. package/README.md +13 -7
  10. package/README.pt.md +4 -4
  11. package/README.ru.md +4 -4
  12. package/README.tr.md +4 -4
  13. package/README.vi.md +4 -4
  14. package/README.zh-TW.md +4 -4
  15. package/README.zh.md +4 -4
  16. package/dist/agents/__tests__/native-config.test.js +37 -33
  17. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  18. package/dist/agents/native-config.d.ts +18 -6
  19. package/dist/agents/native-config.d.ts.map +1 -1
  20. package/dist/agents/native-config.js +109 -92
  21. package/dist/agents/native-config.js.map +1 -1
  22. package/dist/autoresearch/__tests__/contracts.test.js +37 -1
  23. package/dist/autoresearch/__tests__/contracts.test.js.map +1 -1
  24. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js +10 -10
  25. package/dist/autoresearch/__tests__/runtime-parity-extra.test.js.map +1 -1
  26. package/dist/autoresearch/__tests__/runtime.test.js +2 -2
  27. package/dist/autoresearch/__tests__/runtime.test.js.map +1 -1
  28. package/dist/autoresearch/contracts.d.ts.map +1 -1
  29. package/dist/autoresearch/contracts.js +17 -10
  30. package/dist/autoresearch/contracts.js.map +1 -1
  31. package/dist/autoresearch/runtime.d.ts.map +1 -1
  32. package/dist/autoresearch/runtime.js +84 -96
  33. package/dist/autoresearch/runtime.js.map +1 -1
  34. package/dist/cli/__tests__/agents-init.test.js +2 -0
  35. package/dist/cli/__tests__/agents-init.test.js.map +1 -1
  36. package/dist/cli/__tests__/agents.test.d.ts +2 -0
  37. package/dist/cli/__tests__/agents.test.d.ts.map +1 -0
  38. package/dist/cli/__tests__/agents.test.js +114 -0
  39. package/dist/cli/__tests__/agents.test.js.map +1 -0
  40. package/dist/cli/__tests__/autoresearch-guided.test.js +156 -1
  41. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
  42. package/dist/cli/__tests__/autoresearch.test.js +483 -25
  43. package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
  44. package/dist/cli/__tests__/cleanup.test.d.ts +2 -0
  45. package/dist/cli/__tests__/cleanup.test.d.ts.map +1 -0
  46. package/dist/cli/__tests__/cleanup.test.js +213 -0
  47. package/dist/cli/__tests__/cleanup.test.js.map +1 -0
  48. package/dist/cli/__tests__/error-handling-warnings.test.js +1 -1
  49. package/dist/cli/__tests__/error-handling-warnings.test.js.map +1 -1
  50. package/dist/cli/__tests__/explore.test.js +3 -3
  51. package/dist/cli/__tests__/explore.test.js.map +1 -1
  52. package/dist/cli/__tests__/index.test.js +530 -401
  53. package/dist/cli/__tests__/index.test.js.map +1 -1
  54. package/dist/cli/__tests__/native-assets.test.js +72 -9
  55. package/dist/cli/__tests__/native-assets.test.js.map +1 -1
  56. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts +2 -0
  57. package/dist/cli/__tests__/ralph-deslop-contract.test.d.ts.map +1 -0
  58. package/dist/cli/__tests__/ralph-deslop-contract.test.js +28 -0
  59. package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -0
  60. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js +4 -0
  61. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
  62. package/dist/cli/__tests__/ralphthon.test.d.ts +2 -0
  63. package/dist/cli/__tests__/ralphthon.test.d.ts.map +1 -0
  64. package/dist/cli/__tests__/ralphthon.test.js +28 -0
  65. package/dist/cli/__tests__/ralphthon.test.js.map +1 -0
  66. package/dist/cli/__tests__/setup-agents-overwrite.test.js +36 -1
  67. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  68. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +35 -5
  69. package/dist/cli/__tests__/setup-prompts-overwrite.test.js.map +1 -1
  70. package/dist/cli/__tests__/setup-refresh.test.js +2 -2
  71. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  72. package/dist/cli/__tests__/setup-scope.test.js +131 -161
  73. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  74. package/dist/cli/__tests__/setup-skills-overwrite.test.js +10 -10
  75. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
  76. package/dist/cli/__tests__/sparkshell-cli.test.js +28 -2
  77. package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
  78. package/dist/cli/__tests__/team.test.js +1 -112
  79. package/dist/cli/__tests__/team.test.js.map +1 -1
  80. package/dist/cli/__tests__/uninstall.test.js +7 -20
  81. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  82. package/dist/cli/agents-init.d.ts.map +1 -1
  83. package/dist/cli/agents-init.js +99 -95
  84. package/dist/cli/agents-init.js.map +1 -1
  85. package/dist/cli/agents.d.ts +14 -0
  86. package/dist/cli/agents.d.ts.map +1 -0
  87. package/dist/cli/agents.js +261 -0
  88. package/dist/cli/agents.js.map +1 -0
  89. package/dist/cli/autoresearch-guided.d.ts +8 -0
  90. package/dist/cli/autoresearch-guided.d.ts.map +1 -1
  91. package/dist/cli/autoresearch-guided.js +104 -37
  92. package/dist/cli/autoresearch-guided.js.map +1 -1
  93. package/dist/cli/autoresearch-intake.d.ts +62 -0
  94. package/dist/cli/autoresearch-intake.d.ts.map +1 -0
  95. package/dist/cli/autoresearch-intake.js +336 -0
  96. package/dist/cli/autoresearch-intake.js.map +1 -0
  97. package/dist/cli/autoresearch.d.ts +4 -1
  98. package/dist/cli/autoresearch.d.ts.map +1 -1
  99. package/dist/cli/autoresearch.js +181 -32
  100. package/dist/cli/autoresearch.js.map +1 -1
  101. package/dist/cli/cleanup.d.ts +52 -0
  102. package/dist/cli/cleanup.d.ts.map +1 -0
  103. package/dist/cli/cleanup.js +302 -0
  104. package/dist/cli/cleanup.js.map +1 -0
  105. package/dist/cli/doctor.d.ts.map +1 -1
  106. package/dist/cli/doctor.js +9 -37
  107. package/dist/cli/doctor.js.map +1 -1
  108. package/dist/cli/explore.d.ts.map +1 -1
  109. package/dist/cli/explore.js +5 -4
  110. package/dist/cli/explore.js.map +1 -1
  111. package/dist/cli/index.d.ts +5 -7
  112. package/dist/cli/index.d.ts.map +1 -1
  113. package/dist/cli/index.js +623 -451
  114. package/dist/cli/index.js.map +1 -1
  115. package/dist/cli/native-assets.d.ts +15 -1
  116. package/dist/cli/native-assets.d.ts.map +1 -1
  117. package/dist/cli/native-assets.js +134 -32
  118. package/dist/cli/native-assets.js.map +1 -1
  119. package/dist/cli/ralph.d.ts.map +1 -1
  120. package/dist/cli/ralph.js +38 -1
  121. package/dist/cli/ralph.js.map +1 -1
  122. package/dist/cli/ralphthon.d.ts +14 -0
  123. package/dist/cli/ralphthon.d.ts.map +1 -0
  124. package/dist/cli/ralphthon.js +234 -0
  125. package/dist/cli/ralphthon.js.map +1 -0
  126. package/dist/cli/setup.d.ts +1 -4
  127. package/dist/cli/setup.d.ts.map +1 -1
  128. package/dist/cli/setup.js +111 -76
  129. package/dist/cli/setup.js.map +1 -1
  130. package/dist/cli/sparkshell.d.ts +3 -1
  131. package/dist/cli/sparkshell.d.ts.map +1 -1
  132. package/dist/cli/sparkshell.js +35 -16
  133. package/dist/cli/sparkshell.js.map +1 -1
  134. package/dist/cli/team.d.ts.map +1 -1
  135. package/dist/cli/team.js +1 -0
  136. package/dist/cli/team.js.map +1 -1
  137. package/dist/cli/uninstall.d.ts +1 -1
  138. package/dist/cli/uninstall.d.ts.map +1 -1
  139. package/dist/cli/uninstall.js +82 -64
  140. package/dist/cli/uninstall.js.map +1 -1
  141. package/dist/config/__tests__/generator-idempotent.test.js +10 -10
  142. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  143. package/dist/config/__tests__/generator-notify.test.js +15 -0
  144. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  145. package/dist/config/generator.d.ts +0 -1
  146. package/dist/config/generator.d.ts.map +1 -1
  147. package/dist/config/generator.js +53 -42
  148. package/dist/config/generator.js.map +1 -1
  149. package/dist/hooks/__tests__/agents-overlay.test.js +295 -230
  150. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  151. package/dist/hooks/__tests__/anti-slop-workflow.test.js +3 -0
  152. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
  153. package/dist/hooks/__tests__/deep-interview-contract.test.js +49 -24
  154. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  155. package/dist/hooks/__tests__/notify-fallback-watcher-ralphthon.test.d.ts +2 -0
  156. package/dist/hooks/__tests__/notify-fallback-watcher-ralphthon.test.d.ts.map +1 -0
  157. package/dist/hooks/__tests__/notify-fallback-watcher-ralphthon.test.js +193 -0
  158. package/dist/hooks/__tests__/notify-fallback-watcher-ralphthon.test.js.map +1 -0
  159. package/dist/hooks/agents-overlay.d.ts +1 -1
  160. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  161. package/dist/hooks/agents-overlay.js +109 -106
  162. package/dist/hooks/agents-overlay.js.map +1 -1
  163. package/dist/hud/constants.d.ts +1 -1
  164. package/dist/hud/constants.js +1 -1
  165. package/dist/modes/base.d.ts +1 -1
  166. package/dist/modes/base.d.ts.map +1 -1
  167. package/dist/modes/base.js +1 -1
  168. package/dist/modes/base.js.map +1 -1
  169. package/dist/notifications/__tests__/formatter.test.js +36 -2
  170. package/dist/notifications/__tests__/formatter.test.js.map +1 -1
  171. package/dist/notifications/formatter.d.ts +3 -2
  172. package/dist/notifications/formatter.d.ts.map +1 -1
  173. package/dist/notifications/formatter.js +33 -9
  174. package/dist/notifications/formatter.js.map +1 -1
  175. package/dist/ralphthon/__tests__/bootstrap.test.d.ts +2 -0
  176. package/dist/ralphthon/__tests__/bootstrap.test.d.ts.map +1 -0
  177. package/dist/ralphthon/__tests__/bootstrap.test.js +23 -0
  178. package/dist/ralphthon/__tests__/bootstrap.test.js.map +1 -0
  179. package/dist/ralphthon/__tests__/orchestrator.test.d.ts +2 -0
  180. package/dist/ralphthon/__tests__/orchestrator.test.d.ts.map +1 -0
  181. package/dist/ralphthon/__tests__/orchestrator.test.js +309 -0
  182. package/dist/ralphthon/__tests__/orchestrator.test.js.map +1 -0
  183. package/dist/ralphthon/__tests__/prd.test.d.ts +2 -0
  184. package/dist/ralphthon/__tests__/prd.test.d.ts.map +1 -0
  185. package/dist/ralphthon/__tests__/prd.test.js +133 -0
  186. package/dist/ralphthon/__tests__/prd.test.js.map +1 -0
  187. package/dist/ralphthon/bootstrap.d.ts +3 -0
  188. package/dist/ralphthon/bootstrap.d.ts.map +1 -0
  189. package/dist/ralphthon/bootstrap.js +84 -0
  190. package/dist/ralphthon/bootstrap.js.map +1 -0
  191. package/dist/ralphthon/orchestrator.d.ts +50 -0
  192. package/dist/ralphthon/orchestrator.d.ts.map +1 -0
  193. package/dist/ralphthon/orchestrator.js +362 -0
  194. package/dist/ralphthon/orchestrator.js.map +1 -0
  195. package/dist/ralphthon/prd.d.ts +191 -0
  196. package/dist/ralphthon/prd.d.ts.map +1 -0
  197. package/dist/ralphthon/prd.js +359 -0
  198. package/dist/ralphthon/prd.js.map +1 -0
  199. package/dist/ralphthon/runtime.d.ts +31 -0
  200. package/dist/ralphthon/runtime.d.ts.map +1 -0
  201. package/dist/ralphthon/runtime.js +108 -0
  202. package/dist/ralphthon/runtime.js.map +1 -0
  203. package/dist/ralphthon/tmux.d.ts +3 -0
  204. package/dist/ralphthon/tmux.d.ts.map +1 -0
  205. package/dist/ralphthon/tmux.js +39 -0
  206. package/dist/ralphthon/tmux.js.map +1 -0
  207. package/dist/subagents/__tests__/tracker.test.d.ts +2 -0
  208. package/dist/subagents/__tests__/tracker.test.d.ts.map +1 -0
  209. package/dist/subagents/__tests__/tracker.test.js +47 -0
  210. package/dist/subagents/__tests__/tracker.test.js.map +1 -0
  211. package/dist/subagents/tracker.d.ts +52 -0
  212. package/dist/subagents/tracker.d.ts.map +1 -0
  213. package/dist/subagents/tracker.js +175 -0
  214. package/dist/subagents/tracker.js.map +1 -0
  215. package/dist/team/__tests__/runtime.test.js +2 -2
  216. package/dist/team/__tests__/runtime.test.js.map +1 -1
  217. package/dist/team/__tests__/tmux-session.test.js +34 -0
  218. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  219. package/dist/team/__tests__/worker-bootstrap.test.js +189 -163
  220. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  221. package/dist/team/__tests__/worktree.test.js +1 -1
  222. package/dist/team/__tests__/worktree.test.js.map +1 -1
  223. package/dist/team/tmux-session.d.ts +4 -4
  224. package/dist/team/tmux-session.d.ts.map +1 -1
  225. package/dist/team/tmux-session.js +48 -15
  226. package/dist/team/tmux-session.js.map +1 -1
  227. package/dist/team/worker-bootstrap.d.ts +1 -1
  228. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  229. package/dist/team/worker-bootstrap.js +58 -63
  230. package/dist/team/worker-bootstrap.js.map +1 -1
  231. package/dist/team/worktree.js +1 -1
  232. package/dist/team/worktree.js.map +1 -1
  233. package/dist/utils/__tests__/agents-md.test.d.ts +2 -0
  234. package/dist/utils/__tests__/agents-md.test.d.ts.map +1 -0
  235. package/dist/utils/__tests__/agents-md.test.js +32 -0
  236. package/dist/utils/__tests__/agents-md.test.js.map +1 -0
  237. package/dist/utils/__tests__/agents-model-table.test.d.ts +2 -0
  238. package/dist/utils/__tests__/agents-model-table.test.d.ts.map +1 -0
  239. package/dist/utils/__tests__/agents-model-table.test.js +84 -0
  240. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -0
  241. package/dist/utils/__tests__/paths.test.js +78 -83
  242. package/dist/utils/__tests__/paths.test.js.map +1 -1
  243. package/dist/utils/agents-md.d.ts.map +1 -1
  244. package/dist/utils/agents-md.js +10 -0
  245. package/dist/utils/agents-md.js.map +1 -1
  246. package/dist/utils/agents-model-table.d.ts +16 -0
  247. package/dist/utils/agents-model-table.d.ts.map +1 -0
  248. package/dist/utils/agents-model-table.js +83 -0
  249. package/dist/utils/agents-model-table.js.map +1 -0
  250. package/dist/utils/paths.d.ts +6 -6
  251. package/dist/utils/paths.d.ts.map +1 -1
  252. package/dist/utils/paths.js +31 -31
  253. package/dist/utils/paths.js.map +1 -1
  254. package/dist/verification/__tests__/explore-harness-release-workflow.test.js +21 -3
  255. package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
  256. package/dist/verification/__tests__/native-release-manifest.test.d.ts +2 -0
  257. package/dist/verification/__tests__/native-release-manifest.test.d.ts.map +1 -0
  258. package/dist/verification/__tests__/native-release-manifest.test.js +80 -0
  259. package/dist/verification/__tests__/native-release-manifest.test.js.map +1 -0
  260. package/package.json +1 -1
  261. package/prompts/executor.md +15 -0
  262. package/scripts/__tests__/smoke-packed-install.test.mjs +137 -8
  263. package/scripts/eval-adaptive-sort-optimization.py +24 -0
  264. package/scripts/eval-in-action-cat-shellout-demo.js +31 -0
  265. package/scripts/eval-ml-kaggle-model-optimization.py +29 -0
  266. package/scripts/eval-noisy-bayesopt-highdim.py +44 -0
  267. package/scripts/eval-noisy-latent-subspace-discovery.py +44 -0
  268. package/scripts/generate-native-release-manifest.mjs +14 -3
  269. package/scripts/notify-fallback-watcher.js +308 -6
  270. package/scripts/notify-hook.js +20 -0
  271. package/scripts/run-autoresearch-showcase.sh +75 -0
  272. package/scripts/smoke-packed-install.mjs +142 -10
  273. package/skills/ai-slop-cleaner/SKILL.md +7 -0
  274. package/skills/deep-interview/SKILL.md +30 -1
  275. package/skills/omx-setup/SKILL.md +2 -2
  276. package/skills/ralph/SKILL.md +15 -0
  277. package/skills/skill/SKILL.md +32 -32
  278. package/skills/team/SKILL.md +6 -0
  279. package/skills/worker/SKILL.md +2 -2
  280. package/templates/AGENTS.md +97 -16
  281. package/dist/cli/__tests__/runtime-native-resolution.test.d.ts +0 -2
  282. package/dist/cli/__tests__/runtime-native-resolution.test.d.ts.map +0 -1
  283. package/dist/cli/__tests__/runtime-native-resolution.test.js.map +0 -1
  284. package/dist/cli/__tests__/runtime-native.test.d.ts +0 -2
  285. package/dist/cli/__tests__/runtime-native.test.d.ts.map +0 -1
  286. package/dist/cli/__tests__/runtime-native.test.js.map +0 -1
  287. package/dist/cli/runtime-native.d.ts +0 -23
  288. package/dist/cli/runtime-native.d.ts.map +0 -1
  289. package/dist/cli/runtime-native.js +0 -86
  290. package/dist/cli/runtime-native.js.map +0 -1
  291. package/dist/mcp/__tests__/runtime-run-native-cutover.test.d.ts +0 -2
  292. package/dist/mcp/__tests__/runtime-run-native-cutover.test.d.ts.map +0 -1
  293. package/dist/mcp/__tests__/runtime-run-native-cutover.test.js.map +0 -1
@@ -4,213 +4,255 @@
4
4
  * Covers: overlay generation, apply/strip roundtrip, idempotency,
5
5
  * size cap enforcement, and graceful handling of missing state.
6
6
  */
7
- import { describe, it, before, after } from 'node:test';
8
- import assert from 'node:assert/strict';
9
- import { mkdtemp, rm, mkdir, writeFile, readFile } from 'fs/promises';
10
- import { existsSync } from 'fs';
11
- import { join } from 'path';
12
- import { tmpdir } from 'os';
13
- import { generateOverlay, applyOverlay, stripOverlay, hasOverlay, resolveSessionOrchestrationMode, writeSessionModelInstructionsFile, removeSessionModelInstructionsFile, sessionModelInstructionsPath, } from '../agents-overlay.js';
14
- const RUNTIME_START = '<!-- OMX:RUNTIME:START -->';
15
- const RUNTIME_END = '<!-- OMX:RUNTIME:END -->';
16
- const WORKER_START = '<!-- OMX:TEAM:WORKER:START -->';
17
- const WORKER_END = '<!-- OMX:TEAM:WORKER:END -->';
7
+ import { describe, it, before, after } from "node:test";
8
+ import assert from "node:assert/strict";
9
+ import { mkdtemp, rm, mkdir, writeFile, readFile } from "fs/promises";
10
+ import { existsSync } from "fs";
11
+ import { join } from "path";
12
+ import { tmpdir } from "os";
13
+ import { generateOverlay, applyOverlay, stripOverlay, hasOverlay, resolveSessionOrchestrationMode, writeSessionModelInstructionsFile, removeSessionModelInstructionsFile, sessionModelInstructionsPath, } from "../agents-overlay.js";
14
+ const RUNTIME_START = "<!-- OMX:RUNTIME:START -->";
15
+ const RUNTIME_END = "<!-- OMX:RUNTIME:END -->";
16
+ const WORKER_START = "<!-- OMX:TEAM:WORKER:START -->";
17
+ const WORKER_END = "<!-- OMX:TEAM:WORKER:END -->";
18
18
  async function makeTempDir() {
19
- const dir = await mkdtemp(join(tmpdir(), 'omx-overlay-test-'));
20
- await mkdir(join(dir, '.omx', 'state'), { recursive: true });
19
+ const dir = await mkdtemp(join(tmpdir(), "omx-overlay-test-"));
20
+ await mkdir(join(dir, ".omx", "state"), { recursive: true });
21
21
  return dir;
22
22
  }
23
23
  function setMockCodexHome(codexHomePath) {
24
24
  const previous = process.env.CODEX_HOME;
25
25
  process.env.CODEX_HOME = codexHomePath;
26
26
  return () => {
27
- if (typeof previous === 'string')
27
+ if (typeof previous === "string")
28
28
  process.env.CODEX_HOME = previous;
29
29
  else
30
30
  delete process.env.CODEX_HOME;
31
31
  };
32
32
  }
33
- describe('generateOverlay', () => {
33
+ describe("generateOverlay", () => {
34
34
  let tempDir;
35
- before(async () => { tempDir = await makeTempDir(); });
36
- after(async () => { await rm(tempDir, { recursive: true, force: true }); });
37
- it('generates overlay with no state files (empty but valid)', async () => {
38
- const overlay = await generateOverlay(tempDir, 'test-session-1');
39
- assert.ok(overlay.includes('<!-- OMX:RUNTIME:START -->'));
40
- assert.ok(overlay.includes('<!-- OMX:RUNTIME:END -->'));
41
- assert.ok(overlay.includes('test-session-1'));
42
- assert.ok(overlay.includes('Compaction Protocol'));
43
- });
44
- it('includes the team orchestrator overlay only when orchestration mode is team', async () => {
45
- const overlay = await generateOverlay(tempDir, 'team-session', { orchestrationMode: 'team' });
35
+ before(async () => {
36
+ tempDir = await makeTempDir();
37
+ });
38
+ after(async () => {
39
+ await rm(tempDir, { recursive: true, force: true });
40
+ });
41
+ it("generates overlay with no state files (empty but valid)", async () => {
42
+ const overlay = await generateOverlay(tempDir, "test-session-1");
43
+ assert.ok(overlay.includes("<!-- OMX:RUNTIME:START -->"));
44
+ assert.ok(overlay.includes("<!-- OMX:RUNTIME:END -->"));
45
+ assert.ok(overlay.includes("test-session-1"));
46
+ assert.ok(overlay.includes("Compaction Protocol"));
47
+ });
48
+ it("includes the team orchestrator overlay only when orchestration mode is team", async () => {
49
+ const overlay = await generateOverlay(tempDir, "team-session", {
50
+ orchestrationMode: "team",
51
+ });
46
52
  assert.match(overlay, /\*\*Orchestration Mode:\*\* team/);
47
53
  assert.match(overlay, /supervised, high-overhead coordination surface/i);
48
- const defaultOverlay = await generateOverlay(tempDir, 'default-session', { orchestrationMode: 'default' });
54
+ const defaultOverlay = await generateOverlay(tempDir, "default-session", {
55
+ orchestrationMode: "default",
56
+ });
49
57
  assert.doesNotMatch(defaultOverlay, /\*\*Orchestration Mode:\*\* team/);
50
58
  });
51
- it('adds advisory explore routing guidance only when USE_OMX_EXPLORE_CMD is enabled', async () => {
59
+ it("adds advisory explore routing guidance only when USE_OMX_EXPLORE_CMD is enabled", async () => {
52
60
  const previous = process.env.USE_OMX_EXPLORE_CMD;
53
61
  try {
54
62
  delete process.env.USE_OMX_EXPLORE_CMD;
55
- const disabledOverlay = await generateOverlay(tempDir, 'explore-routing-off');
63
+ const disabledOverlay = await generateOverlay(tempDir, "explore-routing-off");
56
64
  assert.doesNotMatch(disabledOverlay, /\*\*Explore Command Preference:\*\*/);
57
- process.env.USE_OMX_EXPLORE_CMD = '1';
58
- const enabledOverlay = await generateOverlay(tempDir, 'explore-routing-on');
65
+ process.env.USE_OMX_EXPLORE_CMD = "1";
66
+ const enabledOverlay = await generateOverlay(tempDir, "explore-routing-on");
59
67
  assert.match(enabledOverlay, /\*\*Explore Command Preference:\*\* enabled via `USE_OMX_EXPLORE_CMD`/);
60
68
  assert.match(enabledOverlay, /strongly prefer `omx explore`/);
61
69
  assert.match(enabledOverlay, /advisory steering/i);
62
70
  }
63
71
  finally {
64
- if (typeof previous === 'string')
72
+ if (typeof previous === "string")
65
73
  process.env.USE_OMX_EXPLORE_CMD = previous;
66
74
  else
67
75
  delete process.env.USE_OMX_EXPLORE_CMD;
68
76
  }
69
77
  });
70
- it('generates overlay with active modes', async () => {
71
- const sessionId = 'test-session-2';
72
- const sessionDir = join(tempDir, '.omx', 'state', 'sessions', sessionId);
78
+ it("generates overlay with active modes", async () => {
79
+ const sessionId = "test-session-2";
80
+ const sessionDir = join(tempDir, ".omx", "state", "sessions", sessionId);
73
81
  await mkdir(sessionDir, { recursive: true });
74
- await writeFile(join(sessionDir, 'ralph-state.json'), JSON.stringify({ active: true, iteration: 3, max_iterations: 10, current_phase: 'executing' }));
82
+ await writeFile(join(sessionDir, "ralph-state.json"), JSON.stringify({
83
+ active: true,
84
+ iteration: 3,
85
+ max_iterations: 10,
86
+ current_phase: "executing",
87
+ }));
75
88
  const overlay = await generateOverlay(tempDir, sessionId);
76
- assert.ok(overlay.includes('ralph'));
77
- assert.ok(overlay.includes('iteration 3/10'));
78
- });
79
- it('generates overlay with session-scoped active modes for current session', async () => {
80
- await mkdir(join(tempDir, '.omx', 'state', 'sessions', 'sess1'), { recursive: true });
81
- await writeFile(join(tempDir, '.omx', 'state', 'sessions', 'sess1', 'team-state.json'), JSON.stringify({ active: true, iteration: 1, max_iterations: 5, current_phase: 'running' }));
82
- const overlay = await generateOverlay(tempDir, 'sess1');
83
- assert.ok(overlay.includes('team'));
84
- assert.ok(overlay.includes('iteration 1/5'));
85
- });
86
- it('generates overlay with notepad priority content', async () => {
87
- await writeFile(join(tempDir, '.omx', 'notepad.md'), '## PRIORITY\nFocus on auth module refactor.\n\n## WORKING\nSome working notes.');
88
- const overlay = await generateOverlay(tempDir, 'test-session-3');
89
- assert.ok(overlay.includes('Focus on auth module refactor'));
90
- assert.ok(overlay.includes('Priority Notes'));
91
- });
92
- it('generates overlay with project memory summary', async () => {
93
- await writeFile(join(tempDir, '.omx', 'project-memory.json'), JSON.stringify({
94
- techStack: 'TypeScript + Node.js',
95
- conventions: 'ESM modules, strict mode',
96
- build: 'npx tsc',
89
+ assert.ok(overlay.includes("ralph"));
90
+ assert.ok(overlay.includes("iteration 3/10"));
91
+ });
92
+ it("generates overlay with session-scoped active modes for current session", async () => {
93
+ await mkdir(join(tempDir, ".omx", "state", "sessions", "sess1"), {
94
+ recursive: true,
95
+ });
96
+ await writeFile(join(tempDir, ".omx", "state", "sessions", "sess1", "team-state.json"), JSON.stringify({
97
+ active: true,
98
+ iteration: 1,
99
+ max_iterations: 5,
100
+ current_phase: "running",
101
+ }));
102
+ const overlay = await generateOverlay(tempDir, "sess1");
103
+ assert.ok(overlay.includes("team"));
104
+ assert.ok(overlay.includes("iteration 1/5"));
105
+ });
106
+ it("generates overlay with notepad priority content", async () => {
107
+ await writeFile(join(tempDir, ".omx", "notepad.md"), "## PRIORITY\nFocus on auth module refactor.\n\n## WORKING\nSome working notes.");
108
+ const overlay = await generateOverlay(tempDir, "test-session-3");
109
+ assert.ok(overlay.includes("Focus on auth module refactor"));
110
+ assert.ok(overlay.includes("Priority Notes"));
111
+ });
112
+ it("generates overlay with project memory summary", async () => {
113
+ await writeFile(join(tempDir, ".omx", "project-memory.json"), JSON.stringify({
114
+ techStack: "TypeScript + Node.js",
115
+ conventions: "ESM modules, strict mode",
116
+ build: "npx tsc",
97
117
  directives: [
98
- { directive: 'Always use strict TypeScript', priority: 'high' },
99
- { directive: 'Low priority thing', priority: 'normal' },
118
+ { directive: "Always use strict TypeScript", priority: "high" },
119
+ { directive: "Low priority thing", priority: "normal" },
100
120
  ],
101
121
  }));
102
- const overlay = await generateOverlay(tempDir, 'test-session-4');
103
- assert.ok(overlay.includes('TypeScript + Node.js'));
104
- assert.ok(overlay.includes('Always use strict TypeScript'));
105
- assert.ok(!overlay.includes('Low priority thing'));
106
- });
107
- it('enforces size cap (overlay <= 3500 chars)', async () => {
108
- const longText = 'A'.repeat(5000);
109
- await writeFile(join(tempDir, '.omx', 'notepad.md'), `## PRIORITY\n${longText}`);
110
- await writeFile(join(tempDir, '.omx', 'project-memory.json'), JSON.stringify({ techStack: 'B'.repeat(2000), conventions: 'C'.repeat(2000) }));
111
- const overlay = await generateOverlay(tempDir, 'test-session-5');
122
+ const overlay = await generateOverlay(tempDir, "test-session-4");
123
+ assert.ok(overlay.includes("TypeScript + Node.js"));
124
+ assert.ok(overlay.includes("Always use strict TypeScript"));
125
+ assert.ok(!overlay.includes("Low priority thing"));
126
+ });
127
+ it("enforces size cap (overlay <= 3500 chars)", async () => {
128
+ const longText = "A".repeat(5000);
129
+ await writeFile(join(tempDir, ".omx", "notepad.md"), `## PRIORITY\n${longText}`);
130
+ await writeFile(join(tempDir, ".omx", "project-memory.json"), JSON.stringify({
131
+ techStack: "B".repeat(2000),
132
+ conventions: "C".repeat(2000),
133
+ }));
134
+ const overlay = await generateOverlay(tempDir, "test-session-5");
112
135
  assert.ok(overlay.length <= 3500, `Overlay too large: ${overlay.length} chars`);
113
- assert.ok(overlay.includes('<!-- OMX:RUNTIME:START -->'));
114
- assert.ok(overlay.includes('<!-- OMX:RUNTIME:END -->'));
136
+ assert.ok(overlay.includes("<!-- OMX:RUNTIME:START -->"));
137
+ assert.ok(overlay.includes("<!-- OMX:RUNTIME:END -->"));
115
138
  });
116
- it('uses deterministic overflow policy under size cap', async () => {
117
- const sessionId = 'overflow-session';
118
- const sessionDir = join(tempDir, '.omx', 'state', 'sessions', sessionId);
139
+ it("uses deterministic overflow policy under size cap", async () => {
140
+ const sessionId = "overflow-session";
141
+ const sessionDir = join(tempDir, ".omx", "state", "sessions", sessionId);
119
142
  await mkdir(sessionDir, { recursive: true });
120
143
  // Inflate optional sections so overflow behavior is exercised.
121
144
  // Per-section truncation limits mean the total max body (~2640 chars) fits
122
145
  // within MAX_OVERLAY_SIZE (3500), so we verify: size cap, required sections
123
146
  // present, and determinism (identical output on repeated calls).
124
147
  for (let i = 0; i < 40; i++) {
125
- await writeFile(join(sessionDir, `mode-${i}-state.json`), JSON.stringify({ active: true, iteration: i + 1, max_iterations: 99, current_phase: 'run' }));
148
+ await writeFile(join(sessionDir, `mode-${i}-state.json`), JSON.stringify({
149
+ active: true,
150
+ iteration: i + 1,
151
+ max_iterations: 99,
152
+ current_phase: "run",
153
+ }));
126
154
  }
127
- await writeFile(join(tempDir, '.omx', 'notepad.md'), `## PRIORITY\n${'N'.repeat(8000)}`);
128
- await writeFile(join(tempDir, '.omx', 'project-memory.json'), JSON.stringify({
129
- techStack: 'T'.repeat(9000),
130
- conventions: 'C'.repeat(9000),
131
- directives: [{ directive: 'D'.repeat(3000), priority: 'high' }],
155
+ await writeFile(join(tempDir, ".omx", "notepad.md"), `## PRIORITY\n${"N".repeat(8000)}`);
156
+ await writeFile(join(tempDir, ".omx", "project-memory.json"), JSON.stringify({
157
+ techStack: "T".repeat(9000),
158
+ conventions: "C".repeat(9000),
159
+ directives: [{ directive: "D".repeat(3000), priority: "high" }],
132
160
  }));
133
161
  const overlay1 = await generateOverlay(tempDir, sessionId);
134
162
  const overlay2 = await generateOverlay(tempDir, sessionId);
135
163
  for (const overlay of [overlay1, overlay2]) {
136
164
  assert.ok(overlay.length <= 3500, `Overlay too large: ${overlay.length} chars`);
137
- assert.ok(overlay.includes('**Active Modes:**'));
138
- assert.ok(overlay.includes('**Priority Notes:**'));
139
- assert.ok(overlay.includes('**Compaction Protocol:**'));
165
+ assert.ok(overlay.includes("**Active Modes:**"));
166
+ assert.ok(overlay.includes("**Priority Notes:**"));
167
+ assert.ok(overlay.includes("**Compaction Protocol:**"));
140
168
  }
141
169
  });
142
- it('skips inactive modes', async () => {
143
- await writeFile(join(tempDir, '.omx', 'state', 'autopilot-state.json'), JSON.stringify({ active: false, current_phase: 'cancelled' }));
144
- const overlay = await generateOverlay(tempDir, 'test-session-6');
145
- assert.ok(!overlay.includes('autopilot'));
170
+ it("skips inactive modes", async () => {
171
+ await writeFile(join(tempDir, ".omx", "state", "autopilot-state.json"), JSON.stringify({ active: false, current_phase: "cancelled" }));
172
+ const overlay = await generateOverlay(tempDir, "test-session-6");
173
+ assert.ok(!overlay.includes("autopilot"));
146
174
  });
147
- it('adds blocked ralph planning gate when PRD/test spec are missing', async () => {
148
- const sessionId = 'ralph-gate-blocked';
149
- const sessionDir = join(tempDir, '.omx', 'state', 'sessions', sessionId);
175
+ it("adds blocked ralph planning gate when PRD/test spec are missing", async () => {
176
+ const sessionId = "ralph-gate-blocked";
177
+ const sessionDir = join(tempDir, ".omx", "state", "sessions", sessionId);
150
178
  await mkdir(sessionDir, { recursive: true });
151
- await writeFile(join(sessionDir, 'ralph-state.json'), JSON.stringify({ active: true, iteration: 0, max_iterations: 50, current_phase: 'starting' }));
152
- await mkdir(join(tempDir, '.omx', 'plans'), { recursive: true });
179
+ await writeFile(join(sessionDir, "ralph-state.json"), JSON.stringify({
180
+ active: true,
181
+ iteration: 0,
182
+ max_iterations: 50,
183
+ current_phase: "starting",
184
+ }));
185
+ await mkdir(join(tempDir, ".omx", "plans"), { recursive: true });
153
186
  const overlay = await generateOverlay(tempDir, sessionId);
154
187
  assert.match(overlay, /\*\*Ralph Ralplan-First Gate:\*\* BLOCKED/);
155
188
  assert.match(overlay, /`prd-\*\.md`/);
156
189
  assert.match(overlay, /`test-spec-\*\.md`/);
157
190
  });
158
- it('unlocks ralph planning gate when PRD and test spec exist', async () => {
159
- const sessionId = 'ralph-gate-unlocked';
160
- const sessionDir = join(tempDir, '.omx', 'state', 'sessions', sessionId);
191
+ it("unlocks ralph planning gate when PRD and test spec exist", async () => {
192
+ const sessionId = "ralph-gate-unlocked";
193
+ const sessionDir = join(tempDir, ".omx", "state", "sessions", sessionId);
161
194
  await mkdir(sessionDir, { recursive: true });
162
- await writeFile(join(sessionDir, 'ralph-state.json'), JSON.stringify({ active: true, iteration: 1, max_iterations: 50, current_phase: 'starting' }));
163
- const plansDir = join(tempDir, '.omx', 'plans');
195
+ await writeFile(join(sessionDir, "ralph-state.json"), JSON.stringify({
196
+ active: true,
197
+ iteration: 1,
198
+ max_iterations: 50,
199
+ current_phase: "starting",
200
+ }));
201
+ const plansDir = join(tempDir, ".omx", "plans");
164
202
  await mkdir(plansDir, { recursive: true });
165
- await writeFile(join(plansDir, 'prd-issue-259.md'), '# PRD\n');
166
- await writeFile(join(plansDir, 'test-spec-issue-259.md'), '# Test Spec\n');
203
+ await writeFile(join(plansDir, "prd-issue-259.md"), "# PRD\n");
204
+ await writeFile(join(plansDir, "test-spec-issue-259.md"), "# Test Spec\n");
167
205
  const overlay = await generateOverlay(tempDir, sessionId);
168
206
  assert.match(overlay, /\*\*Ralph Ralplan-First Gate:\*\* UNLOCKED/);
169
207
  assert.match(overlay, /Planning artifacts present: PRD \+ test spec/);
170
208
  });
171
209
  });
172
- describe('resolveSessionOrchestrationMode', () => {
210
+ describe("resolveSessionOrchestrationMode", () => {
173
211
  let tempDir;
174
- before(async () => { tempDir = await makeTempDir(); });
175
- after(async () => { await rm(tempDir, { recursive: true, force: true }); });
176
- it('uses explicit activeSkill when provided', async () => {
177
- const mode = await resolveSessionOrchestrationMode(tempDir, 'sess-explicit', 'team');
178
- assert.equal(mode, 'team');
179
- });
180
- it('reads persisted team skill state from the current session scope', async () => {
181
- const sessionId = 'sess-team';
182
- const sessionDir = join(tempDir, '.omx', 'state', 'sessions', sessionId);
212
+ before(async () => {
213
+ tempDir = await makeTempDir();
214
+ });
215
+ after(async () => {
216
+ await rm(tempDir, { recursive: true, force: true });
217
+ });
218
+ it("uses explicit activeSkill when provided", async () => {
219
+ const mode = await resolveSessionOrchestrationMode(tempDir, "sess-explicit", "team");
220
+ assert.equal(mode, "team");
221
+ });
222
+ it("reads persisted team skill state from the current session scope", async () => {
223
+ const sessionId = "sess-team";
224
+ const sessionDir = join(tempDir, ".omx", "state", "sessions", sessionId);
183
225
  await mkdir(sessionDir, { recursive: true });
184
- await writeFile(join(sessionDir, 'skill-active-state.json'), JSON.stringify({ active: true, skill: 'team' }));
226
+ await writeFile(join(sessionDir, "skill-active-state.json"), JSON.stringify({ active: true, skill: "team" }));
185
227
  const mode = await resolveSessionOrchestrationMode(tempDir, sessionId);
186
- assert.equal(mode, 'team');
228
+ assert.equal(mode, "team");
187
229
  });
188
- it('falls back to default mode for non-team skill state', async () => {
189
- const sessionId = 'sess-autopilot';
190
- const sessionDir = join(tempDir, '.omx', 'state', 'sessions', sessionId);
230
+ it("falls back to default mode for non-team skill state", async () => {
231
+ const sessionId = "sess-autopilot";
232
+ const sessionDir = join(tempDir, ".omx", "state", "sessions", sessionId);
191
233
  await mkdir(sessionDir, { recursive: true });
192
- await writeFile(join(sessionDir, 'skill-active-state.json'), JSON.stringify({ active: true, skill: 'autopilot' }));
234
+ await writeFile(join(sessionDir, "skill-active-state.json"), JSON.stringify({ active: true, skill: "autopilot" }));
193
235
  const mode = await resolveSessionOrchestrationMode(tempDir, sessionId);
194
- assert.equal(mode, 'default');
236
+ assert.equal(mode, "default");
195
237
  });
196
- it('does not resurrect stale root team skill state when session-scoped skill state is inactive', async () => {
197
- const sessionId = 'sess-team-complete';
198
- const rootStatePath = join(tempDir, '.omx', 'state', 'skill-active-state.json');
199
- const sessionDir = join(tempDir, '.omx', 'state', 'sessions', sessionId);
238
+ it("does not resurrect stale root team skill state when session-scoped skill state is inactive", async () => {
239
+ const sessionId = "sess-team-complete";
240
+ const rootStatePath = join(tempDir, ".omx", "state", "skill-active-state.json");
241
+ const sessionDir = join(tempDir, ".omx", "state", "sessions", sessionId);
200
242
  await mkdir(sessionDir, { recursive: true });
201
- await writeFile(rootStatePath, JSON.stringify({ active: true, skill: 'team' }));
202
- await writeFile(join(sessionDir, 'skill-active-state.json'), JSON.stringify({ active: false, skill: 'team', phase: 'completing' }));
243
+ await writeFile(rootStatePath, JSON.stringify({ active: true, skill: "team" }));
244
+ await writeFile(join(sessionDir, "skill-active-state.json"), JSON.stringify({ active: false, skill: "team", phase: "completing" }));
203
245
  const mode = await resolveSessionOrchestrationMode(tempDir, sessionId);
204
- assert.equal(mode, 'default');
246
+ assert.equal(mode, "default");
205
247
  });
206
- it('falls back to root team skill state only when no session-scoped skill state exists', async () => {
207
- const sessionId = 'sess-root-fallback';
208
- await writeFile(join(tempDir, '.omx', 'state', 'skill-active-state.json'), JSON.stringify({ active: true, skill: 'team' }));
248
+ it("falls back to root team skill state only when no session-scoped skill state exists", async () => {
249
+ const sessionId = "sess-root-fallback";
250
+ await writeFile(join(tempDir, ".omx", "state", "skill-active-state.json"), JSON.stringify({ active: true, skill: "team" }));
209
251
  const mode = await resolveSessionOrchestrationMode(tempDir, sessionId);
210
- assert.equal(mode, 'team');
252
+ assert.equal(mode, "team");
211
253
  });
212
254
  });
213
- describe('applyOverlay + stripOverlay roundtrip', () => {
255
+ describe("applyOverlay + stripOverlay roundtrip", () => {
214
256
  let tempDir;
215
257
  const originalContent = `# My AGENTS.md
216
258
 
@@ -219,65 +261,88 @@ This is the original content.
219
261
  ## Section 1
220
262
  Some instructions here.
221
263
  `;
222
- before(async () => { tempDir = await makeTempDir(); });
223
- after(async () => { await rm(tempDir, { recursive: true, force: true }); });
224
- it('apply then strip restores original (roundtrip)', async () => {
225
- const agentsMd = join(tempDir, 'AGENTS.md');
264
+ before(async () => {
265
+ tempDir = await makeTempDir();
266
+ });
267
+ after(async () => {
268
+ await rm(tempDir, { recursive: true, force: true });
269
+ });
270
+ it("apply then strip restores original (roundtrip)", async () => {
271
+ const agentsMd = join(tempDir, "AGENTS.md");
226
272
  await writeFile(agentsMd, originalContent);
227
- const overlay = await generateOverlay(tempDir, 'roundtrip-test');
273
+ const overlay = await generateOverlay(tempDir, "roundtrip-test");
228
274
  await applyOverlay(agentsMd, overlay, tempDir);
229
- const withOverlay = await readFile(agentsMd, 'utf-8');
275
+ const withOverlay = await readFile(agentsMd, "utf-8");
230
276
  assert.ok(hasOverlay(withOverlay));
231
- assert.ok(withOverlay.includes('roundtrip-test'));
277
+ assert.ok(withOverlay.includes("roundtrip-test"));
232
278
  await stripOverlay(agentsMd, tempDir);
233
- const restored = await readFile(agentsMd, 'utf-8');
279
+ const restored = await readFile(agentsMd, "utf-8");
234
280
  assert.ok(!hasOverlay(restored));
235
281
  assert.equal(restored.trim(), originalContent.trim());
236
282
  });
237
- it('applyOverlay is idempotent (apply twice, no duplication)', async () => {
238
- const agentsMd = join(tempDir, 'AGENTS-idem.md');
283
+ it("stripOverlay preserves a top-of-file autonomy directive header", async () => {
284
+ const agentsMd = join(tempDir, "AGENTS-autonomy.md");
285
+ const autonomyContent = `<!-- AUTONOMY DIRECTIVE — DO NOT REMOVE -->
286
+ YOU ARE AN AUTONOMOUS CODING AGENT. EXECUTE TASKS TO COMPLETION WITHOUT ASKING FOR PERMISSION.
287
+ DO NOT STOP TO ASK "SHOULD I PROCEED?" — PROCEED. DO NOT WAIT FOR CONFIRMATION ON OBVIOUS NEXT STEPS.
288
+ IF BLOCKED, TRY AN ALTERNATIVE APPROACH. ONLY ASK WHEN TRULY AMBIGUOUS OR DESTRUCTIVE.
289
+ <!-- END AUTONOMY DIRECTIVE -->
290
+
291
+ # oh-my-codex - Intelligent Multi-Agent Orchestration
292
+ `;
293
+ await writeFile(agentsMd, autonomyContent);
294
+ const overlay = await generateOverlay(tempDir, "autonomy-header");
295
+ await applyOverlay(agentsMd, overlay, tempDir);
296
+ await stripOverlay(agentsMd, tempDir);
297
+ const restored = await readFile(agentsMd, "utf-8");
298
+ assert.equal(restored, autonomyContent);
299
+ });
300
+ it("applyOverlay is idempotent (apply twice, no duplication)", async () => {
301
+ const agentsMd = join(tempDir, "AGENTS-idem.md");
239
302
  await writeFile(agentsMd, originalContent);
240
- const overlay = await generateOverlay(tempDir, 'idempotent-test');
303
+ const overlay = await generateOverlay(tempDir, "idempotent-test");
241
304
  await applyOverlay(agentsMd, overlay, tempDir);
242
- const firstApply = await readFile(agentsMd, 'utf-8');
305
+ const firstApply = await readFile(agentsMd, "utf-8");
243
306
  await applyOverlay(agentsMd, overlay, tempDir);
244
- const secondApply = await readFile(agentsMd, 'utf-8');
307
+ const secondApply = await readFile(agentsMd, "utf-8");
245
308
  assert.equal(secondApply, firstApply);
246
- const startCount = (secondApply.match(/<!-- OMX:RUNTIME:START -->/g) || []).length;
309
+ const startCount = (secondApply.match(/<!-- OMX:RUNTIME:START -->/g) || [])
310
+ .length;
247
311
  assert.equal(startCount, 1);
248
312
  });
249
- it('handles stale markers from previous session', async () => {
250
- const agentsMd = join(tempDir, 'AGENTS-stale.md');
313
+ it("handles stale markers from previous session", async () => {
314
+ const agentsMd = join(tempDir, "AGENTS-stale.md");
251
315
  const staleContent = originalContent +
252
- '\n<!-- OMX:RUNTIME:START -->\n<session_context>\nOld stale content\n</session_context>\n<!-- OMX:RUNTIME:END -->\n';
316
+ "\n<!-- OMX:RUNTIME:START -->\n<session_context>\nOld stale content\n</session_context>\n<!-- OMX:RUNTIME:END -->\n";
253
317
  await writeFile(agentsMd, staleContent);
254
- const overlay = await generateOverlay(tempDir, 'fresh-session');
318
+ const overlay = await generateOverlay(tempDir, "fresh-session");
255
319
  await applyOverlay(agentsMd, overlay, tempDir);
256
- const result = await readFile(agentsMd, 'utf-8');
257
- assert.ok(result.includes('fresh-session'));
258
- assert.ok(!result.includes('Old stale content'));
259
- const startCount = (result.match(/<!-- OMX:RUNTIME:START -->/g) || []).length;
320
+ const result = await readFile(agentsMd, "utf-8");
321
+ assert.ok(result.includes("fresh-session"));
322
+ assert.ok(!result.includes("Old stale content"));
323
+ const startCount = (result.match(/<!-- OMX:RUNTIME:START -->/g) || [])
324
+ .length;
260
325
  assert.equal(startCount, 1);
261
326
  });
262
- it('stripOverlay is no-op when no overlay exists', async () => {
263
- const agentsMd = join(tempDir, 'AGENTS-noop.md');
327
+ it("stripOverlay is no-op when no overlay exists", async () => {
328
+ const agentsMd = join(tempDir, "AGENTS-noop.md");
264
329
  await writeFile(agentsMd, originalContent);
265
330
  await stripOverlay(agentsMd, tempDir);
266
- const result = await readFile(agentsMd, 'utf-8');
331
+ const result = await readFile(agentsMd, "utf-8");
267
332
  assert.equal(result, originalContent);
268
333
  });
269
- it('creates AGENTS.md if it does not exist during apply', async () => {
270
- const agentsMd = join(tempDir, 'AGENTS-new.md');
271
- const overlay = await generateOverlay(tempDir, 'new-file-test');
334
+ it("creates AGENTS.md if it does not exist during apply", async () => {
335
+ const agentsMd = join(tempDir, "AGENTS-new.md");
336
+ const overlay = await generateOverlay(tempDir, "new-file-test");
272
337
  await applyOverlay(agentsMd, overlay, tempDir);
273
- const result = await readFile(agentsMd, 'utf-8');
338
+ const result = await readFile(agentsMd, "utf-8");
274
339
  assert.ok(hasOverlay(result));
275
- assert.ok(result.includes('new-file-test'));
340
+ assert.ok(result.includes("new-file-test"));
276
341
  });
277
- it('stripOverlay removes runtime overlay and preserves worker overlay (runtime->worker order)', async () => {
278
- const agentsMd = join(tempDir, 'AGENTS-stacked-rw.md');
342
+ it("stripOverlay removes runtime overlay and preserves worker overlay (runtime->worker order)", async () => {
343
+ const agentsMd = join(tempDir, "AGENTS-stacked-rw.md");
279
344
  await writeFile(agentsMd, originalContent);
280
- const runtimeOverlay = await generateOverlay(tempDir, 'stacked-rw');
345
+ const runtimeOverlay = await generateOverlay(tempDir, "stacked-rw");
281
346
  await applyOverlay(agentsMd, runtimeOverlay, tempDir);
282
347
  const workerOverlay = `${WORKER_START}
283
348
  <team_worker_protocol>
@@ -285,17 +350,17 @@ worker protocol body
285
350
  </team_worker_protocol>
286
351
  ${WORKER_END}
287
352
  `;
288
- const withRuntime = await readFile(agentsMd, 'utf-8');
353
+ const withRuntime = await readFile(agentsMd, "utf-8");
289
354
  await writeFile(agentsMd, `${withRuntime.trimEnd()}\n\n${workerOverlay}`);
290
355
  await stripOverlay(agentsMd, tempDir);
291
- const result = await readFile(agentsMd, 'utf-8');
356
+ const result = await readFile(agentsMd, "utf-8");
292
357
  assert.ok(!result.includes(RUNTIME_START));
293
358
  assert.ok(!result.includes(RUNTIME_END));
294
359
  assert.ok(result.includes(WORKER_START));
295
360
  assert.ok(result.includes(WORKER_END));
296
361
  });
297
- it('stripOverlay removes runtime overlay and preserves worker overlay (worker->runtime order)', async () => {
298
- const agentsMd = join(tempDir, 'AGENTS-stacked-wr.md');
362
+ it("stripOverlay removes runtime overlay and preserves worker overlay (worker->runtime order)", async () => {
363
+ const agentsMd = join(tempDir, "AGENTS-stacked-wr.md");
299
364
  const workerOverlay = `${WORKER_START}
300
365
  <team_worker_protocol>
301
366
  worker protocol body
@@ -303,17 +368,17 @@ worker protocol body
303
368
  ${WORKER_END}
304
369
  `;
305
370
  await writeFile(agentsMd, `${originalContent.trimEnd()}\n\n${workerOverlay}`);
306
- const runtimeOverlay = await generateOverlay(tempDir, 'stacked-wr');
371
+ const runtimeOverlay = await generateOverlay(tempDir, "stacked-wr");
307
372
  await applyOverlay(agentsMd, runtimeOverlay, tempDir);
308
373
  await stripOverlay(agentsMd, tempDir);
309
- const result = await readFile(agentsMd, 'utf-8');
374
+ const result = await readFile(agentsMd, "utf-8");
310
375
  assert.ok(!result.includes(RUNTIME_START));
311
376
  assert.ok(!result.includes(RUNTIME_END));
312
377
  assert.ok(result.includes(WORKER_START));
313
378
  assert.ok(result.includes(WORKER_END));
314
379
  });
315
- it('stripOverlay removes duplicate runtime marker blocks', async () => {
316
- const agentsMd = join(tempDir, 'AGENTS-duplicate-runtime.md');
380
+ it("stripOverlay removes duplicate runtime marker blocks", async () => {
381
+ const agentsMd = join(tempDir, "AGENTS-duplicate-runtime.md");
317
382
  const dup = `${originalContent.trimEnd()}
318
383
 
319
384
  ${RUNTIME_START}
@@ -326,13 +391,13 @@ ${RUNTIME_END}
326
391
  `;
327
392
  await writeFile(agentsMd, dup);
328
393
  await stripOverlay(agentsMd, tempDir);
329
- const result = await readFile(agentsMd, 'utf-8');
394
+ const result = await readFile(agentsMd, "utf-8");
330
395
  assert.ok(!result.includes(RUNTIME_START));
331
396
  assert.ok(!result.includes(RUNTIME_END));
332
397
  assert.equal(result.trim(), originalContent.trim());
333
398
  });
334
- it('stripOverlay handles malformed runtime start marker without deleting worker overlay', async () => {
335
- const agentsMd = join(tempDir, 'AGENTS-malformed-runtime.md');
399
+ it("stripOverlay handles malformed runtime start marker without deleting worker overlay", async () => {
400
+ const agentsMd = join(tempDir, "AGENTS-malformed-runtime.md");
336
401
  const malformed = `${originalContent.trimEnd()}
337
402
 
338
403
  ${RUNTIME_START}
@@ -347,99 +412,99 @@ ${WORKER_END}
347
412
  `;
348
413
  await writeFile(agentsMd, malformed);
349
414
  await stripOverlay(agentsMd, tempDir);
350
- const result = await readFile(agentsMd, 'utf-8');
415
+ const result = await readFile(agentsMd, "utf-8");
351
416
  assert.ok(!result.includes(RUNTIME_START));
352
417
  assert.ok(result.includes(WORKER_START));
353
418
  assert.ok(result.includes(WORKER_END));
354
419
  });
355
420
  });
356
- describe('session-scoped model instructions file', () => {
421
+ describe("session-scoped model instructions file", () => {
357
422
  let tempDir;
358
423
  let restoreCodexHome;
359
424
  before(async () => {
360
425
  tempDir = await makeTempDir();
361
- restoreCodexHome = setMockCodexHome(join(tempDir, 'home', '.codex'));
426
+ restoreCodexHome = setMockCodexHome(join(tempDir, "home", ".codex"));
362
427
  });
363
428
  after(async () => {
364
429
  restoreCodexHome?.();
365
430
  await rm(tempDir, { recursive: true, force: true });
366
431
  });
367
- it('writes user + project AGENTS.md + runtime overlay into session-scoped file', async () => {
368
- const userAgentsMd = join(tempDir, 'home', '.codex', 'AGENTS.md');
369
- const projectAgentsMd = join(tempDir, 'AGENTS.md');
370
- await mkdir(join(tempDir, 'home', '.codex'), { recursive: true });
371
- await writeFile(userAgentsMd, '# User instructions\n\nStart globally.\n');
372
- const projectContent = '# Project instructions\n\nStay in scope.\n';
432
+ it("writes user + project AGENTS.md + runtime overlay into session-scoped file", async () => {
433
+ const userAgentsMd = join(tempDir, "home", ".codex", "AGENTS.md");
434
+ const projectAgentsMd = join(tempDir, "AGENTS.md");
435
+ await mkdir(join(tempDir, "home", ".codex"), { recursive: true });
436
+ await writeFile(userAgentsMd, "# User instructions\n\nStart globally.\n");
437
+ const projectContent = "# Project instructions\n\nStay in scope.\n";
373
438
  await writeFile(projectAgentsMd, projectContent);
374
- const overlay = await generateOverlay(tempDir, 'session-a');
375
- const writtenPath = await writeSessionModelInstructionsFile(tempDir, 'session-a', overlay);
376
- const sessionContent = await readFile(writtenPath, 'utf-8');
377
- const projectAfter = await readFile(projectAgentsMd, 'utf-8');
378
- assert.equal(writtenPath, sessionModelInstructionsPath(tempDir, 'session-a'));
439
+ const overlay = await generateOverlay(tempDir, "session-a");
440
+ const writtenPath = await writeSessionModelInstructionsFile(tempDir, "session-a", overlay);
441
+ const sessionContent = await readFile(writtenPath, "utf-8");
442
+ const projectAfter = await readFile(projectAgentsMd, "utf-8");
443
+ assert.equal(writtenPath, sessionModelInstructionsPath(tempDir, "session-a"));
379
444
  assert.match(sessionContent, /# User instructions/);
380
445
  assert.match(sessionContent, /# Project instructions/);
381
- assert.ok(sessionContent.indexOf('# User instructions') <
382
- sessionContent.indexOf('# Project instructions'));
446
+ assert.ok(sessionContent.indexOf("# User instructions") <
447
+ sessionContent.indexOf("# Project instructions"));
383
448
  assert.match(sessionContent, /<!-- OMX:RUNTIME:START -->/);
384
449
  assert.equal(projectAfter, projectContent);
385
450
  });
386
- it('deduplicates duplicate skill references when project and user scopes both install the same skill', async () => {
387
- const userAgentsMd = join(tempDir, 'home', '.codex', 'AGENTS.md');
388
- const projectAgentsMd = join(tempDir, 'AGENTS.md');
389
- const userSkillDir = join(tempDir, 'home', '.codex', 'skills', 'help');
390
- const projectSkillDir = join(tempDir, '.agents', 'skills', 'help');
391
- await mkdir(join(tempDir, 'home', '.codex'), { recursive: true });
451
+ it("deduplicates duplicate skill references when project and user scopes both install the same skill", async () => {
452
+ const userAgentsMd = join(tempDir, "home", ".codex", "AGENTS.md");
453
+ const projectAgentsMd = join(tempDir, "AGENTS.md");
454
+ const userSkillDir = join(tempDir, "home", ".codex", "skills", "help");
455
+ const projectSkillDir = join(tempDir, ".codex", "skills", "help");
456
+ await mkdir(join(tempDir, "home", ".codex"), { recursive: true });
392
457
  await mkdir(userSkillDir, { recursive: true });
393
458
  await mkdir(projectSkillDir, { recursive: true });
394
- await writeFile(join(userSkillDir, 'SKILL.md'), '# user help\n');
395
- await writeFile(join(projectSkillDir, 'SKILL.md'), '# project help\n');
459
+ await writeFile(join(userSkillDir, "SKILL.md"), "# user help\n");
460
+ await writeFile(join(projectSkillDir, "SKILL.md"), "# project help\n");
396
461
  await writeFile(userAgentsMd, [
397
- '# User instructions',
398
- '',
399
- '- help: user copy (file: /tmp/home/.codex/skills/help/SKILL.md)',
400
- ].join('\n'));
462
+ "# User instructions",
463
+ "",
464
+ "- help: user copy (file: /tmp/home/.codex/skills/help/SKILL.md)",
465
+ ].join("\n"));
401
466
  await writeFile(projectAgentsMd, [
402
- '# Project instructions',
403
- '',
404
- '- help: project copy (file: /tmp/project/.agents/skills/help/SKILL.md)',
405
- ].join('\n'));
406
- const overlay = await generateOverlay(tempDir, 'session-dedupe');
407
- const writtenPath = await writeSessionModelInstructionsFile(tempDir, 'session-dedupe', overlay);
408
- const sessionContent = await readFile(writtenPath, 'utf-8');
467
+ "# Project instructions",
468
+ "",
469
+ "- help: project copy (file: /tmp/project/.codex/skills/help/SKILL.md)",
470
+ ].join("\n"));
471
+ const overlay = await generateOverlay(tempDir, "session-dedupe");
472
+ const writtenPath = await writeSessionModelInstructionsFile(tempDir, "session-dedupe", overlay);
473
+ const sessionContent = await readFile(writtenPath, "utf-8");
409
474
  assert.equal((sessionContent.match(/skills\/help\/SKILL\.md/g) || []).length, 1);
410
475
  assert.doesNotMatch(sessionContent, /user copy/);
411
476
  assert.match(sessionContent, /project copy/);
412
477
  });
413
- it('writes overlay-only session file when no base AGENTS.md files exist', async () => {
414
- await rm(join(tempDir, 'home'), { recursive: true, force: true });
415
- await rm(join(tempDir, 'AGENTS.md'), { force: true });
416
- const overlay = await generateOverlay(tempDir, 'session-b');
417
- const writtenPath = await writeSessionModelInstructionsFile(tempDir, 'session-b', overlay);
418
- const sessionContent = await readFile(writtenPath, 'utf-8');
419
- assert.ok(sessionContent.includes('<!-- OMX:RUNTIME:START -->'));
420
- assert.ok(sessionContent.includes('<!-- OMX:RUNTIME:END -->'));
421
- });
422
- it('removes session-scoped file without touching project AGENTS.md', async () => {
423
- const projectAgentsMd = join(tempDir, 'AGENTS.md');
424
- const projectContent = '# Keep me unchanged\n';
478
+ it("writes overlay-only session file when no base AGENTS.md files exist", async () => {
479
+ await rm(join(tempDir, "home"), { recursive: true, force: true });
480
+ await rm(join(tempDir, "AGENTS.md"), { force: true });
481
+ const overlay = await generateOverlay(tempDir, "session-b");
482
+ const writtenPath = await writeSessionModelInstructionsFile(tempDir, "session-b", overlay);
483
+ const sessionContent = await readFile(writtenPath, "utf-8");
484
+ assert.ok(sessionContent.includes("<!-- OMX:RUNTIME:START -->"));
485
+ assert.ok(sessionContent.includes("<!-- OMX:RUNTIME:END -->"));
486
+ });
487
+ it("removes session-scoped file without touching project AGENTS.md", async () => {
488
+ const projectAgentsMd = join(tempDir, "AGENTS.md");
489
+ const projectContent = "# Keep me unchanged\n";
425
490
  await writeFile(projectAgentsMd, projectContent);
426
- const overlay = await generateOverlay(tempDir, 'session-c');
427
- const writtenPath = await writeSessionModelInstructionsFile(tempDir, 'session-c', overlay);
428
- await removeSessionModelInstructionsFile(tempDir, 'session-c');
491
+ const overlay = await generateOverlay(tempDir, "session-c");
492
+ const writtenPath = await writeSessionModelInstructionsFile(tempDir, "session-c", overlay);
493
+ await removeSessionModelInstructionsFile(tempDir, "session-c");
429
494
  assert.equal(existsSync(writtenPath), false);
430
- assert.equal(await readFile(projectAgentsMd, 'utf-8'), projectContent);
495
+ assert.equal(await readFile(projectAgentsMd, "utf-8"), projectContent);
431
496
  });
432
497
  });
433
- describe('hasOverlay', () => {
434
- it('returns true when both markers present', () => {
435
- const content = 'start\n<!-- OMX:RUNTIME:START -->\nmiddle\n<!-- OMX:RUNTIME:END -->\nend';
498
+ describe("hasOverlay", () => {
499
+ it("returns true when both markers present", () => {
500
+ const content = "start\n<!-- OMX:RUNTIME:START -->\nmiddle\n<!-- OMX:RUNTIME:END -->\nend";
436
501
  assert.ok(hasOverlay(content));
437
502
  });
438
- it('returns false when no markers', () => {
439
- assert.ok(!hasOverlay('plain content'));
503
+ it("returns false when no markers", () => {
504
+ assert.ok(!hasOverlay("plain content"));
440
505
  });
441
- it('returns false when only start marker', () => {
442
- assert.ok(!hasOverlay('<!-- OMX:RUNTIME:START -->\nbroken'));
506
+ it("returns false when only start marker", () => {
507
+ assert.ok(!hasOverlay("<!-- OMX:RUNTIME:START -->\nbroken"));
443
508
  });
444
509
  });
445
510
  //# sourceMappingURL=agents-overlay.test.js.map