oh-my-codex 0.18.13 → 0.18.15

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 (360) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +41 -18
  4. package/dist/agents/__tests__/native-config.test.js +62 -0
  5. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  6. package/dist/agents/native-config.d.ts.map +1 -1
  7. package/dist/agents/native-config.js +15 -2
  8. package/dist/agents/native-config.js.map +1 -1
  9. package/dist/autopilot/__tests__/fsm.test.js +7 -0
  10. package/dist/autopilot/__tests__/fsm.test.js.map +1 -1
  11. package/dist/autopilot/__tests__/planner-routing.test.d.ts +2 -0
  12. package/dist/autopilot/__tests__/planner-routing.test.d.ts.map +1 -0
  13. package/dist/autopilot/__tests__/planner-routing.test.js +74 -0
  14. package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -0
  15. package/dist/autopilot/__tests__/ralplan-gate.test.js +315 -0
  16. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  17. package/dist/autopilot/completion-gate.js +1 -1
  18. package/dist/autopilot/completion-gate.js.map +1 -1
  19. package/dist/autopilot/fsm.d.ts +2 -2
  20. package/dist/autopilot/fsm.d.ts.map +1 -1
  21. package/dist/autopilot/fsm.js +3 -0
  22. package/dist/autopilot/fsm.js.map +1 -1
  23. package/dist/autopilot/planner-routing.d.ts +21 -0
  24. package/dist/autopilot/planner-routing.d.ts.map +1 -0
  25. package/dist/autopilot/planner-routing.js +59 -0
  26. package/dist/autopilot/planner-routing.js.map +1 -0
  27. package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
  28. package/dist/autopilot/ralplan-gate.js +30 -0
  29. package/dist/autopilot/ralplan-gate.js.map +1 -1
  30. package/dist/autoresearch/goal.d.ts.map +1 -1
  31. package/dist/autoresearch/goal.js +10 -1
  32. package/dist/autoresearch/goal.js.map +1 -1
  33. package/dist/cli/__tests__/autoresearch-goal.test.js +33 -0
  34. package/dist/cli/__tests__/autoresearch-goal.test.js.map +1 -1
  35. package/dist/cli/__tests__/autoresearch-guided.test.js +3 -0
  36. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
  37. package/dist/cli/__tests__/codex-plugin-layout.test.js +30 -0
  38. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  39. package/dist/cli/__tests__/doctor-artifact-ownership.test.d.ts +2 -0
  40. package/dist/cli/__tests__/doctor-artifact-ownership.test.d.ts.map +1 -0
  41. package/dist/cli/__tests__/doctor-artifact-ownership.test.js +158 -0
  42. package/dist/cli/__tests__/doctor-artifact-ownership.test.js.map +1 -0
  43. package/dist/cli/__tests__/doctor-explore-deprecated.test.d.ts +2 -0
  44. package/dist/cli/__tests__/doctor-explore-deprecated.test.d.ts.map +1 -0
  45. package/dist/cli/__tests__/doctor-explore-deprecated.test.js +33 -0
  46. package/dist/cli/__tests__/doctor-explore-deprecated.test.js.map +1 -0
  47. package/dist/cli/__tests__/doctor-spark-routing.test.js +13 -0
  48. package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -1
  49. package/dist/cli/__tests__/doctor-warning-copy.test.js +132 -2
  50. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  51. package/dist/cli/__tests__/index.test.js +5 -0
  52. package/dist/cli/__tests__/index.test.js.map +1 -1
  53. package/dist/cli/__tests__/mcp-parity.test.js +40 -0
  54. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  55. package/dist/cli/__tests__/nested-help-routing.test.js +4 -0
  56. package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
  57. package/dist/cli/__tests__/package-bin-contract.test.js +7 -1
  58. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  59. package/dist/cli/__tests__/performance-goal.test.js +22 -0
  60. package/dist/cli/__tests__/performance-goal.test.js.map +1 -1
  61. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.d.ts +2 -0
  62. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.d.ts.map +1 -0
  63. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js +64 -0
  64. package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -0
  65. package/dist/cli/__tests__/resume.test.js +96 -0
  66. package/dist/cli/__tests__/resume.test.js.map +1 -1
  67. package/dist/cli/__tests__/session-scoped-runtime.test.js +162 -0
  68. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  69. package/dist/cli/__tests__/session-search.test.js +36 -0
  70. package/dist/cli/__tests__/session-search.test.js.map +1 -1
  71. package/dist/cli/__tests__/setup-agents-overwrite.test.js +70 -1
  72. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  73. package/dist/cli/__tests__/setup-install-mode.test.js +33 -0
  74. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  75. package/dist/cli/__tests__/team.test.js +17 -3
  76. package/dist/cli/__tests__/team.test.js.map +1 -1
  77. package/dist/cli/__tests__/ultragoal.test.js +37 -0
  78. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  79. package/dist/cli/__tests__/update.test.js +81 -2
  80. package/dist/cli/__tests__/update.test.js.map +1 -1
  81. package/dist/cli/__tests__/url.test.d.ts +2 -0
  82. package/dist/cli/__tests__/url.test.d.ts.map +1 -0
  83. package/dist/cli/__tests__/url.test.js +82 -0
  84. package/dist/cli/__tests__/url.test.js.map +1 -0
  85. package/dist/cli/autoresearch-goal.d.ts.map +1 -1
  86. package/dist/cli/autoresearch-goal.js +2 -1
  87. package/dist/cli/autoresearch-goal.js.map +1 -1
  88. package/dist/cli/autoresearch-intake.d.ts.map +1 -1
  89. package/dist/cli/autoresearch-intake.js +2 -0
  90. package/dist/cli/autoresearch-intake.js.map +1 -1
  91. package/dist/cli/doctor.d.ts +39 -1
  92. package/dist/cli/doctor.d.ts.map +1 -1
  93. package/dist/cli/doctor.js +460 -40
  94. package/dist/cli/doctor.js.map +1 -1
  95. package/dist/cli/index.d.ts +2 -2
  96. package/dist/cli/index.d.ts.map +1 -1
  97. package/dist/cli/index.js +71 -4
  98. package/dist/cli/index.js.map +1 -1
  99. package/dist/cli/performance-goal.d.ts.map +1 -1
  100. package/dist/cli/performance-goal.js +4 -2
  101. package/dist/cli/performance-goal.js.map +1 -1
  102. package/dist/cli/plugin-marketplace.d.ts +1 -0
  103. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  104. package/dist/cli/plugin-marketplace.js +88 -67
  105. package/dist/cli/plugin-marketplace.js.map +1 -1
  106. package/dist/cli/project-runtime-codex-homes.d.ts +2 -0
  107. package/dist/cli/project-runtime-codex-homes.d.ts.map +1 -1
  108. package/dist/cli/project-runtime-codex-homes.js +112 -5
  109. package/dist/cli/project-runtime-codex-homes.js.map +1 -1
  110. package/dist/cli/setup.d.ts.map +1 -1
  111. package/dist/cli/setup.js +15 -6
  112. package/dist/cli/setup.js.map +1 -1
  113. package/dist/cli/ultragoal.d.ts.map +1 -1
  114. package/dist/cli/ultragoal.js +5 -1
  115. package/dist/cli/ultragoal.js.map +1 -1
  116. package/dist/cli/update.d.ts.map +1 -1
  117. package/dist/cli/update.js +23 -4
  118. package/dist/cli/update.js.map +1 -1
  119. package/dist/cli/url.d.ts +8 -0
  120. package/dist/cli/url.d.ts.map +1 -0
  121. package/dist/cli/url.js +69 -0
  122. package/dist/cli/url.js.map +1 -0
  123. package/dist/config/__tests__/codex-hooks.test.js +20 -4
  124. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  125. package/dist/config/__tests__/models.test.js +21 -1
  126. package/dist/config/__tests__/models.test.js.map +1 -1
  127. package/dist/config/codex-hooks.d.ts.map +1 -1
  128. package/dist/config/codex-hooks.js +1 -4
  129. package/dist/config/codex-hooks.js.map +1 -1
  130. package/dist/config/models.d.ts +5 -0
  131. package/dist/config/models.d.ts.map +1 -1
  132. package/dist/config/models.js +23 -0
  133. package/dist/config/models.js.map +1 -1
  134. package/dist/goal-workflows/codex-goal-snapshot.d.ts +2 -0
  135. package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
  136. package/dist/goal-workflows/codex-goal-snapshot.js +10 -0
  137. package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
  138. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +7 -0
  139. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  140. package/dist/hooks/__tests__/keyword-detector.test.js +46 -0
  141. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  142. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +100 -0
  143. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  144. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +75 -0
  145. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  146. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +225 -0
  147. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  148. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +75 -0
  149. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  150. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +563 -0
  151. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  152. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +187 -12
  153. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  154. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +225 -0
  155. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  156. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
  157. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
  158. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +75 -0
  159. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  160. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  161. package/dist/hooks/keyword-detector.js +4 -0
  162. package/dist/hooks/keyword-detector.js.map +1 -1
  163. package/dist/hud/__tests__/reconcile.test.js +137 -2
  164. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  165. package/dist/hud/__tests__/state.test.js +107 -0
  166. package/dist/hud/__tests__/state.test.js.map +1 -1
  167. package/dist/hud/__tests__/tmux.test.js +17 -0
  168. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  169. package/dist/hud/reconcile.d.ts.map +1 -1
  170. package/dist/hud/reconcile.js +21 -7
  171. package/dist/hud/reconcile.js.map +1 -1
  172. package/dist/hud/render.d.ts.map +1 -1
  173. package/dist/hud/render.js +9 -0
  174. package/dist/hud/render.js.map +1 -1
  175. package/dist/hud/state.d.ts.map +1 -1
  176. package/dist/hud/state.js +43 -5
  177. package/dist/hud/state.js.map +1 -1
  178. package/dist/hud/types.d.ts +6 -0
  179. package/dist/hud/types.d.ts.map +1 -1
  180. package/dist/hud/types.js.map +1 -1
  181. package/dist/index.d.ts +1 -0
  182. package/dist/index.d.ts.map +1 -1
  183. package/dist/index.js +1 -0
  184. package/dist/index.js.map +1 -1
  185. package/dist/mcp/__tests__/bootstrap.test.js +24 -1
  186. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  187. package/dist/mcp/__tests__/state-paths.test.js +53 -0
  188. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  189. package/dist/mcp/bootstrap.d.ts +2 -0
  190. package/dist/mcp/bootstrap.d.ts.map +1 -1
  191. package/dist/mcp/bootstrap.js +32 -6
  192. package/dist/mcp/bootstrap.js.map +1 -1
  193. package/dist/mcp/state-paths.d.ts.map +1 -1
  194. package/dist/mcp/state-paths.js +11 -5
  195. package/dist/mcp/state-paths.js.map +1 -1
  196. package/dist/modes/__tests__/base-autopilot-gates.test.js +48 -0
  197. package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -1
  198. package/dist/modes/base.d.ts.map +1 -1
  199. package/dist/modes/base.js +1 -0
  200. package/dist/modes/base.js.map +1 -1
  201. package/dist/notifications/__tests__/http-client.test.js +9 -0
  202. package/dist/notifications/__tests__/http-client.test.js.map +1 -1
  203. package/dist/notifications/http-client.js +1 -1
  204. package/dist/notifications/http-client.js.map +1 -1
  205. package/dist/performance-goal/artifacts.d.ts.map +1 -1
  206. package/dist/performance-goal/artifacts.js +10 -1
  207. package/dist/performance-goal/artifacts.js.map +1 -1
  208. package/dist/ralplan/__tests__/consensus-gate.test.js +112 -0
  209. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
  210. package/dist/ralplan/consensus-gate.d.ts +23 -0
  211. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  212. package/dist/ralplan/consensus-gate.js +133 -21
  213. package/dist/ralplan/consensus-gate.js.map +1 -1
  214. package/dist/scripts/__tests__/codex-native-hook.test.js +1251 -13
  215. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  216. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  217. package/dist/scripts/codex-native-hook.js +601 -24
  218. package/dist/scripts/codex-native-hook.js.map +1 -1
  219. package/dist/scripts/notify-hook/team-leader-nudge.d.ts +1 -0
  220. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  221. package/dist/scripts/notify-hook/team-leader-nudge.js +279 -86
  222. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  223. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  224. package/dist/scripts/notify-hook/team-tmux-guard.js +87 -8
  225. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  226. package/dist/scripts/notify-hook/tmux-injection.js +1 -1
  227. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  228. package/dist/scripts/run-compiled-ci.d.ts +2 -0
  229. package/dist/scripts/run-compiled-ci.d.ts.map +1 -0
  230. package/dist/scripts/run-compiled-ci.js +77 -0
  231. package/dist/scripts/run-compiled-ci.js.map +1 -0
  232. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  233. package/dist/scripts/sync-plugin-mirror.js +1 -0
  234. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  235. package/dist/session-history/search.d.ts.map +1 -1
  236. package/dist/session-history/search.js +24 -9
  237. package/dist/session-history/search.js.map +1 -1
  238. package/dist/sidecar/__tests__/args.test.d.ts +2 -0
  239. package/dist/sidecar/__tests__/args.test.d.ts.map +1 -0
  240. package/dist/sidecar/__tests__/args.test.js +18 -0
  241. package/dist/sidecar/__tests__/args.test.js.map +1 -0
  242. package/dist/sidecar/index.d.ts.map +1 -1
  243. package/dist/sidecar/index.js +12 -4
  244. package/dist/sidecar/index.js.map +1 -1
  245. package/dist/state/__tests__/operations.test.js +107 -3
  246. package/dist/state/__tests__/operations.test.js.map +1 -1
  247. package/dist/state/operations.d.ts.map +1 -1
  248. package/dist/state/operations.js +57 -2
  249. package/dist/state/operations.js.map +1 -1
  250. package/dist/team/__tests__/delivery-e2e-smoke.test.js +22 -1
  251. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
  252. package/dist/team/__tests__/model-contract.test.js +57 -1
  253. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  254. package/dist/team/__tests__/runtime.test.js +1468 -110
  255. package/dist/team/__tests__/runtime.test.js.map +1 -1
  256. package/dist/team/__tests__/scaling.test.js +63 -0
  257. package/dist/team/__tests__/scaling.test.js.map +1 -1
  258. package/dist/team/__tests__/state.test.js +24 -1
  259. package/dist/team/__tests__/state.test.js.map +1 -1
  260. package/dist/team/__tests__/tmux-session.test.js +512 -0
  261. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  262. package/dist/team/__tests__/worker-bootstrap.test.js +42 -9
  263. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  264. package/dist/team/model-contract.d.ts +16 -0
  265. package/dist/team/model-contract.d.ts.map +1 -1
  266. package/dist/team/model-contract.js +41 -1
  267. package/dist/team/model-contract.js.map +1 -1
  268. package/dist/team/runtime.d.ts.map +1 -1
  269. package/dist/team/runtime.js +116 -30
  270. package/dist/team/runtime.js.map +1 -1
  271. package/dist/team/scaling.d.ts.map +1 -1
  272. package/dist/team/scaling.js +9 -1
  273. package/dist/team/scaling.js.map +1 -1
  274. package/dist/team/state/types.d.ts +2 -0
  275. package/dist/team/state/types.d.ts.map +1 -1
  276. package/dist/team/state/types.js.map +1 -1
  277. package/dist/team/state.d.ts +3 -0
  278. package/dist/team/state.d.ts.map +1 -1
  279. package/dist/team/state.js +20 -0
  280. package/dist/team/state.js.map +1 -1
  281. package/dist/team/tmux-session.d.ts +38 -3
  282. package/dist/team/tmux-session.d.ts.map +1 -1
  283. package/dist/team/tmux-session.js +275 -36
  284. package/dist/team/tmux-session.js.map +1 -1
  285. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  286. package/dist/team/worker-bootstrap.js +26 -1
  287. package/dist/team/worker-bootstrap.js.map +1 -1
  288. package/dist/ultragoal/__tests__/artifacts.test.js +388 -0
  289. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  290. package/dist/ultragoal/__tests__/docs-contract.test.js +3 -0
  291. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  292. package/dist/ultragoal/artifacts.d.ts +23 -0
  293. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  294. package/dist/ultragoal/artifacts.js +275 -12
  295. package/dist/ultragoal/artifacts.js.map +1 -1
  296. package/dist/url-reader/__tests__/url-reader.test.d.ts +2 -0
  297. package/dist/url-reader/__tests__/url-reader.test.d.ts.map +1 -0
  298. package/dist/url-reader/__tests__/url-reader.test.js +433 -0
  299. package/dist/url-reader/__tests__/url-reader.test.js.map +1 -0
  300. package/dist/url-reader/index.d.ts +4 -0
  301. package/dist/url-reader/index.d.ts.map +1 -0
  302. package/dist/url-reader/index.js +522 -0
  303. package/dist/url-reader/index.js.map +1 -0
  304. package/dist/url-reader/types.d.ts +41 -0
  305. package/dist/url-reader/types.d.ts.map +1 -0
  306. package/dist/url-reader/types.js +2 -0
  307. package/dist/url-reader/types.js.map +1 -0
  308. package/dist/utils/__tests__/agents-md.test.js +39 -1
  309. package/dist/utils/__tests__/agents-md.test.js.map +1 -1
  310. package/dist/utils/__tests__/agents-model-table.test.js +28 -0
  311. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
  312. package/dist/utils/agents-md.d.ts +4 -0
  313. package/dist/utils/agents-md.d.ts.map +1 -1
  314. package/dist/utils/agents-md.js +28 -0
  315. package/dist/utils/agents-md.js.map +1 -1
  316. package/dist/utils/agents-model-table.d.ts +7 -3
  317. package/dist/utils/agents-model-table.d.ts.map +1 -1
  318. package/dist/utils/agents-model-table.js +16 -8
  319. package/dist/utils/agents-model-table.js.map +1 -1
  320. package/dist/utils/platform-command.d.ts +7 -1
  321. package/dist/utils/platform-command.d.ts.map +1 -1
  322. package/dist/utils/platform-command.js +12 -1
  323. package/dist/utils/platform-command.js.map +1 -1
  324. package/dist/verification/__tests__/ci-rust-gates.test.js +4 -0
  325. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  326. package/dist/vscode/__tests__/index.test.d.ts +2 -0
  327. package/dist/vscode/__tests__/index.test.d.ts.map +1 -0
  328. package/dist/vscode/__tests__/index.test.js +236 -0
  329. package/dist/vscode/__tests__/index.test.js.map +1 -0
  330. package/dist/vscode/index.d.ts +76 -0
  331. package/dist/vscode/index.d.ts.map +1 -0
  332. package/dist/vscode/index.js +196 -0
  333. package/dist/vscode/index.js.map +1 -0
  334. package/package.json +3 -3
  335. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  336. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +59 -8
  337. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +9 -5
  338. package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +3 -0
  339. package/plugins/oh-my-codex/skills/performance-goal/SKILL.md +3 -0
  340. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
  341. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +22 -4
  342. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +2 -2
  343. package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +61 -0
  344. package/skills/autopilot/SKILL.md +9 -5
  345. package/skills/autoresearch-goal/SKILL.md +3 -0
  346. package/skills/ecomode/SKILL.md +1 -1
  347. package/skills/ecomode/references/agent-tiers.md +61 -0
  348. package/skills/performance-goal/SKILL.md +3 -0
  349. package/skills/ralplan/SKILL.md +1 -1
  350. package/skills/ultragoal/SKILL.md +22 -4
  351. package/skills/ultrawork/SKILL.md +2 -2
  352. package/skills/ultrawork/references/agent-tiers.md +61 -0
  353. package/src/scripts/__tests__/codex-native-hook.test.ts +1560 -181
  354. package/src/scripts/codex-native-hook.ts +663 -24
  355. package/src/scripts/notify-hook/team-leader-nudge.ts +298 -91
  356. package/src/scripts/notify-hook/team-tmux-guard.ts +92 -8
  357. package/src/scripts/notify-hook/tmux-injection.ts +1 -1
  358. package/src/scripts/run-compiled-ci.ts +85 -0
  359. package/src/scripts/sync-plugin-mirror.ts +1 -0
  360. package/templates/AGENTS.md +6 -0
