oh-my-codex 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +8 -1
  4. package/crates/omx-api/src/lib.rs +3 -3
  5. package/crates/omx-api/tests/cli.rs +4 -4
  6. package/crates/omx-explore/src/main.rs +4 -4
  7. package/crates/omx-sparkshell/src/codex_bridge.rs +2 -2
  8. package/dist/agents/__tests__/definitions.test.js +3 -3
  9. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  10. package/dist/agents/__tests__/native-config.test.js +71 -42
  11. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  12. package/dist/agents/definitions.d.ts +1 -1
  13. package/dist/agents/definitions.d.ts.map +1 -1
  14. package/dist/agents/definitions.js +3 -3
  15. package/dist/agents/definitions.js.map +1 -1
  16. package/dist/agents/native-config.d.ts +2 -2
  17. package/dist/agents/native-config.d.ts.map +1 -1
  18. package/dist/agents/native-config.js +7 -5
  19. package/dist/agents/native-config.js.map +1 -1
  20. package/dist/autopilot/__tests__/planner-routing.test.js +19 -12
  21. package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -1
  22. package/dist/autopilot/__tests__/ralplan-gate.test.js +151 -0
  23. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  24. package/dist/autopilot/planner-routing.d.ts.map +1 -1
  25. package/dist/autopilot/planner-routing.js +4 -2
  26. package/dist/autopilot/planner-routing.js.map +1 -1
  27. package/dist/autopilot/ralplan-gate.d.ts +1 -0
  28. package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
  29. package/dist/autopilot/ralplan-gate.js +38 -2
  30. package/dist/autopilot/ralplan-gate.js.map +1 -1
  31. package/dist/autoresearch/runtime.d.ts +2 -0
  32. package/dist/autoresearch/runtime.d.ts.map +1 -1
  33. package/dist/autoresearch/runtime.js +8 -0
  34. package/dist/autoresearch/runtime.js.map +1 -1
  35. package/dist/capabilities/__tests__/lockfile.test.d.ts +2 -0
  36. package/dist/capabilities/__tests__/lockfile.test.d.ts.map +1 -0
  37. package/dist/capabilities/__tests__/lockfile.test.js +115 -0
  38. package/dist/capabilities/__tests__/lockfile.test.js.map +1 -0
  39. package/dist/capabilities/lockfile.d.ts +102 -0
  40. package/dist/capabilities/lockfile.d.ts.map +1 -0
  41. package/dist/capabilities/lockfile.js +334 -0
  42. package/dist/capabilities/lockfile.js.map +1 -0
  43. package/dist/cli/__tests__/agents.test.js +5 -5
  44. package/dist/cli/__tests__/agents.test.js.map +1 -1
  45. package/dist/cli/__tests__/capabilities.test.d.ts +2 -0
  46. package/dist/cli/__tests__/capabilities.test.d.ts.map +1 -0
  47. package/dist/cli/__tests__/capabilities.test.js +135 -0
  48. package/dist/cli/__tests__/capabilities.test.js.map +1 -0
  49. package/dist/cli/__tests__/codex-plugin-layout.test.js +237 -6
  50. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  51. package/dist/cli/__tests__/doctor-context-window-warning.test.js +9 -9
  52. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
  53. package/dist/cli/__tests__/doctor-invalid-config.test.js +1 -1
  54. package/dist/cli/__tests__/doctor-spark-routing.test.js +22 -6
  55. package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -1
  56. package/dist/cli/__tests__/index.test.js +53 -18
  57. package/dist/cli/__tests__/index.test.js.map +1 -1
  58. package/dist/cli/__tests__/mission.test.d.ts +2 -0
  59. package/dist/cli/__tests__/mission.test.d.ts.map +1 -0
  60. package/dist/cli/__tests__/mission.test.js +239 -0
  61. package/dist/cli/__tests__/mission.test.js.map +1 -0
  62. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js +3 -3
  63. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -1
  64. package/dist/cli/__tests__/resume.test.js +95 -6
  65. package/dist/cli/__tests__/resume.test.js.map +1 -1
  66. package/dist/cli/__tests__/session-scoped-runtime.test.js +67 -0
  67. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  68. package/dist/cli/__tests__/setup-install-mode.test.js +46 -18
  69. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  70. package/dist/cli/__tests__/setup-prompts-overwrite.test.js +3 -3
  71. package/dist/cli/__tests__/setup-refresh.test.js +29 -7
  72. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  73. package/dist/cli/__tests__/ultragoal.test.js +1 -1
  74. package/dist/cli/__tests__/uninstall.test.js +4 -4
  75. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  76. package/dist/cli/agents.js +1 -1
  77. package/dist/cli/agents.js.map +1 -1
  78. package/dist/cli/capabilities.d.ts +3 -0
  79. package/dist/cli/capabilities.d.ts.map +1 -0
  80. package/dist/cli/capabilities.js +118 -0
  81. package/dist/cli/capabilities.js.map +1 -0
  82. package/dist/cli/doctor.d.ts +1 -1
  83. package/dist/cli/doctor.d.ts.map +1 -1
  84. package/dist/cli/doctor.js +9 -4
  85. package/dist/cli/doctor.js.map +1 -1
  86. package/dist/cli/index.d.ts +7 -4
  87. package/dist/cli/index.d.ts.map +1 -1
  88. package/dist/cli/index.js +107 -23
  89. package/dist/cli/index.js.map +1 -1
  90. package/dist/cli/mission.d.ts +36 -0
  91. package/dist/cli/mission.d.ts.map +1 -0
  92. package/dist/cli/mission.js +443 -0
  93. package/dist/cli/mission.js.map +1 -0
  94. package/dist/cli/plugin-marketplace.d.ts +1 -0
  95. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  96. package/dist/cli/plugin-marketplace.js +31 -0
  97. package/dist/cli/plugin-marketplace.js.map +1 -1
  98. package/dist/cli/setup.d.ts.map +1 -1
  99. package/dist/cli/setup.js +7 -4
  100. package/dist/cli/setup.js.map +1 -1
  101. package/dist/config/__tests__/generator-idempotent.test.js +23 -23
  102. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  103. package/dist/config/__tests__/generator-notify.test.js +9 -9
  104. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  105. package/dist/config/__tests__/models.test.js +51 -26
  106. package/dist/config/__tests__/models.test.js.map +1 -1
  107. package/dist/config/generator.d.ts +1 -1
  108. package/dist/config/generator.d.ts.map +1 -1
  109. package/dist/config/models.d.ts +16 -6
  110. package/dist/config/models.d.ts.map +1 -1
  111. package/dist/config/models.js +19 -8
  112. package/dist/config/models.js.map +1 -1
  113. package/dist/hooks/__tests__/keyword-detector.test.js +12 -4
  114. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  115. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +1 -1
  116. package/dist/hooks/__tests__/prometheus-strict-contract.test.js +2 -2
  117. package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
  118. package/dist/hooks/__tests__/tmux-hook-engine.test.js +2 -2
  119. package/dist/hud/__tests__/state.test.js +31 -6
  120. package/dist/hud/__tests__/state.test.js.map +1 -1
  121. package/dist/hud/state.d.ts.map +1 -1
  122. package/dist/hud/state.js +7 -3
  123. package/dist/hud/state.js.map +1 -1
  124. package/dist/leader/__tests__/contract.test.js +108 -1
  125. package/dist/leader/__tests__/contract.test.js.map +1 -1
  126. package/dist/leader/contract.d.ts +26 -0
  127. package/dist/leader/contract.d.ts.map +1 -1
  128. package/dist/leader/contract.js +170 -0
  129. package/dist/leader/contract.js.map +1 -1
  130. package/dist/mcp/__tests__/state-paths.test.js +32 -1
  131. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  132. package/dist/mcp/state-paths.d.ts +4 -0
  133. package/dist/mcp/state-paths.d.ts.map +1 -1
  134. package/dist/mcp/state-paths.js +6 -15
  135. package/dist/mcp/state-paths.js.map +1 -1
  136. package/dist/modes/base.d.ts +1 -1
  137. package/dist/modes/base.d.ts.map +1 -1
  138. package/dist/pipeline/__tests__/stages.test.js +27 -1
  139. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  140. package/dist/pipeline/stages/ralplan.d.ts +2 -1
  141. package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
  142. package/dist/pipeline/stages/ralplan.js +1 -0
  143. package/dist/pipeline/stages/ralplan.js.map +1 -1
  144. package/dist/pipeline/stages/ultragoal.d.ts +5 -1
  145. package/dist/pipeline/stages/ultragoal.d.ts.map +1 -1
  146. package/dist/pipeline/stages/ultragoal.js +14 -4
  147. package/dist/pipeline/stages/ultragoal.js.map +1 -1
  148. package/dist/ralplan/__tests__/consensus-gate.test.js +193 -0
  149. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
  150. package/dist/ralplan/__tests__/runtime.test.js +132 -0
  151. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  152. package/dist/ralplan/consensus-gate.js +24 -3
  153. package/dist/ralplan/consensus-gate.js.map +1 -1
  154. package/dist/ralplan/runtime.d.ts +17 -0
  155. package/dist/ralplan/runtime.d.ts.map +1 -1
  156. package/dist/ralplan/runtime.js +97 -1
  157. package/dist/ralplan/runtime.js.map +1 -1
  158. package/dist/scripts/__tests__/codex-native-hook.test.js +762 -20
  159. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  160. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  161. package/dist/scripts/codex-native-hook.js +306 -22
  162. package/dist/scripts/codex-native-hook.js.map +1 -1
  163. package/dist/scripts/generate-catalog-docs.js +1 -0
  164. package/dist/scripts/generate-catalog-docs.js.map +1 -1
  165. package/dist/state/__tests__/operations.test.js +737 -0
  166. package/dist/state/__tests__/operations.test.js.map +1 -1
  167. package/dist/state/__tests__/skill-active.test.js +59 -0
  168. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  169. package/dist/state/__tests__/workflow-transition.test.js +14 -0
  170. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  171. package/dist/state/operations.d.ts.map +1 -1
  172. package/dist/state/operations.js +80 -17
  173. package/dist/state/operations.js.map +1 -1
  174. package/dist/state/skill-active.js +3 -3
  175. package/dist/state/skill-active.js.map +1 -1
  176. package/dist/state/terminal-normalization.d.ts +8 -0
  177. package/dist/state/terminal-normalization.d.ts.map +1 -0
  178. package/dist/state/terminal-normalization.js +127 -0
  179. package/dist/state/terminal-normalization.js.map +1 -0
  180. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  181. package/dist/state/workflow-transition-reconcile.js +3 -1
  182. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  183. package/dist/team/__tests__/delegation-policy.test.js +2 -2
  184. package/dist/team/__tests__/delegation-policy.test.js.map +1 -1
  185. package/dist/team/__tests__/model-contract.test.js +25 -25
  186. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  187. package/dist/team/__tests__/runtime.test.js +28 -28
  188. package/dist/team/__tests__/runtime.test.js.map +1 -1
  189. package/dist/team/__tests__/scaling.test.js +7 -7
  190. package/dist/team/__tests__/scaling.test.js.map +1 -1
  191. package/dist/team/__tests__/tmux-claude-workers-demo.test.js +5 -5
  192. package/dist/team/__tests__/tmux-claude-workers-demo.test.js.map +1 -1
  193. package/dist/team/__tests__/tmux-session.test.js +12 -12
  194. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  195. package/dist/team/__tests__/worker-bootstrap.test.js +57 -9
  196. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  197. package/dist/team/__tests__/worker-runtime-identity.test.js +3 -3
  198. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  199. package/dist/team/model-contract.d.ts +1 -1
  200. package/dist/team/model-contract.d.ts.map +1 -1
  201. package/dist/team/runtime.d.ts.map +1 -1
  202. package/dist/team/runtime.js +11 -0
  203. package/dist/team/runtime.js.map +1 -1
  204. package/dist/team/worker-bootstrap.d.ts +2 -0
  205. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  206. package/dist/team/worker-bootstrap.js +6 -1
  207. package/dist/team/worker-bootstrap.js.map +1 -1
  208. package/dist/ultragoal/__tests__/artifacts.test.js +82 -5
  209. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  210. package/dist/ultragoal/artifacts.d.ts +5 -1
  211. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  212. package/dist/ultragoal/artifacts.js +111 -14
  213. package/dist/ultragoal/artifacts.js.map +1 -1
  214. package/dist/utils/__tests__/agents-model-table.test.js +7 -7
  215. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
  216. package/dist/utils/__tests__/worktree-tool-context.test.d.ts +2 -0
  217. package/dist/utils/__tests__/worktree-tool-context.test.d.ts.map +1 -0
  218. package/dist/utils/__tests__/worktree-tool-context.test.js +118 -0
  219. package/dist/utils/__tests__/worktree-tool-context.test.js.map +1 -0
  220. package/dist/utils/worktree-tool-context.d.ts +25 -0
  221. package/dist/utils/worktree-tool-context.d.ts.map +1 -0
  222. package/dist/utils/worktree-tool-context.js +116 -0
  223. package/dist/utils/worktree-tool-context.js.map +1 -0
  224. package/package.json +1 -1
  225. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  226. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +96 -10
  227. package/plugins/oh-my-codex/skills/ai-slop-cleaner/SKILL.md +1 -1
  228. package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -1
  229. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +5 -5
  230. package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +3 -3
  231. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
  232. package/plugins/oh-my-codex/skills/team/SKILL.md +1 -1
  233. package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +2 -2
  234. package/prompts/prometheus-strict-metis.md +1 -1
  235. package/skills/ai-slop-cleaner/SKILL.md +1 -1
  236. package/skills/code-review/SKILL.md +1 -1
  237. package/skills/ecomode/references/agent-tiers.md +1 -1
  238. package/skills/omx-setup/SKILL.md +5 -5
  239. package/skills/prometheus-strict/SKILL.md +3 -3
  240. package/skills/ralplan/SKILL.md +1 -1
  241. package/skills/team/SKILL.md +1 -1
  242. package/skills/ultrawork/references/agent-tiers.md +2 -2
  243. package/src/scripts/__tests__/codex-native-hook.test.ts +824 -7
  244. package/src/scripts/codex-native-hook.ts +347 -20
  245. package/src/scripts/generate-catalog-docs.ts +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AA8CA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAiCtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAoDlE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,MAAM,CAAC;AAEX,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,UAAU,yBAAyB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6BAA6B,CAAC,EAAE,OAAO,2BAA2B,CAAC;CACpE;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AAmfD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,kBAAkB,GAAG,IAAI,GACvC,MAAM,GAAG,IAAI,CAmBf;AAsxBD,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IACP,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC,GACL,MAAM,GAAG,IAAI,CAuBf;AA2mCD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMnE;AA0lKD,wBAAsB,wCAAwC,CAC5D,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAyCzC;AA20CD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CA4VnC;AA6BD,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAGT;AAyOD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyC3D"}
