oh-my-codex 0.7.5 → 0.8.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 (374) hide show
  1. package/README.de.md +314 -0
  2. package/README.es.md +295 -17
  3. package/README.fr.md +314 -0
  4. package/README.it.md +314 -0
  5. package/README.ja.md +296 -18
  6. package/README.ko.md +295 -17
  7. package/README.md +68 -3
  8. package/README.pt.md +295 -17
  9. package/README.ru.md +295 -17
  10. package/README.tr.md +314 -0
  11. package/README.vi.md +296 -18
  12. package/README.zh.md +292 -17
  13. package/dist/catalog/__tests__/generator.test.js +2 -0
  14. package/dist/catalog/__tests__/generator.test.js.map +1 -1
  15. package/dist/catalog/__tests__/schema.test.js +7 -0
  16. package/dist/catalog/__tests__/schema.test.js.map +1 -1
  17. package/dist/cli/__tests__/ask.test.d.ts +2 -0
  18. package/dist/cli/__tests__/ask.test.d.ts.map +1 -0
  19. package/dist/cli/__tests__/ask.test.js +236 -0
  20. package/dist/cli/__tests__/ask.test.js.map +1 -0
  21. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts +2 -0
  22. package/dist/cli/__tests__/doctor-warning-copy.test.d.ts.map +1 -0
  23. package/dist/cli/__tests__/doctor-warning-copy.test.js +45 -0
  24. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -0
  25. package/dist/cli/__tests__/index.test.js +43 -1
  26. package/dist/cli/__tests__/index.test.js.map +1 -1
  27. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts +2 -0
  28. package/dist/cli/__tests__/ralph-prd-deep-interview.test.d.ts.map +1 -0
  29. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js +15 -0
  30. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -0
  31. package/dist/cli/__tests__/ralph.test.d.ts +2 -0
  32. package/dist/cli/__tests__/ralph.test.d.ts.map +1 -0
  33. package/dist/cli/__tests__/ralph.test.js +40 -0
  34. package/dist/cli/__tests__/ralph.test.js.map +1 -0
  35. package/dist/cli/__tests__/setup-scope.test.js +2 -0
  36. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  37. package/dist/cli/__tests__/team-decompose.test.d.ts +2 -0
  38. package/dist/cli/__tests__/team-decompose.test.d.ts.map +1 -0
  39. package/dist/cli/__tests__/team-decompose.test.js +67 -0
  40. package/dist/cli/__tests__/team-decompose.test.js.map +1 -0
  41. package/dist/cli/__tests__/version.test.d.ts +2 -0
  42. package/dist/cli/__tests__/version.test.d.ts.map +1 -0
  43. package/dist/cli/__tests__/version.test.js +21 -0
  44. package/dist/cli/__tests__/version.test.js.map +1 -0
  45. package/dist/cli/ask.d.ts +13 -0
  46. package/dist/cli/ask.d.ts.map +1 -0
  47. package/dist/cli/ask.js +174 -0
  48. package/dist/cli/ask.js.map +1 -0
  49. package/dist/cli/constants.d.ts +10 -0
  50. package/dist/cli/constants.d.ts.map +1 -0
  51. package/dist/cli/constants.js +10 -0
  52. package/dist/cli/constants.js.map +1 -0
  53. package/dist/cli/doctor.js +16 -5
  54. package/dist/cli/doctor.js.map +1 -1
  55. package/dist/cli/index.d.ts +7 -1
  56. package/dist/cli/index.d.ts.map +1 -1
  57. package/dist/cli/index.js +117 -43
  58. package/dist/cli/index.js.map +1 -1
  59. package/dist/cli/ralph.d.ts +4 -0
  60. package/dist/cli/ralph.d.ts.map +1 -1
  61. package/dist/cli/ralph.js +89 -13
  62. package/dist/cli/ralph.js.map +1 -1
  63. package/dist/cli/setup.js +1 -1
  64. package/dist/cli/setup.js.map +1 -1
  65. package/dist/cli/team.d.ts +18 -0
  66. package/dist/cli/team.d.ts.map +1 -1
  67. package/dist/cli/team.js +108 -16
  68. package/dist/cli/team.js.map +1 -1
  69. package/dist/config/generator.d.ts.map +1 -1
  70. package/dist/config/generator.js +8 -0
  71. package/dist/config/generator.js.map +1 -1
  72. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts +2 -0
  73. package/dist/hooks/__tests__/deep-interview-contract.test.d.ts.map +1 -0
  74. package/dist/hooks/__tests__/deep-interview-contract.test.js +55 -0
  75. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -0
  76. package/dist/hooks/__tests__/emulator.test.js +6 -0
  77. package/dist/hooks/__tests__/emulator.test.js.map +1 -1
  78. package/dist/hooks/__tests__/keyword-detector.test.js +44 -22
  79. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  80. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +59 -0
  81. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  82. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +88 -0
  83. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  84. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +199 -0
  85. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  86. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts +11 -0
  87. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.d.ts.map +1 -0
  88. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js +266 -0
  89. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -0
  90. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts +2 -0
  91. package/dist/hooks/__tests__/openclaw-setup-contract.test.d.ts.map +1 -0
  92. package/dist/hooks/__tests__/openclaw-setup-contract.test.js +51 -0
  93. package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -0
  94. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts +2 -0
  95. package/dist/hooks/__tests__/pre-context-gate-skills.test.d.ts.map +1 -0
  96. package/dist/hooks/__tests__/pre-context-gate-skills.test.js +34 -0
  97. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -0
  98. package/dist/hooks/__tests__/tmux-hook-engine.test.js +36 -1
  99. package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +1 -1
  100. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts +2 -0
  101. package/dist/hooks/__tests__/visual-verdict-loop.test.d.ts.map +1 -0
  102. package/dist/hooks/__tests__/visual-verdict-loop.test.js +35 -0
  103. package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -0
  104. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  105. package/dist/hooks/agents-overlay.js +18 -16
  106. package/dist/hooks/agents-overlay.js.map +1 -1
  107. package/dist/hooks/codebase-map.d.ts.map +1 -1
  108. package/dist/hooks/codebase-map.js +6 -2
  109. package/dist/hooks/codebase-map.js.map +1 -1
  110. package/dist/hooks/emulator.d.ts.map +1 -1
  111. package/dist/hooks/emulator.js +2 -0
  112. package/dist/hooks/emulator.js.map +1 -1
  113. package/dist/hooks/extensibility/sdk.d.ts.map +1 -1
  114. package/dist/hooks/extensibility/sdk.js +2 -1
  115. package/dist/hooks/extensibility/sdk.js.map +1 -1
  116. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  117. package/dist/hooks/keyword-registry.js +6 -0
  118. package/dist/hooks/keyword-registry.js.map +1 -1
  119. package/dist/hud/index.d.ts.map +1 -1
  120. package/dist/hud/index.js +2 -24
  121. package/dist/hud/index.js.map +1 -1
  122. package/dist/mcp/__tests__/team-server-cleanup.test.d.ts +2 -0
  123. package/dist/mcp/__tests__/team-server-cleanup.test.d.ts.map +1 -0
  124. package/dist/mcp/__tests__/team-server-cleanup.test.js +219 -0
  125. package/dist/mcp/__tests__/team-server-cleanup.test.js.map +1 -0
  126. package/dist/mcp/bootstrap.d.ts +1 -1
  127. package/dist/mcp/bootstrap.d.ts.map +1 -1
  128. package/dist/mcp/bootstrap.js +1 -0
  129. package/dist/mcp/bootstrap.js.map +1 -1
  130. package/dist/mcp/code-intel-server.d.ts.map +1 -1
  131. package/dist/mcp/code-intel-server.js +18 -8
  132. package/dist/mcp/code-intel-server.js.map +1 -1
  133. package/dist/mcp/memory-server.js +72 -11
  134. package/dist/mcp/memory-server.js.map +1 -1
  135. package/dist/mcp/state-paths.d.ts.map +1 -1
  136. package/dist/mcp/state-paths.js +4 -1
  137. package/dist/mcp/state-paths.js.map +1 -1
  138. package/dist/mcp/state-server.d.ts.map +1 -1
  139. package/dist/mcp/state-server.js +18 -5
  140. package/dist/mcp/state-server.js.map +1 -1
  141. package/dist/mcp/team-server.d.ts +24 -0
  142. package/dist/mcp/team-server.d.ts.map +1 -0
  143. package/dist/mcp/team-server.js +425 -0
  144. package/dist/mcp/team-server.js.map +1 -0
  145. package/dist/mcp/trace-server.d.ts.map +1 -1
  146. package/dist/mcp/trace-server.js +8 -3
  147. package/dist/mcp/trace-server.js.map +1 -1
  148. package/dist/notifications/__tests__/verbosity.test.js +35 -0
  149. package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
  150. package/dist/notifications/config.d.ts.map +1 -1
  151. package/dist/notifications/config.js +12 -3
  152. package/dist/notifications/config.js.map +1 -1
  153. package/dist/notifications/dispatcher.d.ts.map +1 -1
  154. package/dist/notifications/dispatcher.js +4 -4
  155. package/dist/notifications/dispatcher.js.map +1 -1
  156. package/dist/notifications/reply-listener.d.ts.map +1 -1
  157. package/dist/notifications/reply-listener.js +6 -2
  158. package/dist/notifications/reply-listener.js.map +1 -1
  159. package/dist/notifications/session-registry.d.ts.map +1 -1
  160. package/dist/notifications/session-registry.js +2 -2
  161. package/dist/notifications/session-registry.js.map +1 -1
  162. package/dist/notifications/tmux.d.ts.map +1 -1
  163. package/dist/notifications/tmux.js +13 -4
  164. package/dist/notifications/tmux.js.map +1 -1
  165. package/dist/notifications/types.d.ts +4 -0
  166. package/dist/notifications/types.d.ts.map +1 -1
  167. package/dist/openclaw/__tests__/index.test.js +40 -0
  168. package/dist/openclaw/__tests__/index.test.js.map +1 -1
  169. package/dist/openclaw/dispatcher.d.ts.map +1 -1
  170. package/dist/openclaw/dispatcher.js +5 -2
  171. package/dist/openclaw/dispatcher.js.map +1 -1
  172. package/dist/openclaw/index.d.ts.map +1 -1
  173. package/dist/openclaw/index.js +1 -0
  174. package/dist/openclaw/index.js.map +1 -1
  175. package/dist/openclaw/types.d.ts +2 -0
  176. package/dist/openclaw/types.d.ts.map +1 -1
  177. package/dist/ralph/__tests__/persistence.test.js +28 -1
  178. package/dist/ralph/__tests__/persistence.test.js.map +1 -1
  179. package/dist/ralph/persistence.d.ts +21 -0
  180. package/dist/ralph/persistence.d.ts.map +1 -1
  181. package/dist/ralph/persistence.js +85 -2
  182. package/dist/ralph/persistence.js.map +1 -1
  183. package/dist/state/paths.d.ts +3 -0
  184. package/dist/state/paths.d.ts.map +1 -0
  185. package/dist/state/paths.js +2 -0
  186. package/dist/state/paths.js.map +1 -0
  187. package/dist/team/__tests__/idle-nudge.test.d.ts +2 -0
  188. package/dist/team/__tests__/idle-nudge.test.d.ts.map +1 -0
  189. package/dist/team/__tests__/idle-nudge.test.js +225 -0
  190. package/dist/team/__tests__/idle-nudge.test.js.map +1 -0
  191. package/dist/team/__tests__/role-router.test.d.ts +2 -0
  192. package/dist/team/__tests__/role-router.test.d.ts.map +1 -0
  193. package/dist/team/__tests__/role-router.test.js +204 -0
  194. package/dist/team/__tests__/role-router.test.js.map +1 -0
  195. package/dist/team/__tests__/runtime-cli.test.d.ts +2 -0
  196. package/dist/team/__tests__/runtime-cli.test.d.ts.map +1 -0
  197. package/dist/team/__tests__/runtime-cli.test.js +72 -0
  198. package/dist/team/__tests__/runtime-cli.test.js.map +1 -0
  199. package/dist/team/__tests__/runtime.test.js +195 -9
  200. package/dist/team/__tests__/runtime.test.js.map +1 -1
  201. package/dist/team/__tests__/scaling.test.js +132 -2
  202. package/dist/team/__tests__/scaling.test.js.map +1 -1
  203. package/dist/team/__tests__/state-root.test.d.ts +2 -0
  204. package/dist/team/__tests__/state-root.test.d.ts.map +1 -0
  205. package/dist/team/__tests__/state-root.test.js +9 -0
  206. package/dist/team/__tests__/state-root.test.js.map +1 -0
  207. package/dist/team/__tests__/state.test.js +52 -17
  208. package/dist/team/__tests__/state.test.js.map +1 -1
  209. package/dist/team/__tests__/team-ops-contract.test.d.ts +2 -0
  210. package/dist/team/__tests__/team-ops-contract.test.d.ts.map +1 -0
  211. package/dist/team/__tests__/team-ops-contract.test.js +90 -0
  212. package/dist/team/__tests__/team-ops-contract.test.js.map +1 -0
  213. package/dist/team/__tests__/tmux-session.test.js +94 -7
  214. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  215. package/dist/team/__tests__/worker-bootstrap.test.js +59 -0
  216. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  217. package/dist/team/__tests__/worktree.test.js +81 -2
  218. package/dist/team/__tests__/worktree.test.js.map +1 -1
  219. package/dist/team/idle-nudge.d.ts +53 -0
  220. package/dist/team/idle-nudge.d.ts.map +1 -0
  221. package/dist/team/idle-nudge.js +140 -0
  222. package/dist/team/idle-nudge.js.map +1 -0
  223. package/dist/team/mcp-comm.d.ts +1 -1
  224. package/dist/team/mcp-comm.d.ts.map +1 -1
  225. package/dist/team/mcp-comm.js +6 -2
  226. package/dist/team/mcp-comm.js.map +1 -1
  227. package/dist/team/orchestrator.d.ts +1 -10
  228. package/dist/team/orchestrator.d.ts.map +1 -1
  229. package/dist/team/orchestrator.js +8 -0
  230. package/dist/team/orchestrator.js.map +1 -1
  231. package/dist/team/role-router.d.ts +32 -0
  232. package/dist/team/role-router.d.ts.map +1 -0
  233. package/dist/team/role-router.js +137 -0
  234. package/dist/team/role-router.js.map +1 -0
  235. package/dist/team/runtime-cli.d.ts +18 -0
  236. package/dist/team/runtime-cli.d.ts.map +1 -0
  237. package/dist/team/runtime-cli.js +244 -0
  238. package/dist/team/runtime-cli.js.map +1 -0
  239. package/dist/team/runtime.d.ts +6 -1
  240. package/dist/team/runtime.d.ts.map +1 -1
  241. package/dist/team/runtime.js +148 -60
  242. package/dist/team/runtime.js.map +1 -1
  243. package/dist/team/scaling.d.ts +1 -0
  244. package/dist/team/scaling.d.ts.map +1 -1
  245. package/dist/team/scaling.js +74 -32
  246. package/dist/team/scaling.js.map +1 -1
  247. package/dist/team/state/approvals.d.ts +25 -0
  248. package/dist/team/state/approvals.d.ts.map +1 -0
  249. package/dist/team/state/approvals.js +31 -0
  250. package/dist/team/state/approvals.js.map +1 -0
  251. package/dist/team/state/config.d.ts +2 -0
  252. package/dist/team/state/config.d.ts.map +1 -0
  253. package/dist/team/state/config.js +2 -0
  254. package/dist/team/state/config.js.map +1 -0
  255. package/dist/team/state/dispatch-lock.d.ts +3 -0
  256. package/dist/team/state/dispatch-lock.d.ts.map +1 -0
  257. package/dist/team/state/dispatch-lock.js +81 -0
  258. package/dist/team/state/dispatch-lock.js.map +1 -0
  259. package/dist/team/state/dispatch.d.ts +61 -0
  260. package/dist/team/state/dispatch.d.ts.map +1 -0
  261. package/dist/team/state/dispatch.js +158 -0
  262. package/dist/team/state/dispatch.js.map +1 -0
  263. package/dist/team/state/events.d.ts +2 -0
  264. package/dist/team/state/events.d.ts.map +1 -0
  265. package/dist/team/state/events.js +2 -0
  266. package/dist/team/state/events.js.map +1 -0
  267. package/dist/team/state/index.d.ts +11 -0
  268. package/dist/team/state/index.d.ts.map +1 -0
  269. package/dist/team/state/index.js +11 -0
  270. package/dist/team/state/index.js.map +1 -0
  271. package/dist/team/state/io.d.ts +2 -0
  272. package/dist/team/state/io.d.ts.map +1 -0
  273. package/dist/team/state/io.js +2 -0
  274. package/dist/team/state/io.js.map +1 -0
  275. package/dist/team/state/locks.d.ts +16 -0
  276. package/dist/team/state/locks.d.ts.map +1 -0
  277. package/dist/team/state/locks.js +201 -0
  278. package/dist/team/state/locks.js.map +1 -0
  279. package/dist/team/state/mailbox.d.ts +39 -0
  280. package/dist/team/state/mailbox.d.ts.map +1 -0
  281. package/dist/team/state/mailbox.js +58 -0
  282. package/dist/team/state/mailbox.js.map +1 -0
  283. package/dist/team/state/monitor.d.ts +96 -0
  284. package/dist/team/state/monitor.d.ts.map +1 -0
  285. package/dist/team/state/monitor.js +163 -0
  286. package/dist/team/state/monitor.js.map +1 -0
  287. package/dist/team/state/shutdown.d.ts +2 -0
  288. package/dist/team/state/shutdown.d.ts.map +1 -0
  289. package/dist/team/state/shutdown.js +2 -0
  290. package/dist/team/state/shutdown.js.map +1 -0
  291. package/dist/team/state/summary.d.ts +2 -0
  292. package/dist/team/state/summary.d.ts.map +1 -0
  293. package/dist/team/state/summary.js +2 -0
  294. package/dist/team/state/summary.js.map +1 -0
  295. package/dist/team/state/tasks.d.ts +49 -0
  296. package/dist/team/state/tasks.d.ts.map +1 -0
  297. package/dist/team/state/tasks.js +182 -0
  298. package/dist/team/state/tasks.js.map +1 -0
  299. package/dist/team/state/types.d.ts +281 -0
  300. package/dist/team/state/types.d.ts.map +1 -0
  301. package/dist/team/state/types.js +3 -0
  302. package/dist/team/state/types.js.map +1 -0
  303. package/dist/team/state/workers.d.ts +2 -0
  304. package/dist/team/state/workers.d.ts.map +1 -0
  305. package/dist/team/state/workers.js +2 -0
  306. package/dist/team/state/workers.js.map +1 -0
  307. package/dist/team/state-root.d.ts +5 -0
  308. package/dist/team/state-root.d.ts.map +1 -0
  309. package/dist/team/state-root.js +8 -0
  310. package/dist/team/state-root.js.map +1 -0
  311. package/dist/team/state.d.ts +6 -2
  312. package/dist/team/state.d.ts.map +1 -1
  313. package/dist/team/state.js +200 -881
  314. package/dist/team/state.js.map +1 -1
  315. package/dist/team/tmux-session.d.ts +42 -2
  316. package/dist/team/tmux-session.d.ts.map +1 -1
  317. package/dist/team/tmux-session.js +229 -74
  318. package/dist/team/tmux-session.js.map +1 -1
  319. package/dist/team/worker-bootstrap.d.ts +2 -0
  320. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  321. package/dist/team/worker-bootstrap.js +47 -20
  322. package/dist/team/worker-bootstrap.js.map +1 -1
  323. package/dist/team/worktree.d.ts +5 -1
  324. package/dist/team/worktree.d.ts.map +1 -1
  325. package/dist/team/worktree.js +71 -17
  326. package/dist/team/worktree.js.map +1 -1
  327. package/dist/utils/safe-json.d.ts +3 -0
  328. package/dist/utils/safe-json.d.ts.map +1 -0
  329. package/dist/utils/safe-json.js +19 -0
  330. package/dist/utils/safe-json.js.map +1 -0
  331. package/dist/utils/sleep.d.ts +3 -0
  332. package/dist/utils/sleep.d.ts.map +1 -0
  333. package/dist/utils/sleep.js +15 -0
  334. package/dist/utils/sleep.js.map +1 -0
  335. package/dist/visual/__tests__/verdict.test.d.ts +2 -0
  336. package/dist/visual/__tests__/verdict.test.d.ts.map +1 -0
  337. package/dist/visual/__tests__/verdict.test.js +81 -0
  338. package/dist/visual/__tests__/verdict.test.js.map +1 -0
  339. package/dist/visual/constants.d.ts +4 -0
  340. package/dist/visual/constants.d.ts.map +1 -0
  341. package/dist/visual/constants.js +3 -0
  342. package/dist/visual/constants.js.map +1 -0
  343. package/dist/visual/verdict.d.ts +17 -0
  344. package/dist/visual/verdict.d.ts.map +1 -0
  345. package/dist/visual/verdict.js +61 -0
  346. package/dist/visual/verdict.js.map +1 -0
  347. package/package.json +10 -3
  348. package/scripts/ask-claude.sh +17 -0
  349. package/scripts/ask-gemini.sh +14 -0
  350. package/scripts/fixtures/ask-advisor-stub.js +12 -0
  351. package/scripts/notify-hook/log.js +5 -0
  352. package/scripts/notify-hook/team-dispatch.js +56 -1
  353. package/scripts/notify-hook/tmux-injection.js +45 -4
  354. package/scripts/notify-hook/visual-verdict.js +158 -0
  355. package/scripts/notify-hook.js +27 -0
  356. package/scripts/run-provider-advisor.js +179 -0
  357. package/scripts/tmux-hook-engine.js +24 -0
  358. package/skills/ask-claude/SKILL.md +61 -0
  359. package/skills/ask-gemini/SKILL.md +61 -0
  360. package/skills/autopilot/SKILL.md +34 -4
  361. package/skills/configure-notifications/SKILL.md +1 -1
  362. package/skills/configure-openclaw/SKILL.md +154 -157
  363. package/skills/deep-interview/SKILL.md +247 -0
  364. package/skills/doctor/SKILL.md +1 -1
  365. package/skills/help/SKILL.md +3 -3
  366. package/skills/ralph/SKILL.md +42 -11
  367. package/skills/ralplan/SKILL.md +17 -0
  368. package/skills/skill/SKILL.md +32 -32
  369. package/skills/team/SKILL.md +60 -0
  370. package/skills/visual-verdict/SKILL.md +76 -0
  371. package/skills/web-clone/SKILL.md +366 -0
  372. package/skills/worker/SKILL.md +5 -4
  373. package/templates/AGENTS.md +9 -0
  374. package/templates/catalog-manifest.json +39 -2