@@ -1,6 +1,6 @@
1
1
  import { spawnSync, execFile } from 'child_process';
2
2
  import { promisify } from 'util';
3
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
3
+ import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'fs';
4
4
  import { homedir } from 'os';
5
5
  import { dirname, isAbsolute, join, resolve } from 'path';
6
6
  import { CODEX_BYPASS_FLAG, CLAUDE_SKIP_PERMISSIONS_FLAG, MADMAX_FLAG, CONFIG_FLAG, LONG_CONFIG_FLAG, MODEL_FLAG, } from '../cli/constants.js';
@@ -14,9 +14,10 @@ import { resolveOmxCliEntryPath } from '../utils/paths.js';
14
14
  const execFileAsync = promisify(execFile);
15
15
  import { HUD_RESIZE_RECONCILE_DELAY_SECONDS, HUD_TMUX_TEAM_HEIGHT_LINES } from '../hud/constants.js';
16
16
  import { OMX_TMUX_HUD_OWNER_ENV } from '../hud/reconcile.js';
17
- import { findHudWatchPaneIds, OMX_TMUX_HUD_LEADER_PANE_ENV } from '../hud/tmux.js';
17
+ import { findHudWatchPaneIds, hudPaneMatchesOwner, OMX_TMUX_HUD_LEADER_PANE_ENV } from '../hud/tmux.js';
18
18
  const OMX_INSTANCE_OPTION = '@omx_instance_id';