1
+ {"version":3,"file":"codex-native-hook.d.ts","sourceRoot":"","sources":["../../src/scripts/codex-native-hook.ts"],"names":[],"mappings":"AA+CA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AAiCtC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAyDlE,KAAK,kBAAkB,GACnB,cAAc,GACd,YAAY,GACZ,aAAa,GACb,kBAAkB,GAClB,YAAY,GACZ,aAAa,GACb,MAAM,CAAC;AAEX,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,UAAU,yBAAyB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6BAA6B,CAAC,EAAE,OAAO,2BAA2B,CAAC;CACpE;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AAmfD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,kBAAkB,GAAG,IAAI,GACvC,MAAM,GAAG,IAAI,CAmBf;AAsxBD,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IACP,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC,GACL,MAAM,GAAG,IAAI,CAuBf;AA4tCD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMnE;AA0uKD,wBAAsB,wCAAwC,CAC5D,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAqDzC;AA83CD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,wBAAwB,CAAC,CA6VnC;AA6BD,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAGT;AAyOD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyC3D"}
@@ -6,7 +6,7 @@ import { pathToFileURL } from "url";
6
6
  import { readModeStateForActiveDecision, readModeStateForSession, updateModeState } from "../modes/base.js";
7
7
  import { redactAuthSecrets } from "../auth/redact.js";