@@ -1,13 +1,12 @@
1
- import { spawnSync } from 'child_process';
1
+ import { spawnSync, execFile } from 'child_process';
2
+ import { promisify } from 'util';
2
3
  import { readFileSync } from 'fs';
3
4
  import { join } from 'path';
5
+ import { CODEX_BYPASS_FLAG, MADMAX_FLAG, CONFIG_FLAG, LONG_CONFIG_FLAG, MODEL_FLAG, } from '../cli/constants.js';
6
+ import { sleep, sleepSync } from '../utils/sleep.js';
7
+ const execFileAsync = promisify(execFile);
4
8
  import { HUD_RESIZE_RECONCILE_DELAY_SECONDS, HUD_TMUX_TEAM_HEIGHT_LINES } from '../hud/constants.js';
5
9
  const INJECTION_MARKER = '[OMX_TMUX_INJECT]';
6
- const CODEX_BYPASS_FLAG = '--dangerously-bypass-approvals-and-sandbox';
7
- const MADMAX_FLAG = '--madmax';
8
- const CONFIG_FLAG = '-c';
9
- const LONG_CONFIG_FLAG = '--config';
10
- const MODEL_FLAG = '--model';
11
10
  const MODEL_INSTRUCTIONS_FILE_KEY = 'model_instructions_file';
