oh-my-codex 0.20.2 → 0.20.3

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 (367) hide show
  1. package/Cargo.lock +7 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +26 -0
  4. package/crates/omx-runtime/Cargo.toml +1 -0
  5. package/crates/omx-runtime/src/main.rs +25 -2
  6. package/crates/omx-runtime/tests/execution.rs +219 -0
  7. package/crates/omx-runtime-core/src/dispatch.rs +96 -10
  8. package/crates/omx-runtime-core/src/engine.rs +839 -29
  9. package/crates/omx-runtime-core/src/lib.rs +8 -0
  10. package/dist/agents/__tests__/definitions.test.js +81 -0
  11. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  12. package/dist/agents/__tests__/native-config.test.js +25 -0
  13. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  14. package/dist/agents/native-config.d.ts +2 -1
  15. package/dist/agents/native-config.d.ts.map +1 -1
  16. package/dist/agents/native-config.js.map +1 -1
  17. package/dist/auth/hotswap.d.ts +6 -0
  18. package/dist/auth/hotswap.d.ts.map +1 -1
  19. package/dist/auth/hotswap.js +85 -15
  20. package/dist/auth/hotswap.js.map +1 -1
  21. package/dist/autopilot/__tests__/ralplan-gate.test.js +1 -1
  22. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  23. package/dist/cli/__tests__/auth.test.js +60 -6
  24. package/dist/cli/__tests__/auth.test.js.map +1 -1
  25. package/dist/cli/__tests__/codex-plugin-layout.test.js +80 -0
  26. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  27. package/dist/cli/__tests__/doctor-warning-copy.test.js +103 -1
  28. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  29. package/dist/cli/__tests__/exec.test.js +136 -0
  30. package/dist/cli/__tests__/exec.test.js.map +1 -1
  31. package/dist/cli/__tests__/index.test.js +258 -4
  32. package/dist/cli/__tests__/index.test.js.map +1 -1
  33. package/dist/cli/__tests__/launch-fallback.test.js +287 -1
  34. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  35. package/dist/cli/__tests__/mcp-parity.test.js +4 -1
  36. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  37. package/dist/cli/__tests__/native-hook-claim-journal.test.js +84 -6
  38. package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -1
  39. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +3 -3
  40. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  41. package/dist/cli/__tests__/ralph.test.js +3 -3
  42. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  43. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +56 -171
  44. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -1
  45. package/dist/cli/__tests__/ralplan.test.js +37 -111
  46. package/dist/cli/__tests__/ralplan.test.js.map +1 -1
  47. package/dist/cli/__tests__/resume.test.js +11 -10
  48. package/dist/cli/__tests__/resume.test.js.map +1 -1
  49. package/dist/cli/__tests__/session-search-help.test.js +25 -1
  50. package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
  51. package/dist/cli/__tests__/setup-install-mode.test.js +42 -4
  52. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  53. package/dist/cli/__tests__/team.test.js +105 -7
  54. package/dist/cli/__tests__/team.test.js.map +1 -1
  55. package/dist/cli/__tests__/uninstall.test.js +46 -0
  56. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  57. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +2 -1
  58. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
  59. package/dist/cli/doctor.d.ts +3 -0
  60. package/dist/cli/doctor.d.ts.map +1 -1
  61. package/dist/cli/doctor.js +15 -2
  62. package/dist/cli/doctor.js.map +1 -1
  63. package/dist/cli/index.d.ts +4 -1
  64. package/dist/cli/index.d.ts.map +1 -1
  65. package/dist/cli/index.js +138 -38
  66. package/dist/cli/index.js.map +1 -1
  67. package/dist/cli/mcp-parity.js +2 -2
  68. package/dist/cli/mcp-parity.js.map +1 -1
  69. package/dist/cli/native-hook-claim-journal.d.ts +16 -5
  70. package/dist/cli/native-hook-claim-journal.d.ts.map +1 -1
  71. package/dist/cli/native-hook-claim-journal.js +42 -29
  72. package/dist/cli/native-hook-claim-journal.js.map +1 -1
  73. package/dist/cli/ralph.js +2 -2
  74. package/dist/cli/ralph.js.map +1 -1
  75. package/dist/cli/ralplan.d.ts +4 -8
  76. package/dist/cli/ralplan.d.ts.map +1 -1
  77. package/dist/cli/ralplan.js +19 -112
  78. package/dist/cli/ralplan.js.map +1 -1
  79. package/dist/cli/session-search.d.ts +5 -0
  80. package/dist/cli/session-search.d.ts.map +1 -1
  81. package/dist/cli/session-search.js +87 -0
  82. package/dist/cli/session-search.js.map +1 -1
  83. package/dist/cli/setup.d.ts +5 -0
  84. package/dist/cli/setup.d.ts.map +1 -1
  85. package/dist/cli/setup.js +80 -31
  86. package/dist/cli/setup.js.map +1 -1
  87. package/dist/cli/uninstall.d.ts +9 -0
  88. package/dist/cli/uninstall.d.ts.map +1 -1
  89. package/dist/cli/uninstall.js +61 -19
  90. package/dist/cli/uninstall.js.map +1 -1
  91. package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
  92. package/dist/config/__tests__/generator-idempotent.test.js +330 -1
  93. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  94. package/dist/config/__tests__/generator-notify.test.js +2 -2
  95. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  96. package/dist/config/__tests__/models.test.js +67 -3
  97. package/dist/config/__tests__/models.test.js.map +1 -1
  98. package/dist/config/generator.d.ts +4 -20
  99. package/dist/config/generator.d.ts.map +1 -1
  100. package/dist/config/generator.js +499 -119
  101. package/dist/config/generator.js.map +1 -1
  102. package/dist/config/models.d.ts +12 -2
  103. package/dist/config/models.d.ts.map +1 -1
  104. package/dist/config/models.js +15 -1
  105. package/dist/config/models.js.map +1 -1
  106. package/dist/hooks/__tests__/agents-overlay.test.js +2 -2
  107. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  108. package/dist/hooks/__tests__/keyword-detector.test.js +4 -4
  109. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  110. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +238 -543
  111. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  112. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +38 -4
  113. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  114. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +96 -9
  115. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  116. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +531 -12
  117. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  118. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +155 -23
  119. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  120. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +482 -32
  121. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  122. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +68 -1
  123. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  124. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +7 -1
  125. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
  126. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +43 -4
  127. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  128. package/dist/hooks/__tests__/session.test.js +348 -2
  129. package/dist/hooks/__tests__/session.test.js.map +1 -1
  130. package/dist/hooks/agents-overlay.js +1 -1
  131. package/dist/hooks/session.d.ts +26 -2
  132. package/dist/hooks/session.d.ts.map +1 -1
  133. package/dist/hooks/session.js +169 -13
  134. package/dist/hooks/session.js.map +1 -1
  135. package/dist/leader/__tests__/contract.test.js +57 -7
  136. package/dist/leader/__tests__/contract.test.js.map +1 -1
  137. package/dist/leader/contract.d.ts +16 -0
  138. package/dist/leader/contract.d.ts.map +1 -1
  139. package/dist/leader/contract.js +79 -4
  140. package/dist/leader/contract.js.map +1 -1
  141. package/dist/mcp/__tests__/code-intel-server.test.js +31 -3
  142. package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -1
  143. package/dist/mcp/__tests__/wiki-server.test.js +18 -0
  144. package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
  145. package/dist/mcp/code-intel-server.d.ts.map +1 -1
  146. package/dist/mcp/code-intel-server.js +13 -3
  147. package/dist/mcp/code-intel-server.js.map +1 -1
  148. package/dist/mcp/wiki-server.d.ts +11 -0
  149. package/dist/mcp/wiki-server.d.ts.map +1 -1
  150. package/dist/mcp/wiki-server.js +9 -2
  151. package/dist/mcp/wiki-server.js.map +1 -1
  152. package/dist/modes/__tests__/base-tmux-pane.test.js +4 -4
  153. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  154. package/dist/notifications/temp-contract.d.ts.map +1 -1
  155. package/dist/notifications/temp-contract.js +4 -0
  156. package/dist/notifications/temp-contract.js.map +1 -1
  157. package/dist/pipeline/__tests__/orchestrator.test.js +4 -4
  158. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  159. package/dist/pipeline/__tests__/stages.test.js +8 -8
  160. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  161. package/dist/ralplan/__tests__/consensus-gate.test.js +134 -10
  162. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
  163. package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts +2 -0
  164. package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts.map +1 -0
  165. package/dist/ralplan/__tests__/documented-leader-preflight.test.js +46 -0
  166. package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
  167. package/dist/ralplan/__tests__/runtime.test.js +8 -4
  168. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  169. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  170. package/dist/ralplan/consensus-gate.js +58 -50
  171. package/dist/ralplan/consensus-gate.js.map +1 -1
  172. package/dist/ralplan/documented-leader-preflight.d.ts +34 -0
  173. package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
  174. package/dist/ralplan/documented-leader-preflight.js +58 -0
  175. package/dist/ralplan/documented-leader-preflight.js.map +1 -0
  176. package/dist/ralplan/runtime.d.ts +1 -0
  177. package/dist/ralplan/runtime.d.ts.map +1 -1
  178. package/dist/ralplan/runtime.js +11 -7
  179. package/dist/ralplan/runtime.js.map +1 -1
  180. package/dist/runtime/__tests__/bridge.test.js +42 -1
  181. package/dist/runtime/__tests__/bridge.test.js.map +1 -1
  182. package/dist/runtime/bridge.d.ts +12 -0
  183. package/dist/runtime/bridge.d.ts.map +1 -1
  184. package/dist/runtime/bridge.js +52 -1
  185. package/dist/runtime/bridge.js.map +1 -1
  186. package/dist/scripts/__tests__/codex-native-hook.test.js +2620 -487
  187. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  188. package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts +2 -0
  189. package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts.map +1 -0
  190. package/dist/scripts/__tests__/reasoning-artifact-contract.test.js +108 -0
  191. package/dist/scripts/__tests__/reasoning-artifact-contract.test.js.map +1 -0
  192. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +46 -173
  193. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -1
  194. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +39 -159
  195. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -1
  196. package/dist/scripts/__tests__/smoke-packed-install.test.js +254 -2
  197. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
  198. package/dist/scripts/codex-native-hook.d.ts +4 -1
  199. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  200. package/dist/scripts/codex-native-hook.js +11013 -1153
  201. package/dist/scripts/codex-native-hook.js.map +1 -1
  202. package/dist/scripts/notify-fallback-watcher.js +82 -108
  203. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  204. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  205. package/dist/scripts/notify-hook/auto-nudge.js +74 -3
  206. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  207. package/dist/scripts/notify-hook/team-dispatch.d.ts +9 -0
  208. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  209. package/dist/scripts/notify-hook/team-dispatch.js +234 -79
  210. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  211. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  212. package/dist/scripts/notify-hook/team-leader-nudge.js +39 -13
  213. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  214. package/dist/scripts/notify-hook/team-tmux-guard.d.ts +12 -4
  215. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  216. package/dist/scripts/notify-hook/team-tmux-guard.js +365 -44
  217. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  218. package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
  219. package/dist/scripts/notify-hook/team-worker-stop.js +19 -18
  220. package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
  221. package/dist/scripts/notify-hook/team-worker.d.ts +3 -0
  222. package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
  223. package/dist/scripts/notify-hook/team-worker.js +37 -28
  224. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  225. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  226. package/dist/scripts/notify-hook/tmux-injection.js +28 -2
  227. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  228. package/dist/scripts/notify-hook.js +1 -0
  229. package/dist/scripts/notify-hook.js.map +1 -1
  230. package/dist/scripts/smoke-packed-install.d.ts +48 -3
  231. package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
  232. package/dist/scripts/smoke-packed-install.js +2796 -13
  233. package/dist/scripts/smoke-packed-install.js.map +1 -1
  234. package/dist/state/__tests__/mode-state-context.test.js +54 -0
  235. package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
  236. package/dist/state/__tests__/operations.test.js +2 -0
  237. package/dist/state/__tests__/operations.test.js.map +1 -1
  238. package/dist/state/mode-state-context.d.ts +5 -0
  239. package/dist/state/mode-state-context.d.ts.map +1 -1
  240. package/dist/state/mode-state-context.js +59 -0
  241. package/dist/state/mode-state-context.js.map +1 -1
  242. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +24 -245
  243. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -1
  244. package/dist/subagents/tracker.d.ts +1 -82
  245. package/dist/subagents/tracker.d.ts.map +1 -1
  246. package/dist/subagents/tracker.js +3 -275
  247. package/dist/subagents/tracker.js.map +1 -1
  248. package/dist/team/__tests__/api-interop.test.js +91 -1
  249. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  250. package/dist/team/__tests__/delivery-e2e-smoke.test.js +52 -10
  251. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
  252. package/dist/team/__tests__/idle-nudge.test.js +45 -15
  253. package/dist/team/__tests__/idle-nudge.test.js.map +1 -1
  254. package/dist/team/__tests__/mcp-comm.test.js +93 -27
  255. package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
  256. package/dist/team/__tests__/model-contract.test.js +110 -3
  257. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  258. package/dist/team/__tests__/runtime-cli.test.js +9 -0
  259. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  260. package/dist/team/__tests__/runtime.test.js +3204 -335
  261. package/dist/team/__tests__/runtime.test.js.map +1 -1
  262. package/dist/team/__tests__/scaling.test.js +2359 -142
  263. package/dist/team/__tests__/scaling.test.js.map +1 -1
  264. package/dist/team/__tests__/state.test.js +804 -36
  265. package/dist/team/__tests__/state.test.js.map +1 -1
  266. package/dist/team/__tests__/team-ops-contract.test.js +6 -0
  267. package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
  268. package/dist/team/__tests__/tmux-session.test.js +3049 -784
  269. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  270. package/dist/team/__tests__/worker-runtime-identity.test.js +38 -2
  271. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  272. package/dist/team/__tests__/worktree.test.js +6 -0
  273. package/dist/team/__tests__/worktree.test.js.map +1 -1
  274. package/dist/team/api-interop.d.ts.map +1 -1
  275. package/dist/team/api-interop.js +15 -9
  276. package/dist/team/api-interop.js.map +1 -1
  277. package/dist/team/exact-pane.d.ts +23 -0
  278. package/dist/team/exact-pane.d.ts.map +1 -0
  279. package/dist/team/exact-pane.js +133 -0
  280. package/dist/team/exact-pane.js.map +1 -0
  281. package/dist/team/idle-nudge.d.ts +12 -1
  282. package/dist/team/idle-nudge.d.ts.map +1 -1
  283. package/dist/team/idle-nudge.js +41 -14
  284. package/dist/team/idle-nudge.js.map +1 -1
  285. package/dist/team/model-contract.d.ts +2 -5
  286. package/dist/team/model-contract.d.ts.map +1 -1
  287. package/dist/team/model-contract.js +59 -17
  288. package/dist/team/model-contract.js.map +1 -1
  289. package/dist/team/runtime.d.ts +1 -0
  290. package/dist/team/runtime.d.ts.map +1 -1
  291. package/dist/team/runtime.js +1244 -180
  292. package/dist/team/runtime.js.map +1 -1
  293. package/dist/team/scaling.d.ts +13 -1
  294. package/dist/team/scaling.d.ts.map +1 -1
  295. package/dist/team/scaling.js +1430 -384
  296. package/dist/team/scaling.js.map +1 -1
  297. package/dist/team/state/dispatch.d.ts.map +1 -1
  298. package/dist/team/state/dispatch.js +26 -8
  299. package/dist/team/state/dispatch.js.map +1 -1
  300. package/dist/team/state/locks.d.ts.map +1 -1
  301. package/dist/team/state/locks.js +61 -13
  302. package/dist/team/state/locks.js.map +1 -1
  303. package/dist/team/state/tasks.d.ts.map +1 -1
  304. package/dist/team/state/tasks.js +4 -3
  305. package/dist/team/state/tasks.js.map +1 -1
  306. package/dist/team/state.d.ts +67 -1
  307. package/dist/team/state.d.ts.map +1 -1
  308. package/dist/team/state.js +636 -129
  309. package/dist/team/state.js.map +1 -1
  310. package/dist/team/team-ops.d.ts +5 -0
  311. package/dist/team/team-ops.d.ts.map +1 -1
  312. package/dist/team/team-ops.js +4 -0
  313. package/dist/team/team-ops.js.map +1 -1
  314. package/dist/team/tmux-session.d.ts +123 -23
  315. package/dist/team/tmux-session.d.ts.map +1 -1
  316. package/dist/team/tmux-session.js +1250 -291
  317. package/dist/team/tmux-session.js.map +1 -1
  318. package/dist/team/worktree.d.ts.map +1 -1
  319. package/dist/team/worktree.js +4 -0
  320. package/dist/team/worktree.js.map +1 -1
  321. package/dist/utils/__tests__/file-durability.test.d.ts +2 -0
  322. package/dist/utils/__tests__/file-durability.test.d.ts.map +1 -0
  323. package/dist/utils/__tests__/file-durability.test.js +57 -0
  324. package/dist/utils/__tests__/file-durability.test.js.map +1 -0
  325. package/dist/utils/file-durability.d.ts +15 -0
  326. package/dist/utils/file-durability.d.ts.map +1 -0
  327. package/dist/utils/file-durability.js +37 -0
  328. package/dist/utils/file-durability.js.map +1 -0
  329. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +3 -0
  330. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
  331. package/dist/wiki/lint.d.ts +4 -1
  332. package/dist/wiki/lint.d.ts.map +1 -1
  333. package/dist/wiki/lint.js +3 -2
  334. package/dist/wiki/lint.js.map +1 -1
  335. package/package.json +1 -1
  336. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  337. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +24 -0
  338. package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -4
  339. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +3 -2
  340. package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
  341. package/skills/ralph/SKILL.md +6 -4
  342. package/skills/ralplan/SKILL.md +3 -2
  343. package/skills/team/SKILL.md +13 -9
  344. package/src/scripts/__tests__/codex-native-hook.test.ts +2826 -497
  345. package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
  346. package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +48 -185
  347. package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +44 -177
  348. package/src/scripts/__tests__/smoke-packed-install.test.ts +320 -2
  349. package/src/scripts/codex-native-hook.ts +10715 -1069
  350. package/src/scripts/notify-fallback-watcher.ts +84 -115
  351. package/src/scripts/notify-hook/auto-nudge.ts +71 -3
  352. package/src/scripts/notify-hook/team-dispatch.ts +242 -75
  353. package/src/scripts/notify-hook/team-leader-nudge.ts +40 -18
  354. package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
  355. package/src/scripts/notify-hook/team-worker-stop.ts +20 -16
  356. package/src/scripts/notify-hook/team-worker.ts +39 -26
  357. package/src/scripts/notify-hook/tmux-injection.ts +28 -2
  358. package/src/scripts/notify-hook.ts +1 -0
  359. package/src/scripts/smoke-packed-install.ts +3196 -14
  360. package/dist/subagents/__tests__/adapted-role-binding.test.d.ts +0 -2
  361. package/dist/subagents/__tests__/adapted-role-binding.test.d.ts.map +0 -1
  362. package/dist/subagents/__tests__/adapted-role-binding.test.js +0 -988
  363. package/dist/subagents/__tests__/adapted-role-binding.test.js.map +0 -1
  364. package/dist/subagents/adapted-role-binding.d.ts +0 -17
  365. package/dist/subagents/adapted-role-binding.d.ts.map +0 -1
  366. package/dist/subagents/adapted-role-binding.js +0 -75
  367. package/dist/subagents/adapted-role-binding.js.map +0 -1