19
19
  const OMX_PANE_INSTANCE_OPTION = '@omx_pane_instance_id';
20
+ const OMX_TEAM_PANE_OWNER_OPTION = '@omx_team_pane_owner_id';
20
21
  const INJECTION_MARKER = '[OMX_TMUX_INJECT]';
21
22
  const MODEL_INSTRUCTIONS_FILE_KEY = 'model_instructions_file';
22
23
  const OMX_BYPASS_DEFAULT_SYSTEM_PROMPT_ENV = 'OMX_BYPASS_DEFAULT_SYSTEM_PROMPT';
@@ -108,6 +109,16 @@ function tagPaneInstance(paneTarget, instanceId) {
108
109
  throw new Error(`failed to tag tmux pane ${target}: ${result.stderr}`);
109
110
  }
110
111
  }
112
+ export function tagPaneTeamOwner(paneTarget, teamOwnerId) {
113
+ const target = paneTarget.trim();
114
+ const sanitized = teamOwnerId.trim();
115
+ if (!target || !sanitized)
116
+ return;
117
+ const result = runTmux(['set-option', '-p', '-t', target, OMX_TEAM_PANE_OWNER_OPTION, sanitized]);
118
+ if (!result.ok) {
119
+ throw new Error(`failed to tag tmux pane ${target}: ${result.stderr}`);
120
+ }
121
+ }
111
122
  export function mitigateCopyModeUnderlineArtifacts(sessionTarget) {
112
123
  const normalizedTarget = sessionTarget.trim();
113
124
  if (normalizedTarget === '')
@@ -227,15 +238,57 @@ export function chooseTeamLeaderPaneId(panes, preferredPaneId) {
227
238
  return preferredPaneId;
228
239
  }
229
240
  function findHudPaneIds(target, leaderPaneId) {
230
- const panes = listPanes(target);
231
- return panes
232
- .filter((pane) => pane.paneId !== leaderPaneId)
233
- .filter((pane) => isHudWatchPane(pane))
234
- .map((pane) => pane.paneId);
241
+ return findHudWatchPaneIds(listPanes(target), leaderPaneId, { leaderPaneId });
235
242
  }
236
243
  function findOwnedHudPaneIds(target, leaderPaneId) {
237
244
  return findHudWatchPaneIds(listPanes(target), leaderPaneId, { leaderPaneId });
238
245
  }
246
+ function readPaneCurrentPath(paneId) {
247
+ if (!paneId.startsWith('%'))
248
+ return null;
249
+ const result = runTmux(['display-message', '-p', '-t', paneId, '#{pane_current_path}']);
250
+ if (!result.ok)
251
+ return null;
252
+ const path = result.stdout.split('\n')[0]?.trim() ?? '';
253
+ return path === '' ? null : path;
254
+ }
255
+ function pathIsUsableDirectory(path) {
256
+ try {
257
+ return statSync(path).isDirectory();
258
+ }
259
+ catch {
260
+ return false;
261
+ }
262
+ }
263
+ function isMsysDriveSlashPath(path) {
264
+ return /^\/[A-Za-z](?:\/|$)/.test(path);
265
+ }
266
+ function uniqueRestoreCwdCandidates(candidates) {
267
+ const seen = new Set();
268
+ const result = [];
269
+ for (const candidate of candidates) {
270
+ const normalized = typeof candidate.rawPath === 'string' ? candidate.rawPath.trim() : '';
271
+ if (!normalized || seen.has(normalized))
272
+ continue;
273
+ seen.add(normalized);
274
+ result.push({ source: candidate.source, rawPath: normalized });
275
+ }
276
+ return result;
277
+ }
278
+ function shouldAttemptRestoreCwdCandidate(candidate) {
279
+ if (candidate.source === 'live' && isMsysOrGitBash() && isMsysDriveSlashPath(candidate.rawPath)) {
280
+ return true;
281
+ }
282
+ return pathIsUsableDirectory(candidate.rawPath);
283
+ }
284
+ function resolveStandaloneHudRestoreCwdCandidates(leaderPaneId, fallbackCwd, explicitCwd) {
285
+ const liveLeaderCwd = readPaneCurrentPath(leaderPaneId);
286
+ return uniqueRestoreCwdCandidates([
287
+ { source: 'explicit', rawPath: explicitCwd },
288
+ { source: 'live', rawPath: liveLeaderCwd },
289
+ { source: 'fallback', rawPath: fallbackCwd },
290
+ ]).filter(shouldAttemptRestoreCwdCandidate);
291
+ }
239
292
  const MAX_FRACTIONAL_SLEEP_MS = 60_000;
240
293
  function toFractionalSleepMs(seconds) {
241
294
  if (!Number.isFinite(seconds) || seconds <= 0)
@@ -1045,7 +1098,7 @@ export function isTmuxAvailable() {
1045
1098
  // Create tmux session with N worker windows
1046
1099
  // Split the current tmux leader window into worker panes.
1047
1100
  // Returns TeamSession or throws if tmux not available
1048
- export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs = [], workerStartups = []) {
1101
+ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs = [], workerStartups = [], options = {}) {
1049
1102
  if (!isTmuxAvailable()) {
1050
1103
  throw new Error('tmux is not available');
1051
1104
  }
@@ -1083,16 +1136,18 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
1083
1136
  throw new Error(`failed to parse current tmux target: ${context.stdout}`);
1084
1137
  }
1085
1138
  const teamTarget = `${sessionName}:${windowIndex}`;
1086
- const instanceId = (process.env.OMX_SESSION_ID || '').trim();
1087
- if (instanceId) {
1088
- const tagResult = runTmux(['set-option', '-t', sessionName, OMX_INSTANCE_OPTION, instanceId]);
1139
+ const ownerSessionId = (options.ownerSessionId ?? process.env.OMX_SESSION_ID ?? '').trim();
1140
+ const teamPaneOwnerId = (options.teamPaneOwnerId ?? `team:${safeTeamName}`).trim();
1141
+ if (ownerSessionId) {
1142
+ const tagResult = runTmux(['set-option', '-t', sessionName, OMX_INSTANCE_OPTION, ownerSessionId]);
1089
1143
  if (!tagResult.ok) {
1090
1144
  throw new Error(`failed to tag tmux session ${sessionName}: ${tagResult.stderr}`);
1091
1145
  }
1092
1146
  }
1093
1147
  const panes = listPanes(teamTarget);
1094
1148
  const leaderPaneId = chooseTeamLeaderPaneId(panes, detectedLeaderPaneId);
1095
- tagPaneInstance(leaderPaneId, instanceId);
1149
+ tagPaneInstance(leaderPaneId, ownerSessionId);
1150
+ tagPaneTeamOwner(leaderPaneId, teamPaneOwnerId);
1096
1151
  const initialHudPaneIds = findHudPaneIds(teamTarget, leaderPaneId);
1097
1152
  const omxEntry = resolveOmxCliEntryPath();
1098
1153
  const canRecreateTeamHud = Boolean(omxEntry && omxEntry.trim() !== '');
@@ -1141,7 +1196,8 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
1141
1196
  if (isNativeWindows() && !waitForPaneToRemainPresent(teamTarget, paneId)) {
1142
1197
  throw new Error(`worker pane ${i} did not remain present after tmux split-window returned ${paneId}`);
1143
1198
  }
1144
- tagPaneInstance(paneId, instanceId);
1199
+ tagPaneInstance(paneId, ownerSessionId);
1200
+ tagPaneTeamOwner(paneId, teamPaneOwnerId);
1145
1201
  workerPaneIds.push(paneId);
1146
1202
  if (i === 1)
1147
1203
  rightStackRootPaneId = paneId;
@@ -1166,7 +1222,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
1166
1222
  let resizeHookName = null;
1167
1223
  let resizeHookTarget = null;
1168
1224
  if (canRecreateTeamHud && omxEntry) {
1169
- const hudCmd = `exec env ${formatHudEnvAssignments(process.env, { sessionId: instanceId, leaderPaneId })} node ${shellQuoteSingle(translatePathForMsys(omxEntry))} hud --watch`;
1225
+ const hudCmd = `exec env ${formatHudEnvAssignments(process.env, { sessionId: ownerSessionId, leaderPaneId })} node ${shellQuoteSingle(translatePathForMsys(omxEntry))} hud --watch`;
1170
1226
  const hudCwd = translatePathForMsys(cwd);
1171
1227
  const hudResult = runTmux([
1172
1228
  'split-window', '-v', '-f', '-l', String(HUD_TMUX_TEAM_HEIGHT_LINES), '-t', teamTarget, '-d', '-P', '-F', '#{pane_id}', '-c', hudCwd, hudCmd,
@@ -1178,7 +1234,8 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
1178
1234
  if (isNativeWindows() && !waitForPaneToRemainPresent(teamTarget, id)) {
1179
1235
  throw new Error(`HUD pane did not remain present after tmux split-window returned ${id}`);
1180
1236
  }
1181
- tagPaneInstance(id, instanceId);
1237
+ tagPaneInstance(id, ownerSessionId);
1238
+ tagPaneTeamOwner(id, teamPaneOwnerId);
1182
1239
  hudPaneId = id;
1183
1240
  if (isNativeWindows()) {
1184
1241
  // Native Windows tmux support may flow through psmux; issuing a
@@ -1247,6 +1304,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
1247
1304
  hudPaneId,
1248
1305
  resizeHookName,
1249
1306
  resizeHookTarget,
1307
+ teamPaneOwnerId,
1250
1308
  };
1251
1309
  }
1252
1310
  catch (error) {
@@ -1262,7 +1320,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
1262
1320
  throw error;
1263
1321
  }
1264
1322
  }
1265
- export function restoreStandaloneHudPane(leaderPaneId, cwd) {
1323
+ export function restoreStandaloneHudPane(leaderPaneId, cwd, options = {}) {
1266
1324
  const normalizedLeaderPaneId = normalizePaneTarget(leaderPaneId);
1267
1325
  if (!normalizedLeaderPaneId)
1268
1326
  return null;
@@ -1284,24 +1342,30 @@ export function restoreStandaloneHudPane(leaderPaneId, cwd) {
1284
1342
  runTmux(['select-pane', '-t', normalizedLeaderPaneId]);
1285
1343
  return existingHudPaneId;
1286
1344
  }
1287
- const hudCmd = `exec env ${formatHudEnvAssignments(process.env, { leaderPaneId: normalizedLeaderPaneId })} ${shellQuoteSingle(translatePathForMsys(resolveLeaderNodePath()))} ${shellQuoteSingle(translatePathForMsys(omxEntry))} hud --watch`;
1288
- const hudCwd = translatePathForMsys(cwd);
1289
- const hudResult = runTmux([
1290
- 'split-window',
1291
- '-v',
1292
- '-l',
1293
- String(HUD_TMUX_TEAM_HEIGHT_LINES),
1294
- '-t',
1295
- normalizedLeaderPaneId,
1296
- '-d',
1297
- '-P',
1298
- '-F',
1299
- '#{pane_id}',
1300
- '-c',
1301
- hudCwd,
1302
- hudCmd,
1303
- ]);
1304
- if (!hudResult.ok)
1345
+ const hudCmd = `exec env ${formatHudEnvAssignments(process.env, { sessionId: options.sessionId, leaderPaneId: normalizedLeaderPaneId })} ${shellQuoteSingle(translatePathForMsys(resolveLeaderNodePath()))} ${shellQuoteSingle(translatePathForMsys(omxEntry))} hud --watch`;
1346
+ let hudResult = null;
1347
+ for (const restoreCwd of resolveStandaloneHudRestoreCwdCandidates(normalizedLeaderPaneId, cwd, options.cwd)) {
1348
+ const candidateResult = runTmux([
1349
+ 'split-window',
1350
+ '-v',
1351
+ '-l',
1352
+ String(HUD_TMUX_TEAM_HEIGHT_LINES),
1353
+ '-t',
1354
+ normalizedLeaderPaneId,
1355
+ '-d',
1356
+ '-P',
1357
+ '-F',
1358
+ '#{pane_id}',
1359
+ '-c',
1360
+ translatePathForMsys(restoreCwd.rawPath),
1361
+ hudCmd,
1362
+ ]);
1363
+ if (candidateResult.ok) {
1364
+ hudResult = candidateResult;
1365
+ break;
1366
+ }
1367
+ }
1368
+ if (!hudResult?.ok)
1305
1369
  return null;
1306
1370
  const paneId = hudResult.stdout.split('\n')[0]?.trim() ?? '';
1307
1371
  if (!paneId.startsWith('%'))
@@ -1929,6 +1993,55 @@ export function killWorkerByPaneId(workerPaneId, leaderPaneId) {
1929
1993
  return;
1930
1994
  runTmux(['kill-pane', '-t', workerPaneId]);
1931
1995
  }
1996
+ export function paneHasOmxInstanceTag(paneId, instanceId) {
1997
+ const normalizedPaneId = normalizePaneTarget(paneId);
1998
+ const expectedInstanceId = typeof instanceId === 'string' ? instanceId.trim() : '';
1999
+ if (!normalizedPaneId || !expectedInstanceId)
2000
+ return false;
2001
+ const result = runTmux(['show-option', '-qv', '-p', '-t', normalizedPaneId, OMX_PANE_INSTANCE_OPTION]);
2002
+ if (!result.ok)
2003
+ return false;
2004
+ return result.stdout.trim() === expectedInstanceId;
2005
+ }
2006
+ export function paneHasOmxTeamOwnerTag(paneId, teamOwnerId) {
2007
+ const expectedTeamOwnerId = typeof teamOwnerId === 'string' ? teamOwnerId.trim() : '';
2008
+ if (!expectedTeamOwnerId)
2009
+ return false;
2010
+ const result = readPaneTeamOwnerTagResult(paneId);
2011
+ return result.status === 'value' && result.value === expectedTeamOwnerId;
2012
+ }
2013
+ export function readPaneTeamOwnerTag(paneId) {
2014
+ const result = readPaneTeamOwnerTagResult(paneId);
2015
+ return result.status === 'value' ? result.value : null;
2016
+ }
2017
+ export function readPaneTeamOwnerTagResult(paneId) {
2018
+ const normalizedPaneId = normalizePaneTarget(paneId);
2019
+ if (!normalizedPaneId)
2020
+ return { status: 'error', error: 'invalid pane target' };
2021
+ const { result } = spawnPlatformCommandSync('tmux', [
2022
+ 'show-option',
2023
+ '-qv',
2024
+ '-p',
2025
+ '-t',
2026
+ normalizedPaneId,
2027
+ OMX_TEAM_PANE_OWNER_OPTION,
2028
+ ], { encoding: 'utf-8' });
2029
+ if (result.error) {
2030
+ return { status: 'error', error: result.error.message };
2031
+ }
2032
+ const stdout = typeof result.stdout === 'string' ? result.stdout.trim() : '';
2033
+ if (result.status === 0) {
2034
+ return stdout === '' ? { status: 'missing' } : { status: 'value', value: stdout };
2035
+ }
2036
+ const stderr = typeof result.stderr === 'string' ? result.stderr.trim() : '';
2037
+ // tmux reports an unset user option as status 1 with no diagnostic on
2038
+ // supported versions. Treat other failures, including signal/null exits,
2039
+ // as real read errors so shared-pane shutdown fails closed instead of
2040
+ // killing a pane whose owner could not be read.
2041
+ if (result.status === 1 && stderr === '')
2042
+ return { status: 'missing' };
2043
+ return { status: 'error', error: stderr || `tmux show-option exited ${result.status ?? 'unknown'}` };
2044
+ }
1932
2045
  export async function killWorkerByPaneIdAsync(workerPaneId, leaderPaneId) {
1933
2046
  if (!workerPaneId.startsWith('%'))
1934
2047
  return;
@@ -1972,7 +2085,7 @@ function normalizePaneTargets(paneIds, options = {}) {
1972
2085
  }
1973
2086
  return { killablePaneIds, excluded };
1974
2087
  }
1975
- export function resolveSharedSessionShutdownTopology(sessionName, preferredLeaderPaneId) {
2088
+ export function resolveSharedSessionShutdownTopology(sessionName, preferredLeaderPaneId, teamName) {
1976
2089
  const panes = listPanes(sessionName);
1977
2090
  const livePaneIds = panes
1978
2091
  .map((pane) => normalizePaneTarget(pane.paneId))
@@ -1981,22 +2094,148 @@ export function resolveSharedSessionShutdownTopology(sessionName, preferredLeade
1981
2094
  if (panes.length === 0) {
1982
2095
  return {
1983
2096
  livePaneIds,
2097
+ teamWorkerPaneIds: [],
1984
2098
  leaderPaneId: fallbackLeaderPaneId,
1985
2099
  hudPaneIds: [],
2100
+ leaderOwnedHudPaneIds: [],
1986
2101
  };
1987
2102
  }
1988
- const resolvedLeaderPaneId = normalizePaneTarget(chooseTeamLeaderPaneId(panes, fallbackLeaderPaneId ?? '')) ?? fallbackLeaderPaneId;
2103
+ const normalizedTeamName = typeof teamName === 'string' ? teamName.trim() : '';
2104
+ const normalizedTeamWorkerPaneIds = normalizedTeamName
2105
+ ? panes
2106
+ .filter((pane) => !isHudWatchPane(pane))
2107
+ .filter((pane) => paneLooksLikeTeamWorkerPane(pane, normalizedTeamName))
2108
+ .map((pane) => pane.paneId)
2109
+ .filter((paneId) => paneId.startsWith('%'))
2110
+ : [];
2111
+ const workerPaneIdSet = new Set(normalizedTeamWorkerPaneIds);
2112
+ const resolvedLeaderPaneId = chooseSharedSessionShutdownLeaderPaneId(panes, fallbackLeaderPaneId, workerPaneIdSet);
1989
2113
  const hudPaneIds = panes
1990
2114
  .filter((pane) => pane.paneId !== resolvedLeaderPaneId)
1991
2115
  .filter((pane) => isHudWatchPane(pane))
1992
2116
  .map((pane) => pane.paneId)
1993
2117
  .filter((paneId) => paneId.startsWith('%'));
2118
+ const leaderOwnedHudPaneIds = resolvedLeaderPaneId
2119
+ ? panes
2120
+ .filter((pane) => pane.paneId !== resolvedLeaderPaneId)
2121
+ .filter((pane) => hudPaneMatchesOwner(pane, { leaderPaneId: resolvedLeaderPaneId }))
2122
+ .map((pane) => pane.paneId)
2123
+ .filter((paneId) => paneId.startsWith('%'))
2124
+ : [];
1994
2125
  return {
1995
2126
  livePaneIds,
2127
+ teamWorkerPaneIds: normalizedTeamWorkerPaneIds,
1996
2128
  leaderPaneId: resolvedLeaderPaneId,
1997
2129
  hudPaneIds,
2130
+ leaderOwnedHudPaneIds,
1998
2131
  };
1999
2132
  }
2133
+ function chooseSharedSessionShutdownLeaderPaneId(panes, preferredLeaderPaneId, teamWorkerPaneIds) {
2134
+ const preferred = panes.find((pane) => pane.paneId === preferredLeaderPaneId);
2135
+ if (preferred && !isHudWatchPane(preferred) && !teamWorkerPaneIds.has(preferred.paneId)) {
2136
+ return preferred.paneId;
2137
+ }
2138
+ return null;
2139
+ }
2140
+ function paneLooksLikeTeamWorkerPane(pane, teamName) {
2141
+ const command = `${pane.startCommand || ''} ${pane.currentCommand || ''}`.replace(/\\/g, '/');
2142
+ if (!command.trim() || !teamName)
2143
+ return false;
2144
+ if (command.includes(`/team/${teamName}/runtime/worker-`) && command.includes('-startup.sh')) {
2145
+ return true;
2146
+ }
2147
+ const commandVariants = [command, ...decodePowerShellEncodedCommands(command)];
2148
+ return commandVariants.some((candidate) => (commandHasTeamWorkerEnvMarker(candidate, 'OMX_TEAM_INTERNAL_WORKER', teamName)
2149
+ || commandHasTeamWorkerEnvMarker(candidate, 'OMX_TEAM_WORKER', teamName)));
2150
+ }
2151
+ function commandHasTeamWorkerEnvMarker(command, envName, teamName) {
2152
+ const normalized = command.replace(/\\/g, '/');
2153
+ const key = escapeRegExp(envName);
2154
+ const workerValue = `${escapeRegExp(teamName)}/worker-[A-Za-z0-9_-]+`;
2155
+ const shellAssignment = new RegExp(`(?:^|[\\s;])(?:export\\s+)?(?:["']${key}=${workerValue}|${key}=(?:["']?${workerValue}))`, 'g');
2156
+ const powerShellAssignment = new RegExp(`(?:^|;)\\s*\\$env:${key}\\s*=\\s*["']?${workerValue}`, 'gi');
2157
+ return hasWorkerCliAfterEnvAssignment(normalized, shellAssignment, hasSafeShellEnvAssignmentContext, shellTailInvokesWorkerCli)
2158
+ || hasWorkerCliAfterEnvAssignment(normalized, powerShellAssignment, () => true, powerShellTailInvokesWorkerCli);
2159
+ }
2160
+ function hasWorkerCliAfterEnvAssignment(command, assignmentPattern, contextIsSafe = () => true, tailInvokesWorkerCli = shellTailInvokesWorkerCli) {
2161
+ assignmentPattern.lastIndex = 0;
2162
+ for (const match of command.matchAll(assignmentPattern)) {
2163
+ const matchIndex = match.index ?? 0;
2164
+ if (!contextIsSafe(command, matchIndex))
2165
+ continue;
2166
+ const afterAssignment = command.slice(matchIndex + match[0].length);
2167
+ if (tailInvokesWorkerCli(afterAssignment)) {
2168
+ return true;
2169
+ }
2170
+ }
2171
+ return false;
2172
+ }
2173
+ const WORKER_CLI_TOKEN_PATTERN = String.raw `(?:"[^"]*(?:^|[\/\\])?(?:codex|claude|gemini)(?:\.(?:js|mjs|cjs|cmd|exe|bat|ps1))?"|'[^']*(?:^|[\/\\])?(?:codex|claude|gemini)(?:\.(?:js|mjs|cjs|cmd|exe|bat|ps1))?'|(?:\S*[\/\\])?(?:codex|claude|gemini)(?:\.(?:js|mjs|cjs|cmd|exe|bat|ps1))?)`;
2174
+ function shellTailInvokesWorkerCli(tail) {
2175
+ const directTail = stripShellAssignmentTailPrefix(tail);
2176
+ const directCliPattern = new RegExp(`^(?:exec\\s+)?${WORKER_CLI_TOKEN_PATTERN}(?:[\\s;"'\`]|$)`, 'i');
2177
+ if (directCliPattern.test(directTail))
2178
+ return true;
2179
+ const shellCommandPattern = /(?:^|\s)-(?:c|lc)\s+(?:"([^"]*)"|'([^']*)'|(\S+))/gi;
2180
+ for (const match of directTail.matchAll(shellCommandPattern)) {
2181
+ const commandText = match[1] ?? match[2] ?? match[3] ?? '';
2182
+ const execCliPattern = new RegExp(`(?:^|[\\s;&|])exec\\s+${WORKER_CLI_TOKEN_PATTERN}(?:[\\s;"'\`]|$)`, 'i');
2183
+ if (execCliPattern.test(commandText))
2184
+ return true;
2185
+ }
2186
+ return false;
2187
+ }
2188
+ function stripShellAssignmentTailPrefix(tail) {
2189
+ let value = tail.trimStart();
2190
+ while (value.startsWith("'") || value.startsWith('"')) {
2191
+ value = value.slice(1).trimStart();
2192
+ }
2193
+ const envAssignmentPattern = /^[A-Za-z_][A-Za-z0-9_]*=(?:'[^']*'|"[^"]*"|\S+)\s+/;
2194
+ let changed = true;
2195
+ while (changed) {
2196
+ changed = false;
2197
+ const match = value.match(envAssignmentPattern);
2198
+ if (match) {
2199
+ value = value.slice(match[0].length).trimStart();
2200
+ changed = true;
2201
+ }
2202
+ }
2203
+ return value;
2204
+ }
2205
+ function powerShellTailInvokesWorkerCli(tail) {
2206
+ return /(?:^|[\s;&|"'`\/\\])(?:codex|claude|gemini)(?:\.(?:js|mjs|cjs|cmd|exe|bat|ps1))?(?:[\s;"'`]|$)/i.test(tail);
2207
+ }
2208
+ function hasSafeShellEnvAssignmentContext(command, matchIndex) {
2209
+ const prefix = command.slice(0, matchIndex).trimEnd();
2210
+ if (!prefix)
2211
+ return true;
2212
+ const segment = prefix.split(/&&|\|\||[;|]/).pop()?.trimEnd() ?? '';
2213
+ if (!segment)
2214
+ return true;
2215
+ return /(?:^|\s)(?:env|export)(?:\s+(?:'[^']*'|"[^"]*"|\S+))*$/.test(segment)
2216
+ || /(?:^|\s)worker[-_]wrapper(?:\s+(?:'[^']*'|"[^"]*"|\S+))*$/.test(segment);
2217
+ }
2218
+ function decodePowerShellEncodedCommands(command) {
2219
+ const decoded = [];
2220
+ const encodedCommandPattern = /(?:^|\s)-(?:EncodedCommand|enc|e)(?:\s+|:)([A-Za-z0-9+/=]+)/gi;
2221
+ for (const match of command.matchAll(encodedCommandPattern)) {
2222
+ const encoded = match[1];
2223
+ if (!encoded)
2224
+ continue;
2225
+ try {
2226
+ const text = Buffer.from(encoded, 'base64').toString('utf16le').trim();
2227
+ if (text)
2228
+ decoded.push(text.replace(/\\/g, '/'));
2229
+ }
2230
+ catch {
2231
+ // Ignore malformed pane command fragments; they are not team ownership evidence.
2232
+ }
2233
+ }
2234
+ return decoded;
2235
+ }
2236
+ function escapeRegExp(value) {
2237
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2238
+ }
2000
2239
  /**
2001
2240
  * Shared pane-id-direct teardown primitive for worker pane cleanup.
2002
2241
  * Must remain liveness-agnostic: do not gate on isWorkerAlive/killWorker.