12
11
  const OMX_BYPASS_DEFAULT_SYSTEM_PROMPT_ENV = 'OMX_BYPASS_DEFAULT_SYSTEM_PROMPT';
13
12
  const OMX_MODEL_INSTRUCTIONS_FILE_ENV = 'OMX_MODEL_INSTRUCTIONS_FILE';
@@ -99,9 +98,6 @@ function findHudPaneIds(target, leaderPaneId) {
99
98
  .filter((pane) => isHudWatchPane(pane))
100
99
  .map((pane) => pane.paneId);
101
100
  }
102
- function sleepMs(ms) {
103
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
104
- }
105
101
  const MAX_FRACTIONAL_SLEEP_MS = 60_000;
106
102
  function toFractionalSleepMs(seconds) {
107
103
  if (!Number.isFinite(seconds) || seconds <= 0)
@@ -114,12 +110,64 @@ function toFractionalSleepMs(seconds) {
114
110
  function sleepSeconds(seconds) {
115
111
  sleepFractionalSeconds(seconds);
116
112
  }
117
- export function sleepFractionalSeconds(seconds, sleepImpl = sleepMs) {
113
+ export function sleepFractionalSeconds(seconds, sleepImpl = sleepSync) {
118
114
  const ms = toFractionalSleepMs(seconds);
119
115
  if (ms <= 0)
120
116
  return;
121
117
  sleepImpl(ms);
122
118
  }
119
+ // ── Async tmux helpers ──────────────────────────────────────────────────────
120
+ async function runTmuxAsync(args) {
121
+ try {
122
+ const { stdout } = await execFileAsync('tmux', args, { encoding: 'utf-8' });
123
+ return { ok: true, stdout: (stdout || '').trim() };
124
+ }
125
+ catch (error) {
126
+ const err = error;
127
+ return { ok: false, stderr: (err.stderr || err.message || '').trim() || 'tmux command failed' };
128
+ }
129
+ }
130
+ async function sendKeyAsync(target, key) {
131
+ const result = await runTmuxAsync(['send-keys', '-t', target, key]);
132
+ if (!result.ok) {
133
+ throw new Error(`sendKeyAsync: failed to send ${key}: ${result.stderr}`);
134
+ }
135
+ }
136
+ async function capturePaneAsync(target) {
137
+ const result = await runTmuxAsync(['capture-pane', '-t', target, '-p', '-S', '-80']);
138
+ if (!result.ok)
139
+ return '';
140
+ return result.stdout;
141
+ }
142
+ async function isWorkerAliveAsync(sessionName, workerIndex, workerPaneId) {
143
+ const result = await runTmuxAsync([
144
+ 'list-panes',
145
+ '-t', paneTarget(sessionName, workerIndex, workerPaneId),
146
+ '-F',
147
+ '#{pane_dead} #{pane_pid}',
148
+ ]);
149
+ if (!result.ok)
150
+ return false;
151
+ const line = result.stdout.split('\n')[0]?.trim();
152
+ if (!line)
153
+ return false;
154
+ const parts = line.split(/\s+/);
155
+ if (parts.length < 2)
156
+ return false;
157
+ const paneDead = parts[0];
158
+ const pid = Number.parseInt(parts[1], 10);
159
+ if (paneDead === '1')
160
+ return false;
161
+ if (!Number.isFinite(pid))
162
+ return false;
163
+ try {
164
+ process.kill(pid, 0);
165
+ return true;
166
+ }
167
+ catch {
168
+ return false;
169
+ }
170
+ }
123
171
  function shellQuoteSingle(value) {
124
172
  return `'${value.replace(/'/g, `'\\''`)}'`;
125
173
  }
@@ -489,9 +537,14 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
489
537
  let registeredResizeHook = null;
490
538
  const rollbackPaneIds = [];
491
539
  try {
492
- const context = runTmux(['display-message', '-p', '#S:#I #{pane_id}']);
540
+ const tmuxPaneTarget = process.env.TMUX_PANE;
541
+ const displayArgs = tmuxPaneTarget
542
+ ? ['display-message', '-p', '-t', tmuxPaneTarget, '#S:#I #{pane_id}']
543
+ : ['display-message', '-p', '#S:#I #{pane_id}'];
544
+ const context = runTmux(displayArgs);
493
545
  if (!context.ok) {
494
- throw new Error(`failed to detect current tmux target: ${context.stderr}`);
546
+ const paneHint = tmuxPaneTarget ? ` (TMUX_PANE=${tmuxPaneTarget})` : '';
547
+ throw new Error(`failed to detect current tmux target${paneHint}: ${context.stderr}`);
495
548
  }
496
549
  const [sessionAndWindow = '', detectedLeaderPaneId = ''] = context.stdout.split(' ');
497
550
  const [sessionName, windowIndex] = (sessionAndWindow || '').split(':');
@@ -706,7 +759,7 @@ export function paneIsBootstrapping(lines) {
706
759
  /\bmodel:\s*loading\b/i.test(line) ||
707
760
  /\bconnecting\s+to\b/i.test(line));
708
761
  }
709
- function paneLooksReady(captured) {
762
+ export function paneLooksReady(captured) {
710
763
  const content = captured.trimEnd();
711
764
  if (content === '')
712
765
  return false;
@@ -730,6 +783,11 @@ function paneLooksReady(captured) {
730
783
  const hasClaudePromptLine = lines.some((line) => /^\s*❯\s*/u.test(line));
731
784
  if (hasCodexPromptLine || hasClaudePromptLine)
732
785
  return true;
786
+ // Custom per-issue prompts (e.g. "› IND-123 only..."). Capture output can
787
+ // occasionally omit the glyph, so accept both with/without leading prompt char.
788
+ const hasIssuePromptLine = lines.some((line) => /^\s*(?:[›>❯]\s*)?[A-Z][A-Z0-9]+-\d+\s+only(?:\s*(?:…|\.{3}))?\s*$/iu.test(line));
789
+ if (hasIssuePromptLine)
790
+ return true;
733
791
  // Status-only markers (model name in status bar, token budget) are NOT
734
792
  // sufficient on their own — they can appear during bootstrap before the CLI
735
793
  // accepts input. Require an actual prompt character (checked above).
@@ -745,12 +803,15 @@ function paneHasTrustPrompt(captured) {
745
803
  const hasActiveChoices = tail.some((line) => /Yes,\s*continue|No,\s*quit|Press enter to continue/i.test(line));
746
804
  return hasQuestion && hasActiveChoices;
747
805
  }
748
- function paneHasActiveTask(captured) {
806
+ export function paneHasActiveTask(captured) {
749
807
  const lines = captured
750
808
  .split('\n')
751
809
  .map((line) => line.replace(/\r/g, '').trim())
752
810
  .filter((line) => line.length > 0);
753
811
  const tail = lines.slice(-40);
812
+ // Codex v5 status line can appear without "esc to interrupt"; treat as busy first.
813
+ if (tail.some((line) => /\b\d+\s+background terminal running\b/i.test(line)))
814
+ return true;
754
815
  if (tail.some((line) => /esc to interrupt/i.test(line)))
755
816
  return true;
756
817
  if (tail.some((line) => /\bbackground terminal running\b/i.test(line)))
@@ -836,39 +897,34 @@ export function shouldAttemptAdaptiveRetry(strategy, paneBusyAtStart, allowAdapt
836
897
  return false;
837
898
  return true;
838
899
  }
839
- function sendKeyOrThrow(target, key, label) {
840
- const result = runTmux(['send-keys', '-t', target, key]);
841
- if (!result.ok) {
842
- throw new Error(`sendToWorker: failed to send ${label}: ${result.stderr}`);
843
- }
844
- }
845
900
  function sendLiteralTextOrThrow(target, text) {
846
901
  const send = runTmux(['send-keys', '-t', target, '-l', '--', text]);
847
902
  if (!send.ok) {
848
903
  throw new Error(`sendToWorker: failed to send text: ${send.stderr}`);
849
904
  }
850
905
  }
851
- function attemptSubmitRounds(target, text, rounds, queueFirstRound, submitKeyPressesPerRound) {
906
+ async function attemptSubmitRounds(target, text, rounds, queueFirstRound, submitKeyPressesPerRound) {
852
907
  const presses = Math.max(1, Math.floor(submitKeyPressesPerRound));
853
908
  for (let round = 0; round < rounds; round++) {
854
- sleepFractionalSeconds(0.1);
909
+ await sleep(100);
855
910
  if (round === 0 && queueFirstRound) {
856
- sendKeyOrThrow(target, 'Tab', 'Tab');
857
- sleepFractionalSeconds(0.08);
858
- sendKeyOrThrow(target, 'C-m', 'C-m');
911
+ await sendKeyAsync(target, 'Tab');
912
+ await sleep(80);
913
+ await sendKeyAsync(target, 'C-m');
859
914
  }
860
915
  else {
861
916
  for (let press = 0; press < presses; press++) {
862
- sendKeyOrThrow(target, 'C-m', 'C-m');
917
+ await sendKeyAsync(target, 'C-m');
863
918
  if (press < presses - 1) {
864
- sleepFractionalSeconds(0.2);
919
+ await sleep(200);
865
920
  }
866
921
  }
867
922
  }
868
- sleepFractionalSeconds(0.14);
869
- if (!paneTailContainsLiteralLine(target, text))
923
+ await sleep(140);
924
+ const captured = await capturePaneAsync(target);
925
+ if (!normalizeTmuxCapture(captured).includes(normalizeTmuxCapture(text)))
870
926
  return true;
871
- sleepFractionalSeconds(0.14);
927
+ await sleep(140);
872
928
  }
873
929
  return false;
874
930
  }
@@ -948,12 +1004,6 @@ export function dismissTrustPromptIfPresent(sessionName, workerIndex, workerPane
948
1004
  runTmux(['send-keys', '-t', target, 'C-m']);
949
1005
  return true;
950
1006
  }
951
- function paneTailContainsLiteralLine(target, text) {
952
- const result = runTmux(['capture-pane', '-t', target, '-p', '-S', '-80']);
953
- if (!result.ok)
954
- return false;
955
- return normalizeTmuxCapture(result.stdout).includes(normalizeTmuxCapture(text));
956
- }
957
1007
  export function normalizeTmuxCapture(value) {
958
1008
  return value
959
1009
  .replace(/\r/g, '')
@@ -981,47 +1031,46 @@ export function sendToWorkerStdin(stdin, text) {
981
1031
  // Send SHORT text (<200 chars) to worker via tmux send-keys
982
1032
  // Validates: text < 200 chars, no injection marker
983
1033
  // Throws on violation
984
- export function sendToWorker(sessionName, workerIndex, text, workerPaneId, workerCli) {
1034
+ export async function sendToWorker(sessionName, workerIndex, text, workerPaneId, workerCli) {
985
1035
  assertWorkerTriggerText(text);
986
1036
  const target = paneTarget(sessionName, workerIndex, workerPaneId);
987
1037
  const strategy = resolveSendStrategyFromEnv();
988
1038
  const resolvedWorkerCli = resolveWorkerCliForSend(workerIndex, workerCli);
989
1039
  // Guard: if the trust prompt is still present, advance it first so our trigger text
990
1040
  // doesn't get typed into the trust screen and ignored.
991
- const captured = runTmux(['capture-pane', '-t', target, '-p', '-S', '-80']);
992
- const paneBusy = captured.ok ? paneHasActiveTask(captured.stdout) : false;
993
- if (captured.ok && paneHasTrustPrompt(captured.stdout)) {
994
- sendKeyOrThrow(target, 'C-m', 'C-m');
995
- sleepFractionalSeconds(0.12);
996
- sendKeyOrThrow(target, 'C-m', 'C-m');
997
- sleepFractionalSeconds(0.2);
1041
+ const capturedStr = await capturePaneAsync(target);
1042
+ const paneBusy = paneHasActiveTask(capturedStr);
1043
+ if (paneHasTrustPrompt(capturedStr)) {
1044
+ await sendKeyAsync(target, 'C-m');
1045
+ await sleep(120);
1046
+ await sendKeyAsync(target, 'C-m');
1047
+ await sleep(200);
998
1048
  }
999
1049
  sendLiteralTextOrThrow(target, text);
1000
1050
  // Allow the input buffer to settle before sending C-m
1001
- sleepFractionalSeconds(0.15);
1051
+ await sleep(150);
1002
1052
  const allowAutoInterruptRetry = process.env[OMX_TEAM_AUTO_INTERRUPT_RETRY_ENV] !== '0';
1003
1053
  const submitPlan = buildWorkerSubmitPlan(strategy, resolvedWorkerCli, paneBusy, allowAutoInterruptRetry);
1004
1054
  if (submitPlan.shouldInterrupt) {
1005
1055
  // Explicit interrupt mode: abort current turn first, then submit the new command.
1006
- sendKeyOrThrow(target, 'C-c', 'C-c');
1007
- sleepFractionalSeconds(0.1);
1056
+ await sendKeyAsync(target, 'C-c');
1057
+ await sleep(100);
1008
1058
  }
1009
1059
  // Submit deterministically using CLI-specific plan:
1010
1060
  // - Codex: queue-first Tab+C-m when configured/busy, then double C-m rounds.
1011
1061
  // - Claude: direct C-m rounds only (never queue-first Tab).
1012
- if (attemptSubmitRounds(target, text, submitPlan.rounds, submitPlan.queueFirstRound, submitPlan.submitKeyPressesPerRound))
1062
+ if (await attemptSubmitRounds(target, text, submitPlan.rounds, submitPlan.queueFirstRound, submitPlan.submitKeyPressesPerRound))
1013
1063
  return;
1014
1064
  // Adaptive escalation for "likely unsent trigger text at ready prompt" cases:
1015
1065
  // clear line, re-send trigger, then re-submit with deterministic C-m rounds.
1016
- const latestCaptureResult = runTmux(['capture-pane', '-t', target, '-p', '-S', '-80']);
1017
- const latestCapture = latestCaptureResult.ok ? latestCaptureResult.stdout : null;
1018
- if (shouldAttemptAdaptiveRetry(strategy, paneBusy, submitPlan.allowAdaptiveRetry, latestCapture, text)) {
1066
+ const latestCapture = await capturePaneAsync(target);
1067
+ if (shouldAttemptAdaptiveRetry(strategy, paneBusy, submitPlan.allowAdaptiveRetry, latestCapture || null, text)) {
1019
1068
  // Keep this branch non-interrupting to avoid canceling active turns on false positives.
1020
- sendKeyOrThrow(target, 'C-u', 'C-u');
1021
- sleepFractionalSeconds(0.08);
1069
+ await sendKeyAsync(target, 'C-u');
1070
+ await sleep(80);
1022
1071
  sendLiteralTextOrThrow(target, text);
1023
- sleepFractionalSeconds(0.12);
1024
- if (attemptSubmitRounds(target, text, 4, false, submitPlan.submitKeyPressesPerRound))
1072
+ await sleep(120);
1073
+ if (await attemptSubmitRounds(target, text, 4, false, submitPlan.submitKeyPressesPerRound))
1025
1074
  return;
1026
1075
  }
1027
1076
  // Fail-open by default: Codex may keep the last submitted line visible even after executing it.
@@ -1031,22 +1080,22 @@ export function sendToWorker(sessionName, workerIndex, text, workerPaneId, worke
1031
1080
  throw new Error('sendToWorker: submit_failed (trigger text still visible after retries)');
1032
1081
  }
1033
1082
  // One last best-effort double C-m nudge, then verify.
1034
- runTmux(['send-keys', '-t', target, 'C-m']);
1035
- sleepFractionalSeconds(0.12);
1036
- runTmux(['send-keys', '-t', target, 'C-m']);
1083
+ await sendKeyAsync(target, 'C-m');
1084
+ await sleep(120);
1085
+ await sendKeyAsync(target, 'C-m');
1037
1086
  // Post-submit verification: wait briefly and confirm the worker consumed the
1038
1087
  // trigger (draft disappeared or active-task indicator appeared). Fixes #391.
1039
- sleepFractionalSeconds(0.3);
1040
- const verifyResult = runTmux(['capture-pane', '-t', target, '-p', '-S', '-80']);
1041
- if (verifyResult.ok) {
1042
- if (paneHasActiveTask(verifyResult.stdout))
1088
+ await sleep(300);
1089
+ const verifyCapture = await capturePaneAsync(target);
1090
+ if (verifyCapture) {
1091
+ if (paneHasActiveTask(verifyCapture))
1043
1092
  return;
1044
- if (!paneTailContainsLiteralLine(target, text))
1093
+ if (!normalizeTmuxCapture(verifyCapture).includes(normalizeTmuxCapture(text)))
1045
1094
  return;
1046
1095
  // Draft still visible and no active task — one more C-m attempt.
1047
- sendKeyOrThrow(target, 'C-m', 'C-m');
1048
- sleepFractionalSeconds(0.15);
1049
- sendKeyOrThrow(target, 'C-m', 'C-m');
1096
+ await sendKeyAsync(target, 'C-m');
1097
+ await sleep(150);
1098
+ await sendKeyAsync(target, 'C-m');
1050
1099
  }
1051
1100
  }
1052
1101
  export function notifyLeaderStatus(sessionName, message) {
@@ -1104,18 +1153,18 @@ export function isWorkerAlive(sessionName, workerIndex, workerPaneId) {
1104
1153
  }
1105
1154
  // Kill a specific worker: send C-c, then C-d, then kill-pane if still alive.
1106
1155
  // leaderPaneId: when provided, the kill is skipped entirely if workerPaneId matches it.
1107
- export function killWorker(sessionName, workerIndex, workerPaneId, leaderPaneId) {
1156
+ export async function killWorker(sessionName, workerIndex, workerPaneId, leaderPaneId) {
1108
1157
  // Guard: never kill the leader's own pane.
1109
1158
  if (leaderPaneId && workerPaneId === leaderPaneId)
1110
1159
  return;
1111
- runTmux(['send-keys', '-t', paneTarget(sessionName, workerIndex, workerPaneId), 'C-c']);
1112
- sleepSeconds(1);
1113
- if (isWorkerAlive(sessionName, workerIndex, workerPaneId)) {
1114
- runTmux(['send-keys', '-t', paneTarget(sessionName, workerIndex, workerPaneId), 'C-d']);
1115
- sleepSeconds(1);
1160
+ await runTmuxAsync(['send-keys', '-t', paneTarget(sessionName, workerIndex, workerPaneId), 'C-c']);
1161
+ await sleep(1000);
1162
+ if (await isWorkerAliveAsync(sessionName, workerIndex, workerPaneId)) {
1163
+ await runTmuxAsync(['send-keys', '-t', paneTarget(sessionName, workerIndex, workerPaneId), 'C-d']);
1164
+ await sleep(1000);
1116
1165
  }
1117
- if (isWorkerAlive(sessionName, workerIndex, workerPaneId)) {
1118
- runTmux(['kill-pane', '-t', paneTarget(sessionName, workerIndex, workerPaneId)]);
1166
+ if (await isWorkerAliveAsync(sessionName, workerIndex, workerPaneId)) {
1167
+ await runTmuxAsync(['kill-pane', '-t', paneTarget(sessionName, workerIndex, workerPaneId)]);
1119
1168
  }
1120
1169
  }
1121
1170
  // leaderPaneId: when provided, the kill is skipped if workerPaneId matches it.
@@ -1127,6 +1176,81 @@ export function killWorkerByPaneId(workerPaneId, leaderPaneId) {
1127
1176
  return;
1128
1177
  runTmux(['kill-pane', '-t', workerPaneId]);
1129
1178
  }
1179
+ export async function killWorkerByPaneIdAsync(workerPaneId, leaderPaneId) {
1180
+ if (!workerPaneId.startsWith('%'))
1181
+ return;
1182
+ // Guard: never kill the leader's own pane.
1183
+ if (leaderPaneId && workerPaneId === leaderPaneId)
1184
+ return;
1185
+ await runTmuxAsync(['kill-pane', '-t', workerPaneId]);
1186
+ }
1187
+ function normalizePaneTarget(value) {
1188
+ if (typeof value !== 'string')
1189
+ return null;
1190
+ const trimmed = value.trim();
1191
+ if (!trimmed.startsWith('%'))
1192
+ return null;
1193
+ return trimmed;
1194
+ }
1195
+ function normalizePaneTargets(paneIds, options = {}) {
1196
+ const leaderPaneId = normalizePaneTarget(options.leaderPaneId);
1197
+ const hudPaneId = normalizePaneTarget(options.hudPaneId);
1198
+ const excluded = { leader: 0, hud: 0, invalid: 0 };
1199
+ const deduped = new Set();
1200
+ const killablePaneIds = [];
1201
+ for (const paneId of paneIds) {
1202
+ const normalized = normalizePaneTarget(paneId);
1203
+ if (!normalized) {
1204
+ excluded.invalid += 1;
1205
+ continue;
1206
+ }
1207
+ if (leaderPaneId && normalized === leaderPaneId) {
1208
+ excluded.leader += 1;
1209
+ continue;
1210
+ }
1211
+ if (hudPaneId && normalized === hudPaneId) {
1212
+ excluded.hud += 1;
1213
+ continue;
1214
+ }
1215
+ if (deduped.has(normalized))
1216
+ continue;
1217
+ deduped.add(normalized);
1218
+ killablePaneIds.push(normalized);
1219
+ }
1220
+ return { killablePaneIds, excluded };
1221
+ }
1222
+ /**
1223
+ * Shared pane-id-direct teardown primitive for worker pane cleanup.
1224
+ * Must remain liveness-agnostic: do not gate on isWorkerAlive/killWorker.
1225
+ */
1226
+ export async function teardownWorkerPanes(paneIds, options = {}) {
1227
+ const { killablePaneIds, excluded } = normalizePaneTargets(paneIds, options);
1228
+ const graceMs = options.graceMs ?? 2000;
1229
+ const perPaneGrace = killablePaneIds.length > 0
1230
+ ? Math.max(100, Math.floor(graceMs / killablePaneIds.length))
1231
+ : 0;
1232
+ const summary = {
1233
+ attemptedPaneIds: killablePaneIds,
1234
+ excluded,
1235
+ kill: {
1236
+ attempted: killablePaneIds.length,
1237
+ succeeded: 0,
1238
+ failed: 0,
1239
+ },
1240
+ };
1241
+ for (const paneId of killablePaneIds) {
1242
+ const result = await runTmuxAsync(['kill-pane', '-t', paneId]);
1243
+ if (result.ok)
1244
+ summary.kill.succeeded += 1;
1245
+ else
1246
+ summary.kill.failed += 1;
1247
+ await sleep(perPaneGrace);
1248
+ }
1249
+ return summary;
1250
+ }
1251
+ export async function killWorkerPanes(paneIds, leaderPaneId, graceMs = 2000, hudPaneId) {
1252
+ return teardownWorkerPanes(paneIds, { leaderPaneId, hudPaneId: hudPaneId ?? null, graceMs });
1253
+ }
1130
1254
  // Kill entire tmux session. Tolerates already-dead sessions.
1131
1255
  export function destroyTeamSession(sessionName) {
1132
1256
  try {
@@ -1147,4 +1271,35 @@ export function listTeamSessions() {
1147
1271
  .filter(Boolean)
1148
1272
  .map(baseSessionName);
1149
1273
  }
1274
+ /**
1275
+ * Send a trigger message directly to the leader pane via tmux send-keys.
1276
+ * Used as the direct-inject fallback when hook-based dispatch to the leader
1277
+ * times out. Unlike notifyLeaderMailboxAsync (which only writes to the
1278
+ * mailbox file), this actually injects text into the leader's tmux pane
1279
+ * so the leader sees it immediately. Fixes #437.
1280
+ */
1281
+ export async function sendToLeaderPane(leaderPaneId, text) {
1282
+ const send = runTmux(['send-keys', '-t', leaderPaneId, '-l', '--', text]);
1283
+ if (!send.ok) {
1284
+ throw new Error(`sendToLeaderPane: failed to send text: ${send.stderr}`);
1285
+ }
1286
+ await sleep(150);
1287
+ await sendKeyAsync(leaderPaneId, 'C-m');
1288
+ await sleep(100);
1289
+ await sendKeyAsync(leaderPaneId, 'C-m');
1290
+ }
1291
+ /**
1292
+ * Notify the leader via mailbox instead of tmux display-message.
1293
+ * This is the async mailbox-based replacement for notifyLeaderStatus.
1294
+ */
1295
+ export async function notifyLeaderMailboxAsync(teamName, fromWorker, message, cwd) {
1296
+ try {
1297
+ const { sendDirectMessage } = await import('./state.js');
1298
+ await sendDirectMessage(teamName, fromWorker, 'leader-fixed', message, cwd);
1299
+ return true;
1300
+ }
1301
+ catch {
1302
+ return false;
1303
+ }
1304
+ }
1150
1305
  //# sourceMappingURL=tmux-session.js.map