@@ -8,13 +8,16 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
8
8
  import { tmpdir } from "node:os";
9
9
  import { isAbsolute, join } from "node:path";
10
10
  import TOML from "@iarna/toml";
11
- import { analyzeLegacyMultiAgentConfig, buildMergedConfig, cleanCodexModelAvailabilityNuxIfNeeded, hasExactOmxSeededBehavioralDefaultsPair, mergeConfig, repairConfigIfNeeded, stripExistingOmxBlocks, stripManagedCodexHookTrustState, stripOmxFeatureFlags, upsertManagedCodexHookTrustState, stripOmxSeededBehavioralDefaults, } from "../generator.js";
11
+ import { analyzeLegacyMultiAgentConfig, buildMergedConfig, cleanCodexModelAvailabilityNuxIfNeeded, hasExactOmxSeededBehavioralDefaultsPair, mergeConfig, repairConfigIfNeeded, repairProjectScopeTrustStateForLaunch, stripExistingOmxBlocks, stripManagedCodexHookTrustState, stripOmxFeatureFlags, syncProjectScopeTrustStateFromRuntime, upsertManagedCodexHookTrustState, stripOmxSeededBehavioralDefaults, } from "../generator.js";
12
12
  import { MANAGED_HOOK_EVENTS, ManagedCodexHooksPlanError, buildManagedCodexHookTrustState, planManagedCodexHooksMerge, } from "../codex-hooks.js";