8
8
  import { SKILL_ACTIVE_STATE_FILE, extractSessionIdFromInitializedStatePath, getSkillActiveStatePathsForStateDir, listActiveSkills, readSkillActiveState, readVisibleSkillActiveStateForStateDir, } from "../state/skill-active.js";
9
- import { isTrustedSubagentThread, readSubagentSessionSummary, readSubagentTrackingState, recordSubagentTurnForSession, } from "../subagents/tracker.js";
9
+ import { isTrustedSubagentThread, readSubagentSessionSummary, readSubagentSessionLedger, readSubagentTrackingState, recordSubagentTurnForSession, } from "../subagents/tracker.js";
10
10
  import { resolveCanonicalTeamStateRoot, resolveWorkerNotifyTeamStateRootPath } from "../team/state-root.js";
11
11
  import { inferTerminalLifecycleOutcome } from "../runtime/run-outcome.js";
12
12
  import { appendToLog, isSessionStale, isSessionStateUsable, readSessionState, readUsableSessionState, reconcileNativeSessionStart, } from "../hooks/session.js";
@@ -31,7 +31,7 @@ import { onPreCompact as buildWikiPreCompactContext, onSessionStart as buildWiki
31
31
  import { readAutoresearchCompletionStatus, readAutoresearchModeStateForActiveDecision } from "../autoresearch/skill-validation.js";
32
32
  import { AGENT_DEFINITIONS } from "../agents/definitions.js";
33
33
  import { deriveAutopilotChildPhase, normalizeAutopilotPhase } from "../autopilot/fsm.js";
34
- import { CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES, LEADER_CONDUCTOR_BLOCK, LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE, actionKindForConductorArtifact, authorizeConductorAction, classifyConductorArtifactKind, } from "../leader/contract.js";
34
+ import { CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES, LEADER_CONDUCTOR_BLOCK, LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE, NATIVE_SUBAGENT_SUPPORT_BLOCKER_FILE, actionKindForConductorArtifact, authorizeConductorAction, buildUnsupportedNativeSubagentGuidance, classifyConductorArtifactKind, isUnsupportedNativeSubagentEvidence, resolveNativeSubagentSupportStatus, } from "../leader/contract.js";
35
35
  import { readRunState } from "../runtime/run-state.js";
36
36
  import { evaluateRalphCompletionAuditEvidence, isRalphCompletePhase } from "../ralph/completion-audit.js";
37
37
  import { buildCodexGoalTerminalCleanupNotice, } from "../goal-workflows/codex-goal-snapshot.js";
@@ -1463,6 +1463,76 @@ async function ensureOmxLocalIgnoreEntry(cwd) {
1463
1463
  await writeFile(excludePath, next);
1464
1464
  return { changed: true, excludePath };
1465
1465
  }
1466
+ function readSessionStartSource(payload) {
1467
+ return safeString(payload?.source ?? payload?.session_start_source ?? payload?.sessionStartSource).trim().toLowerCase();
1468
+ }
1469
+ function shouldBuildSubagentReopenContext(options) {
1470
+ if (options.hookEventName !== "SessionStart")
1471
+ return false;
1472
+ const source = readSessionStartSource(options.payload);
1473
+ return source === "startup" || source === "resume";
1474
+ }
1475
+ function formatSubagentLedgerMetadata(entry) {
1476
+ const metadata = [
1477
+ entry.role ? `role: ${entry.role}` : null,
1478
+ entry.laneId ? `lane: ${entry.laneId}` : null,
1479
+ entry.scope ? `scope: ${entry.scope}` : null,
1480
+ entry.status ? `status: ${entry.status}` : null,
1481
+ entry.lastHandoffSummary ? `handoff: ${entry.lastHandoffSummary.slice(0, 120)}` : null,
1482
+ entry.resumeFailureReason ? `last failure: ${entry.resumeFailureReason.slice(0, 120)}` : null,
1483
+ ].filter((item) => Boolean(item));
1484
+ return metadata.length > 0 ? ` (${metadata.join("; ")})` : "";
1485
+ }
1486
+ async function buildPersistedSubagentReopenContext(cwd, sessionId, options) {
1487
+ if (!shouldBuildSubagentReopenContext(options))
1488
+ return null;
1489
+ const ledger = await readSubagentSessionLedger(cwd, sessionId).catch(() => null);
1490
+ if (!ledger || ledger.savedSubagents.length === 0)
1491
+ return null;
1492
+ const source = readSessionStartSource(options.payload);
1493
+ const reopenTargets = ledger.resumeTargets.filter((entry) => entry.status !== "unavailable");
1494
+ const unavailableTargets = ledger.unavailableSubagents;
1495
+ const failedTargets = ledger.savedSubagents.filter((entry) => entry.resumeFailedAt || entry.resumeFailureReason);
1496
+ const nowIso = new Date().toISOString();
1497
+ await Promise.all(reopenTargets.map((entry) => recordSubagentTurnForSession(cwd, {
1498
+ sessionId,
1499
+ threadId: entry.threadId,
1500
+ kind: "subagent",
1501
+ role: entry.role,
1502
+ laneId: entry.laneId,
1503
+ scope: entry.scope,
1504
+ agentNickname: entry.agentNickname,
1505
+ status: entry.status,
1506
+ resumeRequestedAt: nowIso,
1507
+ preserveCompletionEvidence: true,
1508
+ }).catch(() => null)));
1509
+ const lines = [
1510
+ "[Persisted subagent reopen]",
1511
+ `- SessionStart source: ${source}; saved subagent ids found: ${ledger.savedSubagents.length}.`,
1512
+ ];
1513
+ if (reopenTargets.length > 0) {
1514
+ lines.push("- Reopen these persisted subagents by id before continuing work or spawning any same-role/same-lane replacement:");
1515
+ for (const entry of reopenTargets.slice(0, 12)) {
1516
+ lines.push(` - resume_agent(${JSON.stringify(entry.agentId)})${formatSubagentLedgerMetadata(entry)}`);
1517
+ }
1518
+ if (reopenTargets.length > 12) {
1519
+ lines.push(` - ... ${reopenTargets.length - 12} more saved subagent id(s) omitted from this compact SessionStart context; consult .omx/state/subagent-tracking.json before spawning replacements.`);
1520
+ }
1521
+ }
1522
+ else {
1523
+ lines.push("- No compatible saved subagent id is currently marked reopenable; do not spawn a replacement merely because reopen was unavailable.");
1524
+ }
1525
+ lines.push("- Silver rule: when follow-up work targets an existing role/lane, reuse the matching reopened id; avoid duplicate same-type subagent spawns.");
1526
+ lines.push("- If resume_agent fails, surface a clear warning with the id and reason, then continue in the root or another compatible existing lane; do not spawn a new agent solely because reopen failed.");
1527
+ const warningEntries = [...new Map([...unavailableTargets, ...failedTargets].map((entry) => [entry.agentId, entry])).values()];
1528
+ if (warningEntries.length > 0) {
1529
+ lines.push("- Reopen warnings:");
1530
+ for (const entry of warningEntries.slice(0, 8)) {
1531
+ lines.push(` - ${entry.agentId}${formatSubagentLedgerMetadata(entry)}`);
1532
+ }
1533
+ }
1534
+ return lines.join("\n");
1535
+ }
1466
1536
  async function buildSessionStartContext(cwd, sessionId, options = {}) {
1467
1537
  const sections = [];
1468
1538
  sections.push(buildExecutionEnvironmentSection(cwd, {
@@ -1560,6 +1630,13 @@ async function buildSessionStartContext(cwd, sessionId, options = {}) {
1560
1630
  if (subagentSummary && subagentSummary.activeSubagentThreadIds.length > 0) {
1561
1631
  sections.push(`[Subagents]\n- active subagent threads: ${subagentSummary.activeSubagentThreadIds.length}`);
1562
1632
  }
1633
+ const persistedSubagentReopenContext = await buildPersistedSubagentReopenContext(cwd, sessionId, {
1634
+ hookEventName: options.hookEventName,
1635
+ payload: options.payload,
1636
+ });
1637
+ if (persistedSubagentReopenContext) {
1638
+ sections.push(persistedSubagentReopenContext);
1639
+ }
1563
1640
  return sections.length > 0 ? sections.join("\n\n") : null;
1564
1641
  }
1565
1642
  function resolveExecutionEnvironment(cwd, options = {}) {
@@ -1722,6 +1799,17 @@ function buildAutopilotPromptActivationNote(skillState, options = {}) {
1722
1799
  const teamHandoff = readTeamModeConfig(options.cwd).enabled
1723
1800
  ? " (+ $team if needed)"
1724
1801
  : "";
1802
+ const stateDir = getBaseStateDir(options.cwd);
1803
+ const nativeSubagentSupport = resolveNativeSubagentSupportStatus({
1804
+ payload: options.payload,
1805
+ persistedSupportBlocker: readJsonSyncIfExists(nativeSubagentSupportBlockerPath(stateDir)),
1806
+ persistedCapacityBlocker: readJsonSyncIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
1807
+ cwd: options.cwd,
1808
+ sessionId: options.sessionId,
1809
+ });
1810
+ const conductorGuidance = nativeSubagentSupport.status === "unsupported"
1811
+ ? buildUnsupportedNativeSubagentGuidance(nativeSubagentSupport)
1812
+ : `${LEADER_CONDUCTOR_BLOCK} ${LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE}`;
1725
1813
  return [
1726
1814
  `Autopilot protocol: the durable default chain is $deep-interview -> $ralplan -> $ultragoal${teamHandoff} -> $code-review -> $ultraqa (deep-interview -> ralplan -> ultragoal -> code-review -> ultraqa).`,
1727
1815
  "Start/resume at current_phase=deep-interview unless the task is clear and bounded; if deep-interview is intentionally skipped, persist and state an explicit deep_interview_gate.skip_reason before moving to ralplan.",
@@ -1733,8 +1821,7 @@ function buildAutopilotPromptActivationNote(skillState, options = {}) {
1733
1821
  "The ralplan phase is not complete until Planner output has been reviewed sequentially by Architect and then Critic; do not hand off to Ultragoal or implementation until the ralplan state/artifact records both ralplan_architect_review and ralplan_critic_review with approval or an explicit blocker.",
1734
1822
  "Do not silently fall back to ordinary $plan/ralplan-only handling; keep autopilot-state.json, skill-active-state.json, HUD/statusline, and Codex goal-mode handoff guidance visible while the workflow is active.",
1735
1823
  "When Codex goal tools are available, call get_goal/create_goal only from the active thread handoff and treat the active goal as the completion contract until code-review and ultraqa are clean.",
1736
- LEADER_CONDUCTOR_BLOCK,
1737
- LEADER_CONDUCTOR_REUSE_AND_LEDGER_GUIDANCE,
1824
+ conductorGuidance,
1738
1825
  ].filter(Boolean).join(" ");
1739
1826
  }
1740
1827
  function formatExecutionHandoffList(cwd) {
@@ -1761,7 +1848,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
1761
1848
  : null;
1762
1849
  const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
1763
1850
  const markedQuestionAnswer = /^\s*\[omx question answered\]/i.test(prompt);
1764
- const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer, cwd });
1851
+ const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer, cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
1765
1852
  return [
1766
1853
  `OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}".`,
1767
1854
  promptPriorityMessage,
@@ -1785,7 +1872,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
1785
1872
  ? buildDeepInterviewQuestionBridgeInstruction(cwd, payload)
1786
1873
  : null;
1787
1874
  const deepInterviewConfigPromptActivationNote = buildDeepInterviewConfigInstruction(cwd, skillState);
1788
- const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer: true, cwd });
1875
+ const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { markedQuestionAnswer: true, cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
1789
1876
  return [
1790
1877
  `OMX native UserPromptSubmit continued active workflow skill "${continuedSkill}"; workflow-like tokens inside the marked omx question answer are treated as answer text, not a new workflow activation.`,
1791
1878
  promptPriorityMessage,
@@ -1818,7 +1905,7 @@ function buildAdditionalContextMessage(prompt, skillState, cwd = process.cwd(),
1818
1905
  const ultragoalPromptActivationNote = match.skill === "ultragoal"
1819
1906
  ? "Ultragoal protocol: use `omx ultragoal create-goals` / `complete-goals` / `checkpoint` for `.omx/ultragoal` artifacts, then use Codex goal model tools only from the active agent handoff (`get_goal`, `create_goal`, `update_goal`) and never overwrite a different active Codex goal. Ultragoal does not call `/goal clear`; for multiple sequential ultragoal runs in one Codex session/thread, manually clear the completed Codex goal in the UI before creating the next aggregate goal."
1820
1907
  : null;
1821
- const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { cwd });
1908
+ const autopilotPromptActivationNote = buildAutopilotPromptActivationNote(skillState, { cwd, payload, sessionId: safeString(skillState?.session_id).trim() });
1822
1909
  const combinedTransitionMessage = (() => {
1823
1910
  if (!skillState?.transition_message)
1824
1911
  return null;
@@ -2574,6 +2661,17 @@ function readPayloadTurnId(payload) {
2574
2661
  function nativeSubagentCapacityBlockerPath(stateDir) {
2575
2662
  return join(stateDir, NATIVE_SUBAGENT_CAPACITY_BLOCKER_FILE);
2576
2663
  }
2664
+ function nativeSubagentSupportBlockerPath(stateDir) {
2665
+ return join(stateDir, NATIVE_SUBAGENT_SUPPORT_BLOCKER_FILE);
2666
+ }
2667
+ function readJsonSyncIfExists(path) {
2668
+ try {
2669
+ return JSON.parse(readFileSync(path, "utf-8"));
2670
+ }
2671
+ catch {
2672
+ return null;
2673
+ }
2674
+ }
2577
2675
  function stringifyUnknown(value) {
2578
2676
  if (typeof value === "string")
2579
2677
  return value;
@@ -2602,6 +2700,44 @@ function isNativeSubagentCapacityFailure(payload) {
2602
2700
  const toolName = safeString(payload.tool_name).trim();
2603
2701
  return !toolName || /(?:spawn_agent|multi_agent|subagent|collab|agent)/i.test(toolName);
2604
2702
  }
2703
+ function nativeSubagentFailureReason(payload) {
2704
+ const evidence = payloadEvidenceText(payload);
2705
+ const toolName = safeString(payload.tool_name).trim();
2706
+ if (toolName && !/(?:spawn_agent|multi_agent|subagent|collab|agent)/i.test(toolName))
2707
+ return null;
2708
+ if (/\bagent thread limit reached\b/i.test(evidence))
2709
+ return null;
2710
+ if (/\bnative subagents? (?:unsupported|disabled|not enabled|unavailable|not found)\b/i.test(evidence))
2711
+ return "native_subagents_unsupported";
2712
+ if (/\bmulti_agent_v1\b/i.test(evidence) && /\b(?:unavailable|unknown tool|disabled|not enabled|not found|unsupported)\b/i.test(evidence))
2713
+ return "multi_agent_v1_unavailable";
2714
+ if (/\b(?:unknown tool|tool not found|not enabled|disabled|unavailable|unsupported)\b/i.test(evidence))
2715
+ return "multi_agent_v1_unavailable";
2716
+ return null;
2717
+ }
2718
+ function summarizeNativeSubagentSupportFailure(text) {
2719
+ const normalized = text.replace(/\s+/g, " ").trim();
2720
+ return (normalized || "native subagent support unavailable").slice(0, 500);
2721
+ }
2722
+ async function recordNativeSubagentSupportBlocker(cwd, stateDir, payload) {
2723
+ const reason = nativeSubagentFailureReason(payload);
2724
+ if (!reason)
2725
+ return;
2726
+ const nowIso = new Date().toISOString();
2727
+ await mkdir(stateDir, { recursive: true });
2728
+ await writeFile(nativeSubagentSupportBlockerPath(stateDir), JSON.stringify({
2729
+ schema_version: 1,
2730
+ status: "unsupported",
2731
+ reason,
2732
+ ...(readPayloadSessionId(payload) ? { session_id: readPayloadSessionId(payload) } : {}),
2733
+ ...(readPayloadThreadId(payload) ? { thread_id: readPayloadThreadId(payload) } : {}),
2734
+ ...(readPayloadTurnId(payload) ? { turn_id: readPayloadTurnId(payload) } : {}),
2735
+ ...(safeString(payload.tool_name).trim() ? { tool_name: safeString(payload.tool_name).trim() } : {}),
2736
+ evidence: summarizeNativeSubagentSupportFailure(payloadEvidenceText(payload)),
2737
+ observed_at: nowIso,
2738
+ cwd,
2739
+ }, null, 2));
2740
+ }
2605
2741
  function summarizeCapacityFailure(text) {
2606
2742
  const normalized = text.replace(/\s+/g, " ").trim();
2607
2743
  if (!normalized)
@@ -2791,6 +2927,7 @@ const PROTECTED_PLANNING_STATE_FILE_NAMES = new Set([
2791
2927
  "ralplan-state.json",
2792
2928
  "skill-active-state.json",
2793
2929
  ]);
2930
+ const RUNTIME_SESSION_ID_SEGMENT_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
2794
2931
  const PLANNING_MODE_IMPLEMENTATION_TOOL_NAMES = new Set([
2795
2932
  "Write",
2796
2933
  "Edit",
@@ -2821,6 +2958,15 @@ function isActiveDeepInterviewPhase(state) {
2821
2958
  return false;
2822
2959
  return true;
2823
2960
  }
2961
+ function isInactiveCompletedDeepInterviewPhase(state) {
2962
+ if (!state || state.active !== false)
2963
+ return false;
2964
+ const mode = safeString(state.mode).trim();
2965
+ if (mode && mode !== "deep-interview")
2966
+ return false;
2967
+ const phase = safeString(state.current_phase ?? state.currentPhase).trim().toLowerCase();
2968
+ return phase === "complete" || phase === "completed";
2969
+ }
2824
2970
  function isActiveRalplanPhase(state) {
2825
2971
  if (!state || state.active !== true)
2826
2972
  return false;
@@ -2866,6 +3012,33 @@ function isProtectedPlanningStatePath(relativePath) {
2866
3012
  const fileName = relativePath.split("/").pop() ?? "";
2867
3013
  return PROTECTED_PLANNING_STATE_FILE_NAMES.has(fileName);
2868
3014
  }
3015
+ function isAllowedAuthoritativeRuntimePlanningStatePath(cwd, rawPath) {
3016
+ const trimmed = rawPath.trim().replace(/^['"]|['"]$/g, "");
3017
+ if (!trimmed || trimmed.includes("\0"))
3018
+ return false;
3019
+ let targetPath;
3020
+ let baseStateDir;
3021
+ try {
3022
+ targetPath = resolve(cwd, trimmed);
3023
+ baseStateDir = resolve(getBaseStateDir(cwd));
3024
+ }
3025
+ catch {
3026
+ return false;
3027
+ }
3028
+ const localStateDir = resolve(cwd, ".omx", "state");
3029
+ if (baseStateDir === localStateDir)
3030
+ return false;
3031
+ const relativeToBase = relative(baseStateDir, targetPath).replace(/\\/g, "/");
3032
+ if (!relativeToBase || relativeToBase.startsWith("..") || relativeToBase.startsWith("/"))
3033
+ return false;
3034
+ const segments = relativeToBase.split("/");
3035
+ if (segments.length !== 3 || segments[0] !== "sessions")
3036
+ return false;
3037
+ const sessionId = segments[1] ?? "";
3038
+ const fileName = segments[2] ?? "";
3039
+ return RUNTIME_SESSION_ID_SEGMENT_PATTERN.test(sessionId)
3040
+ && PROTECTED_PLANNING_STATE_FILE_NAMES.has(fileName);
3041
+ }
2869
3042
  function isPlanningTmpRelativePath(relativePath) {
2870
3043
  return relativePath === ".omx/tmp" || relativePath.startsWith(".omx/tmp/");
2871
3044
  }
@@ -2881,9 +3054,9 @@ function isAllowedPlanningTmpScratchPath(relativePath) {
2881
3054
  function isAllowedPlanningArtifactPath(cwd, rawPath, allowedPrefixes) {
2882
3055
  const relativePath = normalizePlanningArtifactRelativePath(cwd, rawPath);
2883
3056
  if (!relativePath)
2884
- return false;
3057
+ return isAllowedAuthoritativeRuntimePlanningStatePath(cwd, rawPath);
2885
3058
  if (isProtectedPlanningStatePath(relativePath))
2886
- return false;
3059
+ return isAllowedAuthoritativeRuntimePlanningStatePath(cwd, rawPath);
2887
3060
  if (isPlanningTmpRelativePath(relativePath)) {
2888
3061
  return allowedPrefixes.includes(".omx/tmp") && isAllowedPlanningTmpScratchPath(relativePath);
2889
3062
  }
@@ -5262,6 +5435,56 @@ function isPackageManagerCommandWord(word) {
5262
5435
  const base = shellWordBaseName(word);
5263
5436
  return base === "npm" || base === "pnpm" || base === "yarn" || base === "npx" || base === "pnpx";
5264
5437
  }
5438
+ function isStructuredUltragoalSteeringShellCommand(command) {
5439
+ const segments = splitShellCommandSegments(stripHeredocBodiesForCommandScan(command));
5440
+ let sawStructuredSteer = false;
5441
+ for (const segment of segments) {
5442
+ const words = tokenizeShellWords(segment);
5443
+ let commandStart = true;
5444
+ let inForHeader = false;
5445
+ for (let index = 0; index < words.length; index += 1) {
5446
+ const word = words[index] ?? "";
5447
+ if (!word)
5448
+ continue;
5449
+ if (isShellCommandSeparator(word)) {
5450
+ commandStart = true;
5451
+ continue;
5452
+ }
5453
+ if (inForHeader) {
5454
+ if (word === "do") {
5455
+ inForHeader = false;
5456
+ commandStart = true;
5457
+ }
5458
+ continue;
5459
+ }
5460
+ if (isShellGroupingSyntaxWord(word))
5461
+ continue;
5462
+ if (commandStart && isEnvironmentAssignmentWord(word))
5463
+ continue;
5464
+ if (commandStart && CONDUCTOR_BASH_COMPOUND_SYNTAX_WORDS.has(word)) {
5465
+ if (word === "for")
5466
+ inForHeader = true;
5467
+ continue;
5468
+ }
5469
+ if (commandStart && word.startsWith("-"))
5470
+ continue;
5471
+ if (!commandStart)
5472
+ continue;
5473
+ const commandName = commandNameFromShellWord(word);
5474
+ if (commandName === "read" || commandName === "true" || commandName === ":") {
5475
+ commandStart = false;
5476
+ continue;
5477
+ }
5478
+ if (commandName === "omx" && words[index + 1] === "ultragoal" && words[index + 2] === "steer") {
5479
+ sawStructuredSteer = true;
5480
+ commandStart = false;
5481
+ continue;
5482
+ }
5483
+ return false;
5484
+ }
5485
+ }
5486
+ return sawStructuredSteer;
5487
+ }
5265
5488
  function hasDynamicNestedShellExecution(command) {
5266
5489
  const commands = splitShellCommandSegments(stripHeredocBodiesForCommandScan(command));
5267
5490
  for (const segment of commands) {
@@ -5289,13 +5512,13 @@ function hasDynamicNestedShellExecution(command) {
5289
5512
  return true;
5290
5513
  if (commandStringIndex !== null) {
5291
5514
  const nestedCommand = words[commandStringIndex] ?? "";
5292
- if (isDynamicNestedCommandString(nestedCommand))
5515
+ if (isDynamicNestedCommandString(nestedCommand) && !isStructuredUltragoalSteeringShellCommand(nestedCommand))
5293
5516
  return true;
5294
5517
  }
5295
5518
  }
5296
5519
  if (word === "eval") {
5297
5520
  const nestedCommand = words.slice(index + 1).join(" ");
5298
- if (isDynamicNestedCommandString(nestedCommand))
5521
+ if (isDynamicNestedCommandString(nestedCommand) && !isStructuredUltragoalSteeringShellCommand(nestedCommand))
5299
5522
  return true;
5300
5523
  }
5301
5524
  }
@@ -6030,6 +6253,8 @@ async function readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionI
6030
6253
  if (hasActiveDeepInterviewSkill)
6031
6254
  return modeState;
6032
6255
  }
6256
+ if (isInactiveCompletedDeepInterviewPhase(modeState))
6257
+ return null;
6033
6258
  const autopilotState = sessionId
6034
6259
  ? await readStopSessionPinnedState("autopilot-state.json", cwd, sessionId, stateDir)
6035
6260
  : await readJsonIfExists(join(stateDir, "autopilot-state.json"));
@@ -6174,7 +6399,7 @@ function buildDeepInterviewBashBlockedDetail(cwd, command) {
6174
6399
  }
6175
6400
  async function buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir, resolvedSessionId) {
6176
6401
  const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
6177
- if (await hasTrustedTypedSubagentThreadSpawnProvenanceForPreToolUse(payload, cwd, sessionId))
6402
+ if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId))
6178
6403
  return null;
6179
6404
  const threadId = readPayloadThreadId(payload);
6180
6405
  const activeState = await readActiveRalplanStateForPreToolUse(cwd, stateDir, sessionId, threadId);
@@ -6233,7 +6458,7 @@ async function buildRalplanPreToolUseBoundaryOutput(payload, cwd, stateDir, reso
6233
6458
  }
6234
6459
  async function buildDeepInterviewPreToolUseBoundaryOutput(payload, cwd, stateDir, resolvedSessionId) {
6235
6460
  const sessionId = safeString(resolvedSessionId ?? readPayloadSessionId(payload)).trim();
6236
- if (await hasTrustedTypedSubagentThreadSpawnProvenanceForPreToolUse(payload, cwd, sessionId))
6461
+ if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId))
6237
6462
  return null;
6238
6463
  const threadId = readPayloadThreadId(payload);
6239
6464
  const activeState = await readActiveDeepInterviewStateForPreToolUse(cwd, stateDir, sessionId, threadId);
@@ -6351,9 +6576,18 @@ async function buildPlanningRootPointerConflictPreToolUseOutput(payload, cwd, st
6351
6576
  }
6352
6577
  return blocked ? buildRalplanRootPointerConflictBlock(ralplanState) : null;
6353
6578
  }
6354
- async function hasTrustedTypedSubagentThreadSpawnProvenanceForPreToolUse(payload, cwd, sessionId) {
6579
+ async function hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId) {
6355
6580
  if (hasTeamWorkerEnvironment())
6356
6581
  return true;
6582
+ if (!isTypedAgentRolePayload(payload))
6583
+ return false;
6584
+ const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
6585
+ const session = trackingState?.sessions?.[sessionId];
6586
+ if (!session)
6587
+ return false;
6588
+ const payloadThreadId = readPayloadThreadId(payload);
6589
+ if (payloadThreadId && isTrustedSubagentThread(session, payloadThreadId))
6590
+ return true;
6357
6591
  const source = safeObject(payload.source);
6358
6592
  const subagent = safeObject(source.subagent);
6359
6593
  const threadSpawn = safeObject(subagent.thread_spawn);
@@ -6363,13 +6597,10 @@ async function hasTrustedTypedSubagentThreadSpawnProvenanceForPreToolUse(payload
6363
6597
  ?? threadSpawn.leaderThreadId).trim();
6364
6598
  if (!parentThreadId)
6365
6599
  return false;
6366
- if (!isTypedAgentRolePayload(payload))
6367
- return false;
6368
- const trackingState = await readSubagentTrackingState(cwd).catch(() => null);
6369
- const session = trackingState?.sessions?.[sessionId];
6370
- if (!session)
6600
+ const leaderThreadId = safeString(session.leader_thread_id).trim();
6601
+ if (payloadThreadId && leaderThreadId && payloadThreadId === leaderThreadId)
6371
6602
  return false;
6372
- return session.leader_thread_id === parentThreadId || parentThreadId in session.threads;
6603
+ return leaderThreadId === parentThreadId || parentThreadId in session.threads;
6373
6604
  }
6374
6605
  function isActiveConductorModeState(state, mode, sessionId) {
6375
6606
  if (!state || state.active !== true)
@@ -6396,7 +6627,7 @@ async function readActiveMainRootConductorStateForPreToolUse(payload, cwd, state
6396
6627
  const threadId = readPayloadThreadId(payload);
6397
6628
  if (!sessionId)
6398
6629
  return null;
6399
- if (await hasTrustedTypedSubagentThreadSpawnProvenanceForPreToolUse(payload, cwd, sessionId))
6630
+ if (await hasTrustedTypedSubagentProvenanceForPreToolUse(payload, cwd, sessionId))
6400
6631
  return null;
6401
6632
  const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
6402
6633
  if (!canonicalState)
@@ -7211,6 +7442,13 @@ export async function buildConductorPreToolUseWriteGuardOutput(payload, cwd, sta
7211
7442
  const activeState = await readActiveMainRootConductorStateForPreToolUse(payload, cwd, stateDir, resolvedSessionId);
7212
7443
  if (!activeState)
7213
7444
  return null;
7445
+ const nativeSubagentSupport = resolveNativeSubagentSupportStatus({
7446
+ payload,
7447
+ persistedSupportBlocker: await readJsonIfExists(nativeSubagentSupportBlockerPath(stateDir)),
7448
+ persistedCapacityBlocker: await readJsonIfExists(nativeSubagentCapacityBlockerPath(stateDir)),
7449
+ cwd,
7450
+ sessionId: resolvedSessionId || readPayloadSessionId(payload),
7451
+ });
7214
7452
  const toolName = safeString(payload.tool_name).trim();
7215
7453
  const command = readPreToolUseCommand(payload);
7216
7454
  const pathCandidates = readPreToolUsePathCandidates(payload);
@@ -7237,6 +7475,9 @@ export async function buildConductorPreToolUseWriteGuardOutput(payload, cwd, sta
7237
7475
  }
7238
7476
  if (!blocked)
7239
7477
  return null;
7478
+ const unsupportedNativeGuidance = isUnsupportedNativeSubagentEvidence(nativeSubagentSupport)
7479
+ ? ` ${buildUnsupportedNativeSubagentGuidance(nativeSubagentSupport)} Treat the active conductor workflow as blocked/cancelled for native delegation recovery; do not call multi_agent_v1.close_agent.`
7480
+ : "";
7240
7481
  return {
7241
7482
  decision: "block",
7242
7483
  reason: `Main-root Conductor mode is active (${activeState.mode} phase: ${formatPhase(activeState.phase, "active")}); direct plan/code writes are blocked and must be delegated; ${blockedDetail}.`,
@@ -7245,7 +7486,8 @@ export async function buildConductorPreToolUseWriteGuardOutput(payload, cwd, sta
7245
7486
  additionalContext: `${LEADER_CONDUCTOR_GOLDEN_RULE} `
7246
7487
  + "Use specialized agents for source edits and plan/spec authorship. "
7247
7488
  + `Main-root Conductor may write only orchestration metadata/transport/ledger artifacts under ${CONDUCTOR_ORCHESTRATION_METADATA_PREFIXES.join(", ")}; path location alone is not authorization for substantive deliverables. `
7248
- + "Autopilot rework and typed subagent/worker lanes are exempt from this guard.",
7489
+ + unsupportedNativeGuidance
7490
+ + " Autopilot rework and typed subagent/worker lanes are exempt from this guard.",
7249
7491
  },
7250
7492
  };
7251
7493
  }
@@ -7380,6 +7622,44 @@ function modeStateHasExplicitMatchingCwd(state, cwd) {
7380
7622
  return false;
7381
7623
  }
7382
7624
  }
7625
+ async function clearNativeStopSessionEntries(stateDir, payload, canonicalSessionId) {
7626
+ const statePath = join(stateDir, NATIVE_STOP_STATE_FILE);
7627
+ const state = await readJsonIfExists(statePath);
7628
+ if (!state)
7629
+ return;
7630
+ const sessions = safeObject(state.sessions);
7631
+ const keys = new Set(uniqueNonEmpty([
7632
+ readNativeStopSessionKey(payload, canonicalSessionId),
7633
+ canonicalSessionId,
7634
+ readPayloadSessionId(payload),
7635
+ readPayloadThreadId(payload),
7636
+ ]));
7637
+ let changed = false;
7638
+ for (const key of keys) {
7639
+ if (Object.prototype.hasOwnProperty.call(sessions, key)) {
7640
+ delete sessions[key];
7641
+ changed = true;
7642
+ }
7643
+ }
7644
+ if (!changed)
7645
+ return;
7646
+ await writeFile(statePath, JSON.stringify({ ...state, sessions }, null, 2));
7647
+ }
7648
+ async function hasAuthoritativeInactiveSkillStopState(cwd, stateDir, skill, sessionId, threadId) {
7649
+ const sessionModeState = await readStopSessionPinnedState(`${skill}-state.json`, cwd, sessionId, stateDir);
7650
+ if (!sessionModeState || !isTerminalOrInactiveModeState(sessionModeState))
7651
+ return false;
7652
+ const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
7653
+ if (canonicalState && !rootSkillStateHasNoActiveSkillForStopContext(canonicalState, skill, sessionId, threadId)) {
7654
+ return false;
7655
+ }
7656
+ const rootModeState = await readJsonIfExists(join(stateDir, `${skill}-state.json`));
7657
+ if (!rootModeState)
7658
+ return true;
7659
+ if (!modeStateMatchesSkillStopContext(rootModeState, cwd, sessionId))
7660
+ return true;
7661
+ return isTerminalOrInactiveModeState(rootModeState);
7662
+ }
7383
7663
  async function readBlockingSkillForStop(cwd, stateDir, sessionId, threadId, requiredSkill) {
7384
7664
  const canonicalState = await readVisibleSkillActiveStateForStateDir(stateDir, sessionId);
7385
7665
  const visibleEntries = canonicalState ? listActiveSkills(canonicalState) : [];
@@ -8029,6 +8309,9 @@ async function buildStopHookOutput(payload, cwd, stateDir, options = {}) {
8029
8309
  const suppressParentWorkflowStop = shouldSuppressParentWorkflowStopForSideConversation(payload);
8030
8310
  if (canonicalSessionId) {
8031
8311
  await reconcileStaleRootSkillActiveStateForStop(cwd, stateDir, canonicalSessionId);
8312
+ if (await hasAuthoritativeInactiveSkillStopState(cwd, stateDir, "ralplan", canonicalSessionId, threadId)) {
8313
+ await clearNativeStopSessionEntries(stateDir, payload, canonicalSessionId);
8314
+ }
8032
8315
  }
8033
8316
  if (suppressParentWorkflowStop) {
8034
8317
  return null;
@@ -8454,6 +8737,7 @@ export async function dispatchCodexNativeHook(payload, options = {}) {
8454
8737
  }
8455
8738
  else if (hookEventName === "PostToolUse") {
8456
8739
  await recordNativeSubagentCapacityBlocker(cwd, stateDir, payload).catch(() => { });
8740
+ await recordNativeSubagentSupportBlocker(cwd, stateDir, payload).catch(() => { });
8457
8741
  if (detectMcpTransportFailure(payload)) {
8458
8742
  await markTeamTransportFailure(cwd, payload);
8459
8743
  }