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
@@ -3,7 +3,7 @@
3
3
  * Team leader nudge: remind the leader to check teammate/mailbox state.
4
4
  */
5
5
 
6
- import { readFile, writeFile, mkdir, appendFile, readdir } from 'fs/promises';
6
+ import { readFile, writeFile, mkdir, appendFile, readdir, rename, unlink } from 'fs/promises';
7
7
  import { existsSync } from 'fs';
8
8
  import { join, resolve } from 'path';
9
9
  import { readUsableSessionState } from '../../hooks/session.js';
@@ -21,13 +21,13 @@ import {
21
21
  import { DEFAULT_MARKER, paneHasActiveTask } from '../tmux-hook-engine.js';
22
22
  import { isLeaderRuntimeStale } from '../../team/leader-activity.js';
23
23
  import { appendTeamDeliveryLog } from '../../team/delivery-log.js';
24
- import { writeTeamLeaderAttention } from '../../team/state.js';
25
24
  import { readLatestTeamProgressEvidenceMs } from '../../team/progress-evidence.js';
26
25
  import { validateSessionId } from '../../mcp/state-paths.js';
27
26
  import { TEAM_NAME_SAFE_PATTERN } from '../../team/contracts.js';
28
27
  import { isDeepInterviewStateActive } from './auto-nudge.js';
29
28
  const LEADER_PANE_MISSING_NO_INJECTION_REASON = 'leader_pane_missing_no_injection';
30
29
  const LEADER_PANE_SHELL_NO_INJECTION_REASON = 'leader_pane_shell_no_injection';
30
+ const TEAM_SHUTDOWN_NO_INJECTION_REASON = 'team_state_gone_or_shutdown';
31
31
  const LEADER_PANE_SAME_CLASSIFIED_STATE_SUPPRESSED_REASON = 'pane_already_shows_same_classified_state';
32
32
  const LEADER_NOTIFICATION_DEFERRED_TYPE = 'leader_notification_deferred';
33
33
  const ACK_WITHOUT_START_EVIDENCE_REASON = 'ack_without_start_evidence';
@@ -37,6 +37,109 @@ const ACK_LIKE_PATTERNS = [
37
37
  /^(?:on it|will do|i(?:'|')ll do it|working on it)[.!]*$/i,
38
38
  ];
39
39
 
40
+ let atomicJsonWriteCounter = 0;
41
+
42
+ // Synchronous test-only callbacks let regression tests emulate filesystem races
43
+ // without shipping env-gated destructive fault injection in the notify hook.
44
+ const leaderNudgeTestHooks = {
45
+ beforeLeaderAttentionRename: null,
46
+ afterLeaderAttentionRename: null,
47
+ beforeGlobalNudgeStateRename: null,
48
+ afterGlobalNudgeStateRename: null,
49
+ };
50
+
51
+ export function setLeaderNudgeTestHooksForTests(hooks = {}) {
52
+ leaderNudgeTestHooks.beforeLeaderAttentionRename = typeof hooks.beforeLeaderAttentionRename === 'function'
53
+ ? hooks.beforeLeaderAttentionRename
54
+ : null;
55
+ leaderNudgeTestHooks.afterLeaderAttentionRename = typeof hooks.afterLeaderAttentionRename === 'function'
56
+ ? hooks.afterLeaderAttentionRename
57
+ : null;
58
+ leaderNudgeTestHooks.beforeGlobalNudgeStateRename = typeof hooks.beforeGlobalNudgeStateRename === 'function'
59
+ ? hooks.beforeGlobalNudgeStateRename
60
+ : null;
61
+ leaderNudgeTestHooks.afterGlobalNudgeStateRename = typeof hooks.afterGlobalNudgeStateRename === 'function'
62
+ ? hooks.afterGlobalNudgeStateRename
63
+ : null;
64
+ }
65
+
66
+ async function atomicWriteJsonNoParentCreate(path, value, { beforeRename = null, afterRename = null } = {}) {
67
+ const tempPath = `${path}.${process.pid}.${Date.now()}.${++atomicJsonWriteCounter}.tmp`;
68
+ try {
69
+ await writeFile(tempPath, JSON.stringify(value, null, 2));
70
+ if (beforeRename) await beforeRename(tempPath);
71
+ await rename(tempPath, path);
72
+ if (afterRename) await afterRename(path);
73
+ } catch (error) {
74
+ await unlink(tempPath).catch(() => {});
75
+ throw error;
76
+ }
77
+ }
78
+
79
+ function cloneLeaderNudgeState(state) {
80
+ return {
81
+ ...(state && typeof state === 'object' ? state : {}),
82
+ last_nudged_by_team: { ...(state?.last_nudged_by_team || {}) },
83
+ last_idle_nudged_by_team: { ...(state?.last_idle_nudged_by_team || {}) },
84
+ progress_by_team: { ...(state?.progress_by_team || {}) },
85
+ };
86
+ }
87
+
88
+ function removeTeamFromLeaderNudgeState(state, teamName) {
89
+ if (state?.progress_by_team && typeof state.progress_by_team === 'object') {
90
+ delete state.progress_by_team[teamName];
91
+ }
92
+ if (state?.last_nudged_by_team && typeof state.last_nudged_by_team === 'object') {
93
+ delete state.last_nudged_by_team[teamName];
94
+ }
95
+ if (state?.last_idle_nudged_by_team && typeof state.last_idle_nudged_by_team === 'object') {
96
+ delete state.last_idle_nudged_by_team[teamName];
97
+ }
98
+ }
99
+
100
+ async function teamStateAllowsLeaderNudge(stateDir, teamName) {
101
+ const teamDir = join(stateDir, 'team', teamName);
102
+ if (!existsSync(teamDir)) return false;
103
+ if (existsSync(join(teamDir, 'shutdown.json'))) return false;
104
+
105
+ const phase = await readJsonIfExists(join(teamDir, 'phase.json'), null);
106
+ const currentPhase = safeString(phase?.current_phase || phase?.phase || '').trim();
107
+ if (currentPhase && isTerminalPhase(currentPhase)) return false;
108
+
109
+ return true;
110
+ }
111
+
112
+ async function recordSuppressedLeaderNudge({
113
+ logsDir,
114
+ source,
115
+ teamName,
116
+ reason,
117
+ orchestrationIntent = null,
118
+ }) {
119
+ const nowIso = new Date().toISOString();
120
+ await logTmuxHookEvent(logsDir, {
121
+ timestamp: nowIso,
122
+ type: 'team_leader_nudge_suppressed',
123
+ team: teamName,
124
+ worker: 'leader-fixed',
125
+ to_worker: 'leader-fixed',
126
+ reason,
127
+ orchestration_intent: orchestrationIntent,
128
+ tmux_injection_attempted: false,
129
+ source_type: 'leader_nudge',
130
+ }).catch(() => {});
131
+ await appendTeamDeliveryLog(logsDir, {
132
+ event: 'nudge_triggered',
133
+ source,
134
+ team: teamName,
135
+ to_worker: 'leader-fixed',
136
+ transport: 'none',
137
+ result: 'suppressed',
138
+ reason,
139
+ orchestration_intent: orchestrationIntent,
140
+ }).catch(() => {});
141
+ }
142
+
40
143
  function normalizeValidSessionId(value) {
41
144
  const trimmed = safeString(value).trim();
42
145
  if (!trimmed) return '';
@@ -613,6 +716,15 @@ export async function maybeNudgeTeamLeader({
613
716
  const leaderStale = typeof preComputedLeaderStale === 'boolean' ? preComputedLeaderStale : false;
614
717
 
615
718
  for (const teamName of candidateTeamNames) {
719
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
720
+ await recordSuppressedLeaderNudge({
721
+ logsDir,
722
+ source,
723
+ teamName,
724
+ reason: TEAM_SHUTDOWN_NO_INJECTION_REASON,
725
+ });
726
+ continue;
727
+ }
616
728
  let tmuxSession = '';
617
729
  let leaderPaneId = '';
618
730
  let ownerSessionId = '';
@@ -773,60 +885,167 @@ export async function maybeNudgeTeamLeader({
773
885
  }
774
886
 
775
887
  const unreadLeaderMessageCount = messages.filter((message) => !safeString(message?.delivered_at).trim()).length;
776
- nudgeState.progress_by_team[teamName] = {
777
- signature: progressSnapshot.signature,
778
- last_progress_at: effectiveProgressAtIso,
779
- observed_at: nowIso,
780
- missing_signal_workers: progressSnapshot.missingSignalWorkers,
781
- work_remaining: progressSnapshot.workRemaining,
782
- leader_action_state: leaderActionState,
783
- leader_attention_pending: !!nudgeReason,
784
- leader_attention_reason: nudgeReason || null,
785
- leader_stale: leaderStale,
786
- all_workers_idle: allWorkersIdle,
787
- pending_task_count:
788
- (progressSnapshot.taskCounts.pending || 0)
789
- + (progressSnapshot.taskCounts.blocked || 0)
790
- + (progressSnapshot.taskCounts.in_progress || 0),
791
- unread_leader_message_count: unreadLeaderMessageCount,
792
- stalled_for_ms: null,
793
- source: source === 'notify_fallback_watcher' ? 'notify_hook' : source,
888
+ const recordShutdownSuppression = async (orchestrationIntent = null) => {
889
+ await recordSuppressedLeaderNudge({
890
+ logsDir,
891
+ source,
892
+ teamName,
893
+ reason: TEAM_SHUTDOWN_NO_INJECTION_REASON,
894
+ orchestrationIntent,
895
+ });
896
+ };
897
+ const cleanupTeamPersistence = async () => {
898
+ await unlink(join(stateDir, 'team', teamName, 'leader-attention.json')).catch(() => {});
899
+ const latestState = await readJsonIfExists(nudgeStatePath, nudgeState);
900
+ const cleanedState = cloneLeaderNudgeState(latestState);
901
+ removeTeamFromLeaderNudgeState(cleanedState, teamName);
902
+ nudgeState = cleanedState;
903
+ await atomicWriteJsonNoParentCreate(nudgeStatePath, cleanedState).catch(() => {});
794
904
  };
795
- await writeTeamLeaderAttention(teamName, {
796
- team_name: teamName,
797
- updated_at: nowIso,
798
- source: 'notify_hook',
799
- leader_decision_state: leaderActionState,
800
- leader_attention_pending: !!nudgeReason,
801
- leader_attention_reason: nudgeReason || null,
802
- attention_reasons: nudgeReason ? [nudgeReason] : [],
803
- leader_stale: leaderStale,
804
- leader_session_active: true,
805
- leader_session_id: currentSessionId || ownerSessionId || null,
806
- leader_session_stopped_at: null,
807
- unread_leader_message_count: unreadLeaderMessageCount,
808
- work_remaining: progressSnapshot.workRemaining,
809
- stalled_for_ms: null,
810
- }, cwd).catch(() => {});
811
-
812
- if (!nudgeReason) continue;
813
- const orchestrationIntent = resolveLeaderNudgeIntent({ nudgeReason, leaderActionState });
814
- const capped = text.length > 180 ? `${text.slice(0, 177)}...` : text;
815
- const markedText = `${capped} ${DEFAULT_MARKER}`;
816
905
 
817
- if (!tmuxTarget) {
818
- nudgeState.last_nudged_by_team[teamName] = {
819
- at: nowIso,
820
- last_message_id: newestId || prevMsgId || '',
821
- reason: nudgeReason,
822
- orchestration_intent: orchestrationIntent,
906
+ const persistLeaderNudgeBookkeeping = async ({ orchestrationIntent = null, recordLastNudged = false } = {}) => {
907
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
908
+ await recordShutdownSuppression(orchestrationIntent);
909
+ return false;
910
+ }
911
+
912
+ const leaderAttention = {
913
+ team_name: teamName,
914
+ updated_at: nowIso,
915
+ source: 'notify_hook',
916
+ leader_decision_state: leaderActionState,
917
+ leader_attention_pending: !!nudgeReason,
918
+ leader_attention_reason: nudgeReason || null,
919
+ attention_reasons: nudgeReason ? [nudgeReason] : [],
920
+ leader_stale: leaderStale,
921
+ leader_session_active: true,
922
+ leader_session_id: currentSessionId || ownerSessionId || null,
923
+ leader_session_stopped_at: null,
924
+ unread_leader_message_count: unreadLeaderMessageCount,
925
+ work_remaining: progressSnapshot.workRemaining,
926
+ stalled_for_ms: null,
927
+ };
928
+
929
+ const leaderAttentionPath = join(stateDir, 'team', teamName, 'leader-attention.json');
930
+ try {
931
+ await atomicWriteJsonNoParentCreate(leaderAttentionPath, leaderAttention, {
932
+ beforeRename: async (tempPath) => {
933
+ if (leaderNudgeTestHooks.beforeLeaderAttentionRename) {
934
+ await leaderNudgeTestHooks.beforeLeaderAttentionRename({ stateDir, teamName, tempPath });
935
+ }
936
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
937
+ throw new Error('team_state_gone_or_shutdown_before_leader_attention_rename');
938
+ }
939
+ },
940
+ afterRename: async () => {
941
+ if (leaderNudgeTestHooks.afterLeaderAttentionRename) {
942
+ await leaderNudgeTestHooks.afterLeaderAttentionRename({ stateDir, teamName, path: leaderAttentionPath });
943
+ }
944
+ },
945
+ });
946
+ } catch {
947
+ await unlink(leaderAttentionPath).catch(() => {});
948
+ await recordShutdownSuppression(orchestrationIntent);
949
+ return false;
950
+ }
951
+
952
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
953
+ await cleanupTeamPersistence();
954
+ await recordShutdownSuppression(orchestrationIntent);
955
+ return false;
956
+ }
957
+
958
+ const nextNudgeState = cloneLeaderNudgeState(nudgeState);
959
+ nextNudgeState.progress_by_team[teamName] = {
960
+ signature: progressSnapshot.signature,
961
+ last_progress_at: effectiveProgressAtIso,
962
+ observed_at: nowIso,
963
+ missing_signal_workers: progressSnapshot.missingSignalWorkers,
964
+ work_remaining: progressSnapshot.workRemaining,
965
+ leader_action_state: leaderActionState,
966
+ leader_attention_pending: !!nudgeReason,
967
+ leader_attention_reason: nudgeReason || null,
968
+ leader_stale: leaderStale,
969
+ all_workers_idle: allWorkersIdle,
970
+ pending_task_count:
971
+ (progressSnapshot.taskCounts.pending || 0)
972
+ + (progressSnapshot.taskCounts.blocked || 0)
973
+ + (progressSnapshot.taskCounts.in_progress || 0),
974
+ unread_leader_message_count: unreadLeaderMessageCount,
975
+ stalled_for_ms: null,
976
+ source: source === 'notify_fallback_watcher' ? 'notify_hook' : source,
823
977
  };
824
- if (shouldSendAllIdleNudge) {
825
- nudgeState.last_idle_nudged_by_team[teamName] = {
978
+ if (recordLastNudged) {
979
+ nextNudgeState.last_nudged_by_team[teamName] = {
826
980
  at: nowIso,
827
- worker_count: workerNames.length,
981
+ last_message_id: newestId || prevMsgId || '',
982
+ reason: nudgeReason,
828
983
  orchestration_intent: orchestrationIntent,
829
984
  };
985
+ if (shouldSendAllIdleNudge) {
986
+ nextNudgeState.last_idle_nudged_by_team[teamName] = {
987
+ at: nowIso,
988
+ worker_count: workerNames.length,
989
+ orchestration_intent: orchestrationIntent,
990
+ };
991
+ }
992
+ }
993
+
994
+ try {
995
+ await atomicWriteJsonNoParentCreate(nudgeStatePath, nextNudgeState, {
996
+ beforeRename: async (tempPath) => {
997
+ if (leaderNudgeTestHooks.beforeGlobalNudgeStateRename) {
998
+ await leaderNudgeTestHooks.beforeGlobalNudgeStateRename({ stateDir, teamName, tempPath });
999
+ }
1000
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
1001
+ throw new Error('team_state_gone_or_shutdown_before_nudge_state_rename');
1002
+ }
1003
+ },
1004
+ afterRename: async () => {
1005
+ if (leaderNudgeTestHooks.afterGlobalNudgeStateRename) {
1006
+ await leaderNudgeTestHooks.afterGlobalNudgeStateRename({ stateDir, teamName, path: nudgeStatePath });
1007
+ }
1008
+ },
1009
+ });
1010
+ } catch {
1011
+ await cleanupTeamPersistence();
1012
+ await recordShutdownSuppression(orchestrationIntent);
1013
+ return false;
1014
+ }
1015
+
1016
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
1017
+ await cleanupTeamPersistence();
1018
+ await recordShutdownSuppression(orchestrationIntent);
1019
+ return false;
1020
+ }
1021
+
1022
+ nudgeState = nextNudgeState;
1023
+ return true;
1024
+ };
1025
+
1026
+ if (!nudgeReason) {
1027
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
1028
+ await recordShutdownSuppression();
1029
+ continue;
1030
+ }
1031
+ await persistLeaderNudgeBookkeeping();
1032
+ continue;
1033
+ }
1034
+ const orchestrationIntent = resolveLeaderNudgeIntent({ nudgeReason, leaderActionState });
1035
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
1036
+ await recordShutdownSuppression(orchestrationIntent);
1037
+ continue;
1038
+ }
1039
+ const capped = text.length > 180 ? `${text.slice(0, 177)}...` : text;
1040
+ const markedText = `${capped} ${DEFAULT_MARKER}`;
1041
+
1042
+ if (!tmuxTarget) {
1043
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
1044
+ await recordShutdownSuppression(orchestrationIntent);
1045
+ continue;
1046
+ }
1047
+ if (!(await persistLeaderNudgeBookkeeping({ orchestrationIntent, recordLastNudged: true }))) {
1048
+ continue;
830
1049
  }
831
1050
  await emitLeaderNudgeDeferredEvent(cwd, teamName, LEADER_PANE_MISSING_NO_INJECTION_REASON, orchestrationIntent, nowIso, {
832
1051
  tmuxSession,
@@ -873,18 +1092,12 @@ export async function maybeNudgeTeamLeader({
873
1092
  const deferredReason = paneGuard.reason === 'pane_running_shell'
874
1093
  ? LEADER_PANE_SHELL_NO_INJECTION_REASON
875
1094
  : paneGuard.reason;
876
- nudgeState.last_nudged_by_team[teamName] = {
877
- at: nowIso,
878
- last_message_id: newestId || prevMsgId || '',
879
- reason: nudgeReason,
880
- orchestration_intent: orchestrationIntent,
881
- };
882
- if (shouldSendAllIdleNudge) {
883
- nudgeState.last_idle_nudged_by_team[teamName] = {
884
- at: nowIso,
885
- worker_count: workerNames.length,
886
- orchestration_intent: orchestrationIntent,
887
- };
1095
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
1096
+ await recordShutdownSuppression(orchestrationIntent);
1097
+ continue;
1098
+ }
1099
+ if (!(await persistLeaderNudgeBookkeeping({ orchestrationIntent, recordLastNudged: true }))) {
1100
+ continue;
888
1101
  }
889
1102
  await emitLeaderNudgeDeferredEvent(cwd, teamName, deferredReason, orchestrationIntent, nowIso, {
890
1103
  tmuxSession,
@@ -925,20 +1138,13 @@ export async function maybeNudgeTeamLeader({
925
1138
  }
926
1139
 
927
1140
  if (paneAlreadyShowsVisibleLeaderState(paneGuard.paneCapture, capped)) {
928
- nudgeState.last_nudged_by_team[teamName] = {
929
- at: nowIso,
930
- last_message_id: newestId || prevMsgId || '',
931
- reason: nudgeReason,
932
- orchestration_intent: orchestrationIntent,
933
- };
934
- if (shouldSendAllIdleNudge) {
935
- nudgeState.last_idle_nudged_by_team[teamName] = {
936
- at: nowIso,
937
- worker_count: workerNames.length,
938
- orchestration_intent: orchestrationIntent,
939
- };
1141
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
1142
+ await recordShutdownSuppression(orchestrationIntent);
1143
+ continue;
1144
+ }
1145
+ if (!(await persistLeaderNudgeBookkeeping({ orchestrationIntent, recordLastNudged: true }))) {
1146
+ continue;
940
1147
  }
941
-
942
1148
  await emitTeamNudgeEvent(cwd, teamName, nudgeReason, orchestrationIntent, nowIso);
943
1149
 
944
1150
  try {
@@ -973,6 +1179,11 @@ export async function maybeNudgeTeamLeader({
973
1179
  continue;
974
1180
  }
975
1181
 
1182
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
1183
+ await recordShutdownSuppression(orchestrationIntent);
1184
+ continue;
1185
+ }
1186
+
976
1187
  try {
977
1188
  const leaderHasActiveTask = paneHasActiveTask(paneGuard.paneCapture);
978
1189
  let deliveryMode = 'sent';
@@ -996,22 +1207,16 @@ export async function maybeNudgeTeamLeader({
996
1207
  throw new Error(sendResult.error || sendResult.reason);
997
1208
  }
998
1209
  }
999
- nudgeState.last_nudged_by_team[teamName] = {
1000
- at: nowIso,
1001
- last_message_id: newestId || prevMsgId || '',
1002
- reason: nudgeReason,
1003
- orchestration_intent: orchestrationIntent,
1004
- };
1005
- if (shouldSendAllIdleNudge) {
1006
- nudgeState.last_idle_nudged_by_team[teamName] = {
1007
- at: nowIso,
1008
- worker_count: workerNames.length,
1009
- orchestration_intent: orchestrationIntent,
1010
- };
1210
+ if (await teamStateAllowsLeaderNudge(stateDir, teamName)) {
1211
+ if (!(await persistLeaderNudgeBookkeeping({ orchestrationIntent, recordLastNudged: true }))) {
1212
+ continue;
1213
+ }
1214
+ await emitTeamNudgeEvent(cwd, teamName, nudgeReason, orchestrationIntent, nowIso);
1215
+ } else {
1216
+ await recordShutdownSuppression(orchestrationIntent);
1217
+ continue;
1011
1218
  }
1012
1219
 
1013
- await emitTeamNudgeEvent(cwd, teamName, nudgeReason, orchestrationIntent, nowIso);
1014
-
1015
1220
  try {
1016
1221
  await logTmuxHookEvent(logsDir, {
1017
1222
  timestamp: nowIso,
@@ -1039,6 +1244,10 @@ export async function maybeNudgeTeamLeader({
1039
1244
  orchestration_intent: orchestrationIntent,
1040
1245
  }).catch(() => {});
1041
1246
  } catch (err) {
1247
+ if (!(await teamStateAllowsLeaderNudge(stateDir, teamName))) {
1248
+ await recordShutdownSuppression(orchestrationIntent);
1249
+ continue;
1250
+ }
1042
1251
  try {
1043
1252
  await logTmuxHookEvent(logsDir, {
1044
1253
  timestamp: nowIso,
@@ -1063,6 +1272,4 @@ export async function maybeNudgeTeamLeader({
1063
1272
  }).catch(() => {});
1064
1273
  }
1065
1274
  }
1066
-
1067
- await writeFile(nudgeStatePath, JSON.stringify(nudgeState, null, 2)).catch(() => {});
1068
1275
  }
@@ -11,6 +11,28 @@ import {
11
11
  } from '../tmux-hook-engine.js';
12
12
 
13
13
  export const PANE_READINESS_UNVERIFIED_REASON = 'pane_readiness_unverified';
14
+ let nextTmuxBufferId = 0;
15
+
16
+ function buildSafePasteArgv(target: string, prompt: string): {
17
+ bufferName: string;
18
+ setBufferArgv: string[];
19
+ showBufferArgv: string[];
20
+ clearComposerArgv: string[];
21
+ pasteBufferArgv: string[];
22
+ deleteBufferArgv: string[];
23
+ } {
24
+ nextTmuxBufferId += 1;
25
+ const bufferName = `omx-pane-input-${process.pid}-${Date.now()}-${nextTmuxBufferId}`;
26
+ return {
27
+ bufferName,
28
+ setBufferArgv: ['set-buffer', '-b', bufferName, '--', prompt],
29
+ showBufferArgv: ['show-buffer', '-b', bufferName],
30
+ clearComposerArgv: ['send-keys', '-t', target, 'C-u'],
31
+ pasteBufferArgv: ['paste-buffer', '-t', target, '-b', bufferName, '-p', '-d'],
32
+ deleteBufferArgv: ['delete-buffer', '-b', bufferName],
33
+ };
34
+ }
35
+
14
36
 
15
37
  export function mapPaneInjectionReadinessReason(reason: any): any {
16
38
  return reason === 'pane_running_shell' ? 'agent_not_running' : reason;
@@ -145,24 +167,82 @@ export async function sendPaneInput({
145
167
  ? Math.max(0, Math.floor(submitKeyPresses))
146
168
  : 2;
147
169
  const literalPrompt = safeString(prompt);
148
- const argv = normalizedSubmitKeyPresses === 0
149
- ? {
150
- typeArgv: ['send-keys', '-t', target, '-l', literalPrompt],
151
- submitArgv: [] as string[][],
152
- }
170
+ const submitArgv = normalizedSubmitKeyPresses === 0
171
+ ? [] as string[][]
153
172
  : buildSendKeysArgv({
154
173
  paneTarget: target,
155
174
  prompt: literalPrompt,
156
175
  dryRun: false,
157
176
  submitKeyPresses: normalizedSubmitKeyPresses,
158
- });
159
- if (!argv) {
177
+ })?.submitArgv;
178
+ if (!submitArgv) {
160
179
  return { ok: false, sent: false, reason: 'send_failed', paneTarget: target };
161
180
  }
181
+ const pasteArgv = buildSafePasteArgv(target, literalPrompt);
182
+ const argv = {
183
+ typeArgv: pasteArgv.pasteBufferArgv,
184
+ submitArgv,
185
+ bufferName: pasteArgv.bufferName,
186
+ setBufferArgv: pasteArgv.setBufferArgv,
187
+ showBufferArgv: pasteArgv.showBufferArgv,
188
+ clearComposerArgv: pasteArgv.clearComposerArgv,
189
+ pasteBufferArgv: pasteArgv.pasteBufferArgv,
190
+ deleteBufferArgv: pasteArgv.deleteBufferArgv,
191
+ };
162
192
 
193
+ let bufferSet = false;
163
194
  try {
164
195
  if (typePrompt) {
165
- await runProcess('tmux', argv.typeArgv, 3000);
196
+ try {
197
+ await runProcess('tmux', pasteArgv.setBufferArgv, 3000);
198
+ bufferSet = true;
199
+ } catch (error) {
200
+ return {
201
+ ok: false,
202
+ sent: false,
203
+ reason: 'buffer_set_failed',
204
+ paneTarget: target,
205
+ argv,
206
+ error: error instanceof Error ? error.message : safeString(error),
207
+ };
208
+ }
209
+ let verifiedBuffer;
210
+ try {
211
+ verifiedBuffer = await runProcess('tmux', pasteArgv.showBufferArgv, 3000);
212
+ } catch (error) {
213
+ return {
214
+ ok: false,
215
+ sent: false,
216
+ reason: 'buffer_show_failed',
217
+ paneTarget: target,
218
+ argv,
219
+ error: error instanceof Error ? error.message : safeString(error),
220
+ };
221
+ }
222
+ if (verifiedBuffer.stdout !== literalPrompt) {
223
+ return {
224
+ ok: false,
225
+ sent: false,
226
+ reason: 'buffer_verify_failed',
227
+ paneTarget: target,
228
+ argv,
229
+ expectedBytes: literalPrompt.length,
230
+ actualBytes: verifiedBuffer.stdout.length,
231
+ };
232
+ }
233
+ try {
234
+ await runProcess('tmux', pasteArgv.clearComposerArgv, 3000);
235
+ await runProcess('tmux', pasteArgv.pasteBufferArgv, 3000);
236
+ } catch (error) {
237
+ return {
238
+ ok: false,
239
+ sent: false,
240
+ reason: 'buffer_paste_failed',
241
+ paneTarget: target,
242
+ argv,
243
+ error: error instanceof Error ? error.message : safeString(error),
244
+ };
245
+ }
166
246
  }
167
247
  if (queueFirstSubmit && argv.submitArgv.length > 0) {
168
248
  await runProcess('tmux', ['send-keys', '-t', target, 'Tab'], 3000);
@@ -186,6 +266,10 @@ export async function sendPaneInput({
186
266
  argv,
187
267
  error: error instanceof Error ? error.message : safeString(error),
188
268
  };
269
+ } finally {
270
+ if (bufferSet) {
271
+ await runProcess('tmux', pasteArgv.deleteBufferArgv, 3000).catch(() => {});
272
+ }
189
273
  }
190
274
  }
191
275
 
@@ -71,7 +71,7 @@ async function finalizeResolvedPane(paneId: string, reason: string, expectedCwd:
71
71
 
72
72
  async function resolveCanonicalPaneFromPaneTarget(paneTarget: any, expectedCwd: any): Promise<any> {
73
73
  const paneResult = await runProcess('tmux', ['display-message', '-p', '-t', paneTarget, '#{pane_id}']);
74
- const paneId = safeString(paneResult.stdout).trim();
74
+ const paneId = safeString(paneResult.stdout).trim() || (safeString(paneTarget).trim().match(/^%\d+$/) ? safeString(paneTarget).trim() : '');
75
75
  if (!paneId) return { paneTarget: null, reason: 'target_not_found' };
76
76
 
77
77
  let startCommand = '';