13
13
  import { OMX_FIRST_PARTY_MCP_SERVER_NAMES } from "../omx-first-party-mcp.js";
14
14
  /** Count occurrences of a pattern in text */
15
15
  function count(text, pattern) {
16
16
  return (text.match(pattern) ?? []).length;
17
17
  }
18
+ function escapeRegExp(value) {
19
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
20
+ }
18
21
  async function writeSetupGeneratedHookTrustFixture(wd) {
19
22
  const configPath = join(wd, "config.toml");
20
23
  const hooksPath = join(wd, "hooks.json");
@@ -2061,4 +2064,330 @@ describe("config generator idempotency (#384)", () => {
2061
2064
  }
2062
2065
  });
2063
2066
  });
2067
+ describe("project trust sync ownership reconciliation (#3199)", () => {
2068
+ const markerStart = "# OMX-synced Codex project trust state (from runtime CODEX_HOME)";
2069
+ const markerEnd = "# End OMX-synced Codex project trust state";
2070
+ it("retains an equal external project family byte-for-byte and removes only its fenced duplicate", () => {
2071
+ const key = "/tmp/외부.project";
2072
+ const external = `[projects."${key}"] # retain this spelling\ntrust_level = "trusted"\n\n[projects."${key}".child]\nanswer = 42\n`;
2073
+ const durable = `${external}\n${markerStart}\n[projects."${key}"]\ntrust_level = "trusted"\n\n[projects."${key}".child]\nanswer = 42\n${markerEnd}\n`;
2074
+ const runtime = `[projects."${key}"]\ntrust_level = "trusted"\n\n[projects."${key}".child]\nanswer = 42\n`;
2075
+ const synced = syncProjectScopeTrustStateFromRuntime(durable, runtime, "/tmp/hooks.json");
2076
+ assert.equal(synced, external);
2077
+ assert.deepEqual(TOML.parse(synced), TOML.parse(external));
2078
+ assert.equal(syncProjectScopeTrustStateFromRuntime(synced, runtime, "/tmp/hooks.json"), synced);
2079
+ assert.equal(syncProjectScopeTrustStateFromRuntime(synced, runtime, "/tmp/hooks.json"), synced);
2080
+ });
2081
+ it("fails closed atomically for mismatched, nested, and ambiguous project source", () => {
2082
+ const runtime = '[projects."/tmp/a"]\ntrust_level = "trusted"\n\n[projects."/tmp/b"]\ntrust_level = "trusted"\n';
2083
+ const mismatch = '[projects."/tmp/a"]\ntrust_level = "untrusted"\n';
2084
+ assert.equal(syncProjectScopeTrustStateFromRuntime(mismatch, runtime, "/tmp/hooks.json"), mismatch);
2085
+ const nested = '[projects."/tmp/a"]\n[projects."/tmp/a".child]\nvalue = "x"\n';
2086
+ assert.equal(syncProjectScopeTrustStateFromRuntime("", nested, "/tmp/hooks.json"), "");
2087
+ const duplicateMarker = `${markerStart}\n${markerEnd}\n${markerStart}\n${markerEnd}\n`;
2088
+ assert.equal(syncProjectScopeTrustStateFromRuntime(duplicateMarker, runtime, "/tmp/hooks.json"), duplicateMarker);
2089
+ });
2090
+ it("preserves BOM and hook-only marker state through launch repair", () => {
2091
+ const hook = "/tmp/hooks.json:pre_tool_use:0:0";
2092
+ const runtime = `[hooks.state."${hook}"]\ntrusted_hash = "sha256:ok"\n`;
2093
+ const bom = `\uFEFF# non-ascii: 외부\r\n`;
2094
+ const synced = syncProjectScopeTrustStateFromRuntime(bom, runtime, "/tmp/hooks.json");
2095
+ assert.ok(synced.startsWith("\uFEFF# non-ascii: 외부\r\n"));
2096
+ assert.ok(synced.includes(`${markerStart}\r\n`));
2097
+ assert.doesNotThrow(() => TOML.parse(synced.slice(1)));
2098
+ assert.equal(repairProjectScopeTrustStateForLaunch(synced, "/tmp/hooks.json"), synced);
2099
+ });
2100
+ it("preserves unrelated external tables and distinguishes quoted dotted keys from dotted paths", () => {
2101
+ const target = "org.example/project";
2102
+ const external = [
2103
+ "# user-owned leading comment",
2104
+ `[projects.'${target}']`,
2105
+ 'trust_level = "trusted" # user-owned trailing comment',
2106
+ "",
2107
+ '[projects."other.key"]',
2108
+ 'trust_level = "untrusted"',
2109
+ "",
2110
+ "[user.section]",
2111
+ 'note = "keep"',
2112
+ "",
2113
+ ].join("\n");
2114
+ const runtime = `[projects."${target}"]\ntrust_level = "trusted"\n`;
2115
+ const synced = syncProjectScopeTrustStateFromRuntime(external, runtime, "/tmp/hooks.json");
2116
+ assert.equal(synced, external);
2117
+ assert.equal(TOML.parse(synced).projects["other.key"] !== undefined, true);
2118
+ });
2119
+ it("normal sync removes semantically empty markers while launch repair leaves them untouched", () => {
2120
+ const empty = `${markerStart}\n${markerEnd}\n`;
2121
+ assert.equal(syncProjectScopeTrustStateFromRuntime(empty, "", "/tmp/hooks.json"), "\n");
2122
+ const comments = `${markerStart}\n# OMX payload comment\n\n${markerEnd}\n`;
2123
+ assert.equal(syncProjectScopeTrustStateFromRuntime(comments, "", "/tmp/hooks.json"), "\n");
2124
+ assert.equal(repairProjectScopeTrustStateForLaunch(comments, "/tmp/hooks.json"), comments);
2125
+ const hook = "/tmp/hooks.json:post_tool_use:0:0";
2126
+ const runtime = `[hooks.state."${hook}"]\ntrusted_hash = "sha256:hook"\n`;
2127
+ const hookOnly = syncProjectScopeTrustStateFromRuntime(comments, runtime, "/tmp/hooks.json");
2128
+ assert.ok(hookOnly.includes(markerStart));
2129
+ assert.match(hookOnly, new RegExp(`^\\[hooks\\.state\\."${escapeRegExp(hook)}"\\]$`, "m"));
2130
+ assert.equal(syncProjectScopeTrustStateFromRuntime(hookOnly, runtime, "/tmp/hooks.json"), hookOnly);
2131
+ });
2132
+ it("keeps project and hook mutation atomic across runtime shape and multi-key failures", () => {
2133
+ const hook = "/tmp/hooks.json:pre_tool_use:0:0";
2134
+ const hookRuntime = `[hooks.state."${hook}"]\ntrusted_hash = "sha256:hook"\n`;
2135
+ const nonRecord = `projects = "invalid"\n\n${hookRuntime}`;
2136
+ assert.equal(syncProjectScopeTrustStateFromRuntime("# durable\n", nonRecord, "/tmp/hooks.json"), "# durable\n");
2137
+ const mixed = `${hookRuntime}\n[projects."/safe"]\ntrust_level = "trusted"\n\n[projects."/unsafe"]\n[projects."/unsafe".child]\nvalue = "nested"\n`;
2138
+ const durable = '[projects."/unsafe"]\ntrust_level = "untrusted"\n';
2139
+ assert.equal(syncProjectScopeTrustStateFromRuntime(durable, mixed, "/tmp/hooks.json"), durable);
2140
+ const absentProjects = syncProjectScopeTrustStateFromRuntime("", hookRuntime, "/tmp/hooks.json");
2141
+ assert.match(absentProjects, /hooks\.state/);
2142
+ const emptyProjects = syncProjectScopeTrustStateFromRuntime("", `projects = {}\n\n${hookRuntime}`, "/tmp/hooks.json");
2143
+ assert.match(emptyProjects, /hooks\.state/);
2144
+ });
2145
+ it("accepts nested external retention but refuses nested rendering and malformed project forms", () => {
2146
+ const nested = '[projects."/nested"]\ntrust_level = "trusted"\n\n[projects."/nested".child]\nvalue = "x"\n';
2147
+ assert.equal(syncProjectScopeTrustStateFromRuntime(nested, nested, "/tmp/hooks.json"), nested);
2148
+ assert.equal(syncProjectScopeTrustStateFromRuntime("", nested, "/tmp/hooks.json"), "");
2149
+ for (const unsafe of [
2150
+ 'projects = { "/inline" = { trust_level = "trusted" } }\n',
2151
+ '[projects]\n"/dotted".trust_level = "trusted"\n',
2152
+ '[[projects."/array"]]\ntrust_level = "trusted"\n',
2153
+ '[projects."/bad"\ntrust_level = "trusted"\n',
2154
+ ]) {
2155
+ assert.equal(syncProjectScopeTrustStateFromRuntime(unsafe, '[projects."/bad"]\ntrust_level = "trusted"\n', "/tmp/hooks.json"), unsafe);
2156
+ }
2157
+ });
2158
+ it("fails closed for equal external state with parent-only dotted or inline nested marker bodies", () => {
2159
+ const external = '[projects."/nested"]\nchild.value = "x"\n';
2160
+ const runtime = '[projects."/nested"]\n[projects."/nested".child]\nvalue = "x"\n';
2161
+ const inlineExternal = '[projects."/nested"]\nchild = { value = "x" }\n';
2162
+ const inlineRuntime = '[projects."/nested"]\n[projects."/nested".child]\nvalue = "x"\n';
2163
+ for (const [outside, source] of [
2164
+ [external, external],
2165
+ [inlineExternal, inlineExternal],
2166
+ ]) {
2167
+ const durable = `${outside}\n${markerStart}\n${source}${markerEnd}\n`;
2168
+ assert.equal(syncProjectScopeTrustStateFromRuntime(durable, source === external ? runtime : inlineRuntime, "/tmp/hooks.json"), durable);
2169
+ assert.equal(repairProjectScopeTrustStateForLaunch(durable, "/tmp/hooks.json"), durable);
2170
+ }
2171
+ });
2172
+ it("fails closed for implicit nested runtime and external sources before any hook mutation", () => {
2173
+ const hook = "/tmp/hooks.json:post_tool_use:0:0";
2174
+ const hookRuntime = `[hooks.state."${hook}"]\ntrusted_hash = "sha256:hook"\n`;
2175
+ const durable = '# durable bytes\n';
2176
+ for (const runtime of [
2177
+ '[projects."/dotted"]\nchild.value = "x"\n',
2178
+ '[projects."/inline"]\nchild = { value = "x" }\n',
2179
+ ]) {
2180
+ assert.equal(syncProjectScopeTrustStateFromRuntime(durable, `${runtime}\n${hookRuntime}`, "/tmp/hooks.json"), durable);
2181
+ }
2182
+ for (const external of [
2183
+ '[projects."/dotted"]\nchild.value = "x"\n',
2184
+ '[projects."/inline"]\nchild = { value = "x" }\n',
2185
+ ]) {
2186
+ assert.equal(syncProjectScopeTrustStateFromRuntime(external, `${external}\n${hookRuntime}`, "/tmp/hooks.json"), external);
2187
+ }
2188
+ });
2189
+ it("preserves managed marker headers and assignments with inline comments exactly", () => {
2190
+ const hook = "/tmp/hooks.json:pre_tool_use:0:0";
2191
+ const runtime = `[projects."/commented"]\ntrust_level = "trusted"\n\n[hooks.state."${hook}"]\ntrusted_hash = "sha256:hook"\n`;
2192
+ for (const managedLine of [
2193
+ '[projects."/commented"] # user-owned header comment',
2194
+ 'trust_level = "trusted" # user-owned assignment comment',
2195
+ ]) {
2196
+ const durable = `${markerStart}\n${managedLine}\n${managedLine.startsWith("[") ? 'trust_level = "trusted"' : '[projects."/commented"]'}\n${markerEnd}\n`;
2197
+ assert.equal(syncProjectScopeTrustStateFromRuntime(durable, runtime, "/tmp/hooks.json"), durable);
2198
+ assert.equal(repairProjectScopeTrustStateForLaunch(durable, "/tmp/hooks.json"), durable);
2199
+ }
2200
+ const inlineMarker = `${markerStart} # user-owned marker comment\n${markerEnd}\n`;
2201
+ assert.equal(syncProjectScopeTrustStateFromRuntime(inlineMarker, runtime, "/tmp/hooks.json"), inlineMarker);
2202
+ });
2203
+ it("fails closed rather than moving comments before or between table assignments", () => {
2204
+ const durable = [
2205
+ markerStart,
2206
+ '[projects."/commented"]',
2207
+ "# before trust level",
2208
+ 'trust_level = "trusted"',
2209
+ "# between assignments",
2210
+ 'approval = "trusted"',
2211
+ markerEnd,
2212
+ "",
2213
+ ].join("\n");
2214
+ const runtime = '[projects."/commented"]\ntrust_level = "trusted"\napproval = "trusted"\n';
2215
+ assert.equal(syncProjectScopeTrustStateFromRuntime(durable, runtime, "/tmp/hooks.json"), durable);
2216
+ assert.equal(repairProjectScopeTrustStateForLaunch(durable, "/tmp/hooks.json"), durable);
2217
+ });
2218
+ it("fails closed for noncanonical runtime and marker project source forms", () => {
2219
+ const canonical = '[projects."/safe"]\ntrust_level = "trusted"\n';
2220
+ const runtimeForms = [
2221
+ 'projects = { "/inline" = { trust_level = "trusted" } }\n',
2222
+ '[projects]\n"/dotted".trust_level = "trusted"\n',
2223
+ '[projects]\n"/implicit" = { trust_level = "trusted" }\n',
2224
+ ];
2225
+ for (const runtime of runtimeForms) {
2226
+ assert.equal(syncProjectScopeTrustStateFromRuntime("# durable\n", runtime, "/tmp/hooks.json"), "# durable\n");
2227
+ }
2228
+ for (const payload of runtimeForms) {
2229
+ const durable = `${markerStart}\n${payload}${markerEnd}\n`;
2230
+ assert.equal(syncProjectScopeTrustStateFromRuntime(durable, canonical, "/tmp/hooks.json"), durable);
2231
+ }
2232
+ const malformed = `${markerStart}\n[projects."/bad"\ntrust_level = "trusted"\n${markerEnd}\n`;
2233
+ const noncontiguous = '[projects."/safe"]\ntrust_level = "trusted"\n\n[user]\nkeep = true\n\n[projects."/safe".child]\nvalue = "x"\n';
2234
+ const multiline = 'note = """\n[projects."/not-a-header"]\n"""\n';
2235
+ assert.equal(syncProjectScopeTrustStateFromRuntime(malformed, canonical, "/tmp/hooks.json"), malformed);
2236
+ assert.equal(syncProjectScopeTrustStateFromRuntime(noncontiguous, noncontiguous, "/tmp/hooks.json"), noncontiguous);
2237
+ const multilineSynced = syncProjectScopeTrustStateFromRuntime(multiline, canonical, "/tmp/hooks.json");
2238
+ assert.match(multilineSynced, /^note = """\n\[projects\."\/not-a-header"\]\n"""$/m);
2239
+ assert.equal(syncProjectScopeTrustStateFromRuntime(multilineSynced, canonical, "/tmp/hooks.json"), multilineSynced);
2240
+ });
2241
+ it("preserves zero and multiple durable trailing newlines without accumulating separators", () => {
2242
+ const runtime = '[projects."/eol"]\ntrust_level = "trusted"\n';
2243
+ for (const trailingEols of ["", "\n\n\n", "\r\n\n\r\n"]) {
2244
+ const durable = `# external${trailingEols}`;
2245
+ const synced = syncProjectScopeTrustStateFromRuntime(durable, runtime, "/tmp/hooks.json");
2246
+ const replaced = syncProjectScopeTrustStateFromRuntime(synced, runtime, "/tmp/hooks.json");
2247
+ const removed = syncProjectScopeTrustStateFromRuntime(replaced, "", "/tmp/hooks.json");
2248
+ assert.equal(synced.match(/(?:\r\n|\n)*$/)?.[0], trailingEols);
2249
+ assert.equal(replaced, synced);
2250
+ assert.equal(removed, durable);
2251
+ }
2252
+ });
2253
+ it("repairs an equal external-and-fenced project duplicate without moving external bytes", () => {
2254
+ const external = '# before external\n[projects."/repair"]\ntrust_level = "trusted"\n';
2255
+ const durable = `${external}\n${markerStart}\n[projects."/repair"]\ntrust_level = "trusted"\n${markerEnd}\n`;
2256
+ const repaired = repairProjectScopeTrustStateForLaunch(durable, "/tmp/hooks.json");
2257
+ assert.equal(repaired, external);
2258
+ assert.doesNotThrow(() => TOML.parse(repaired));
2259
+ });
2260
+ it("preserves BOM and escaped project keys through second and third sync", () => {
2261
+ const key = '__omx_project_sync_probe__\\"quoted';
2262
+ const runtime = `[projects."${key.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"]\ntrust_level = "trusted"\n`;
2263
+ const first = syncProjectScopeTrustStateFromRuntime("\uFEFF# é\n", runtime, "/tmp/hooks.json");
2264
+ const second = syncProjectScopeTrustStateFromRuntime(first, runtime, "/tmp/hooks.json");
2265
+ const third = syncProjectScopeTrustStateFromRuntime(second, runtime, "/tmp/hooks.json");
2266
+ const projects = TOML.parse(third.slice(1)).projects;
2267
+ assert.equal(second, first);
2268
+ assert.equal(third, first);
2269
+ assert.deepEqual(Object.keys(projects), [key]);
2270
+ assert.equal(syncProjectScopeTrustStateFromRuntime("# x\uFEFF\n", runtime, "/tmp/hooks.json"), "# x\uFEFF\n");
2271
+ assert.equal(syncProjectScopeTrustStateFromRuntime("\uFEFF\uFEFF# x\n", runtime, "/tmp/hooks.json"), "\uFEFF\uFEFF# x\n");
2272
+ });
2273
+ it("fails closed for unsupported marker tables and assignments", () => {
2274
+ const runtime = '[projects."/safe"]\ntrust_level = "trusted"\n';
2275
+ for (const unsupported of [
2276
+ '[omx_unknown]\nvalue = true\n',
2277
+ 'unknown_managed_assignment = true\n',
2278
+ ]) {
2279
+ const durable = `${markerStart}\n${unsupported}${markerEnd}\n`;
2280
+ assert.equal(syncProjectScopeTrustStateFromRuntime(durable, runtime, "/tmp/hooks.json"), durable);
2281
+ assert.equal(repairProjectScopeTrustStateForLaunch(durable, "/tmp/hooks.json"), durable);
2282
+ }
2283
+ });
2284
+ it("fails closed for descendant-only and hook-interleaved marker project families", () => {
2285
+ const hook = "/tmp/hooks.json:post_tool_use:0:0";
2286
+ const external = [
2287
+ '[projects."/safe"]',
2288
+ 'trust_level = "trusted"',
2289
+ "",
2290
+ '[projects."/safe".child]',
2291
+ 'value = "nested"',
2292
+ "",
2293
+ ].join("\n");
2294
+ const runtime = `${external}[hooks.state."${hook}"]\ntrusted_hash = "sha256:hook"\n`;
2295
+ const descendantOnly = `${external}${markerStart}\n[projects."/safe".child]\nvalue = "nested"\n${markerEnd}\n`;
2296
+ const hookInterleaved = `${external}${markerStart}\n[projects."/safe"]\ntrust_level = "trusted"\n\n[hooks.state."${hook}"]\ntrusted_hash = "sha256:hook"\n\n[projects."/safe".child]\nvalue = "nested"\n${markerEnd}\n`;
2297
+ for (const durable of [descendantOnly, hookInterleaved]) {
2298
+ assert.equal(syncProjectScopeTrustStateFromRuntime(durable, runtime, "/tmp/hooks.json"), durable);
2299
+ assert.equal(repairProjectScopeTrustStateForLaunch(durable, "/tmp/hooks.json"), durable);
2300
+ }
2301
+ });
2302
+ it("inserts new runtime project and hook tables before the trailing owned payload gap", () => {
2303
+ const hook = "/tmp/hooks.json:post_tool_use:0:0";
2304
+ const durable = [
2305
+ markerStart,
2306
+ '[projects."/existing"]',
2307
+ 'trust_level = "trusted"',
2308
+ "# trailing owned gap",
2309
+ "",
2310
+ markerEnd,
2311
+ "",
2312
+ ].join("\n");
2313
+ const runtime = [
2314
+ '[projects."/existing"]',
2315
+ 'trust_level = "trusted"',
2316
+ "",
2317
+ '[projects."/new"]',
2318
+ 'trust_level = "trusted"',
2319
+ "",
2320
+ `[hooks.state."${hook}"]`,
2321
+ 'trusted_hash = "sha256:hook"',
2322
+ "",
2323
+ ].join("\n");
2324
+ const expected = [
2325
+ markerStart,
2326
+ '[projects."/existing"]',
2327
+ 'trust_level = "trusted"',
2328
+ '[projects."/new"]',
2329
+ 'trust_level = "trusted"',
2330
+ `[hooks.state."${hook}"]`,
2331
+ 'trusted_hash = "sha256:hook"',
2332
+ "# trailing owned gap",
2333
+ "",
2334
+ markerEnd,
2335
+ "",
2336
+ ].join("\n");
2337
+ const synced = syncProjectScopeTrustStateFromRuntime(durable, runtime, "/tmp/hooks.json");
2338
+ assert.equal(synced, expected);
2339
+ assert.equal(syncProjectScopeTrustStateFromRuntime(synced, runtime, "/tmp/hooks.json"), synced);
2340
+ });
2341
+ it("preserves owned payload gaps while removing first, middle, and last project duplicates", () => {
2342
+ const hook = "/tmp/hooks.json:post_tool_use:0:0";
2343
+ const external = [
2344
+ '[projects."/first"]',
2345
+ 'trust_level = "trusted"',
2346
+ "",
2347
+ '[projects."/middle"]',
2348
+ 'trust_level = "trusted"',
2349
+ "",
2350
+ '[projects."/last"]',
2351
+ 'trust_level = "trusted"',
2352
+ "",
2353
+ ].join("\n");
2354
+ const runtime = `${external}[hooks.state."${hook}"]\ntrusted_hash = "sha256:hook"\n`;
2355
+ const durable = [
2356
+ external,
2357
+ markerStart,
2358
+ "# before first",
2359
+ '[projects."/first"]',
2360
+ 'trust_level = "trusted"',
2361
+ "# between first and middle",
2362
+ '[projects."/middle"]',
2363
+ 'trust_level = "trusted"',
2364
+ "# between middle and hook",
2365
+ `[hooks.state."${hook}"]`,
2366
+ 'trusted_hash = "sha256:hook"',
2367
+ "# between hook and last",
2368
+ '[projects."/last"]',
2369
+ 'trust_level = "trusted"',
2370
+ "# after last",
2371
+ markerEnd,
2372
+ "",
2373
+ ].join("\n");
2374
+ const expected = [
2375
+ external,
2376
+ markerStart,
2377
+ "# before first",
2378
+ "# between first and middle",
2379
+ "# between middle and hook",
2380
+ `[hooks.state."${hook}"]`,
2381
+ 'trusted_hash = "sha256:hook"',
2382
+ "# between hook and last",
2383
+ "# after last",
2384
+ markerEnd,
2385
+ "",
2386
+ ].join("\n");
2387
+ const synced = syncProjectScopeTrustStateFromRuntime(durable, runtime, "/tmp/hooks.json");
2388
+ assert.equal(synced, expected);
2389
+ assert.equal(syncProjectScopeTrustStateFromRuntime(synced, runtime, "/tmp/hooks.json"), synced);
2390
+ assert.doesNotThrow(() => TOML.parse(synced));
2391
+ });
2392
+ });
2064
2393
  //# sourceMappingURL=generator-idempotent.test.js.map