claudecode-omc 4.4.10 → 4.7.4

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 (1091) hide show
  1. package/.claude-plugin/marketplace.json +18 -4
  2. package/.claude-plugin/plugin.json +14 -1
  3. package/.mcp.json +0 -4
  4. package/README.de.md +260 -0
  5. package/README.es.md +27 -41
  6. package/README.fr.md +260 -0
  7. package/README.it.md +260 -0
  8. package/README.ja.md +27 -41
  9. package/README.ko.md +45 -54
  10. package/README.md +247 -14
  11. package/README.pt.md +23 -6
  12. package/README.ru.md +260 -0
  13. package/README.tr.md +260 -0
  14. package/README.vi.md +23 -6
  15. package/README.zh.md +27 -41
  16. package/agents/harsh-critic.md +254 -0
  17. package/bridge/cli.cjs +67181 -0
  18. package/bridge/gyoshu_bridge.py +69 -19
  19. package/bridge/mcp-server.cjs +846 -526
  20. package/bridge/runtime-cli.cjs +2861 -367
  21. package/bridge/team-bridge.cjs +216 -60
  22. package/bridge/team-mcp.cjs +493 -255
  23. package/bridge/team.js +1460 -0
  24. package/dist/__tests__/agent-registry.test.js +13 -3
  25. package/dist/__tests__/agent-registry.test.js.map +1 -1
  26. package/dist/__tests__/auto-slash-aliases.test.js +12 -20
  27. package/dist/__tests__/auto-slash-aliases.test.js.map +1 -1
  28. package/dist/__tests__/auto-update.test.js +1 -1
  29. package/dist/__tests__/auto-update.test.js.map +1 -1
  30. package/dist/__tests__/bash-history.test.js.map +1 -1
  31. package/dist/__tests__/cleanup-validation.test.d.ts +2 -0
  32. package/dist/__tests__/cleanup-validation.test.d.ts.map +1 -0
  33. package/dist/__tests__/cleanup-validation.test.js +44 -0
  34. package/dist/__tests__/cleanup-validation.test.js.map +1 -0
  35. package/dist/__tests__/config-force-inherit-env.test.d.ts +5 -0
  36. package/dist/__tests__/config-force-inherit-env.test.d.ts.map +1 -0
  37. package/dist/__tests__/config-force-inherit-env.test.js +35 -0
  38. package/dist/__tests__/config-force-inherit-env.test.js.map +1 -0
  39. package/dist/__tests__/consolidation-contracts.test.js +4 -7
  40. package/dist/__tests__/consolidation-contracts.test.js.map +1 -1
  41. package/dist/__tests__/daemon-module-path.test.d.ts +2 -0
  42. package/dist/__tests__/daemon-module-path.test.d.ts.map +1 -0
  43. package/dist/__tests__/daemon-module-path.test.js +29 -0
  44. package/dist/__tests__/daemon-module-path.test.js.map +1 -0
  45. package/dist/__tests__/delegation-enforcement-levels.test.js.map +1 -1
  46. package/dist/__tests__/delegation-enforcer.test.js +172 -0
  47. package/dist/__tests__/delegation-enforcer.test.js.map +1 -1
  48. package/dist/__tests__/doctor-conflicts.test.js +144 -1
  49. package/dist/__tests__/doctor-conflicts.test.js.map +1 -1
  50. package/dist/__tests__/file-lock.test.d.ts +2 -0
  51. package/dist/__tests__/file-lock.test.d.ts.map +1 -0
  52. package/dist/__tests__/file-lock.test.js +209 -0
  53. package/dist/__tests__/file-lock.test.js.map +1 -0
  54. package/dist/__tests__/hooks.test.js +27 -56
  55. package/dist/__tests__/hooks.test.js.map +1 -1
  56. package/dist/__tests__/hud/defaults.test.js +3 -0
  57. package/dist/__tests__/hud/defaults.test.js.map +1 -1
  58. package/dist/__tests__/hud/limits-error.test.d.ts +5 -0
  59. package/dist/__tests__/hud/limits-error.test.d.ts.map +1 -0
  60. package/dist/__tests__/hud/limits-error.test.js +43 -0
  61. package/dist/__tests__/hud/limits-error.test.js.map +1 -0
  62. package/dist/__tests__/hud/max-width.test.d.ts +2 -0
  63. package/dist/__tests__/hud/max-width.test.d.ts.map +1 -0
  64. package/dist/__tests__/hud/max-width.test.js +149 -0
  65. package/dist/__tests__/hud/max-width.test.js.map +1 -0
  66. package/dist/__tests__/hud/rate-limits-error.test.d.ts +5 -0
  67. package/dist/__tests__/hud/rate-limits-error.test.d.ts.map +1 -0
  68. package/dist/__tests__/hud/rate-limits-error.test.js +76 -0
  69. package/dist/__tests__/hud/rate-limits-error.test.js.map +1 -0
  70. package/dist/__tests__/hud/render.test.js +245 -1
  71. package/dist/__tests__/hud/render.test.js.map +1 -1
  72. package/dist/__tests__/hud/state.test.js +15 -0
  73. package/dist/__tests__/hud/state.test.js.map +1 -1
  74. package/dist/__tests__/hud/usage-api.test.js +19 -5
  75. package/dist/__tests__/hud/usage-api.test.js.map +1 -1
  76. package/dist/__tests__/hud/version-display.test.js +3 -1
  77. package/dist/__tests__/hud/version-display.test.js.map +1 -1
  78. package/dist/__tests__/hud-agents.test.js.map +1 -1
  79. package/dist/__tests__/hud-api-key-source.test.d.ts +7 -0
  80. package/dist/__tests__/hud-api-key-source.test.d.ts.map +1 -0
  81. package/dist/__tests__/hud-api-key-source.test.js +112 -0
  82. package/dist/__tests__/hud-api-key-source.test.js.map +1 -0
  83. package/dist/__tests__/hud-build-guidance.test.d.ts +2 -0
  84. package/dist/__tests__/hud-build-guidance.test.d.ts.map +1 -0
  85. package/dist/__tests__/hud-build-guidance.test.js +26 -0
  86. package/dist/__tests__/hud-build-guidance.test.js.map +1 -0
  87. package/dist/__tests__/installer-hooks-merge.test.js +1 -1
  88. package/dist/__tests__/installer-hooks-merge.test.js.map +1 -1
  89. package/dist/__tests__/installer.test.js +4 -0
  90. package/dist/__tests__/installer.test.js.map +1 -1
  91. package/dist/__tests__/job-management.test.js +1 -1
  92. package/dist/__tests__/job-management.test.js.map +1 -1
  93. package/dist/__tests__/live-data.test.js +11 -5
  94. package/dist/__tests__/live-data.test.js.map +1 -1
  95. package/dist/__tests__/mcp-default-config.test.d.ts +2 -0
  96. package/dist/__tests__/mcp-default-config.test.d.ts.map +1 -0
  97. package/dist/__tests__/mcp-default-config.test.js +13 -0
  98. package/dist/__tests__/mcp-default-config.test.js.map +1 -0
  99. package/dist/__tests__/model-routing.test.js.map +1 -1
  100. package/dist/__tests__/non-claude-provider-detection.test.d.ts +11 -0
  101. package/dist/__tests__/non-claude-provider-detection.test.d.ts.map +1 -0
  102. package/dist/__tests__/non-claude-provider-detection.test.js +303 -0
  103. package/dist/__tests__/non-claude-provider-detection.test.js.map +1 -0
  104. package/dist/__tests__/omc-tools-server.test.js +5 -5
  105. package/dist/__tests__/package-dir-resolution-regression.test.d.ts +2 -0
  106. package/dist/__tests__/package-dir-resolution-regression.test.d.ts.map +1 -0
  107. package/dist/__tests__/package-dir-resolution-regression.test.js +63 -0
  108. package/dist/__tests__/package-dir-resolution-regression.test.js.map +1 -0
  109. package/dist/__tests__/pipeline-orchestrator.test.d.ts +5 -0
  110. package/dist/__tests__/pipeline-orchestrator.test.d.ts.map +1 -0
  111. package/dist/__tests__/pipeline-orchestrator.test.js +244 -0
  112. package/dist/__tests__/pipeline-orchestrator.test.js.map +1 -0
  113. package/dist/__tests__/plugin-setup-deps.test.d.ts +2 -0
  114. package/dist/__tests__/plugin-setup-deps.test.d.ts.map +1 -0
  115. package/dist/__tests__/plugin-setup-deps.test.js +64 -0
  116. package/dist/__tests__/plugin-setup-deps.test.js.map +1 -0
  117. package/dist/__tests__/pre-tool-agent-prefix.test.d.ts +8 -0
  118. package/dist/__tests__/pre-tool-agent-prefix.test.d.ts.map +1 -0
  119. package/dist/__tests__/pre-tool-agent-prefix.test.js +131 -0
  120. package/dist/__tests__/pre-tool-agent-prefix.test.js.map +1 -0
  121. package/dist/__tests__/project-memory-merge.test.d.ts +2 -0
  122. package/dist/__tests__/project-memory-merge.test.d.ts.map +1 -0
  123. package/dist/__tests__/project-memory-merge.test.js +342 -0
  124. package/dist/__tests__/project-memory-merge.test.js.map +1 -0
  125. package/dist/__tests__/ralph-prd-mandatory.test.d.ts +2 -0
  126. package/dist/__tests__/ralph-prd-mandatory.test.d.ts.map +1 -0
  127. package/dist/__tests__/ralph-prd-mandatory.test.js +316 -0
  128. package/dist/__tests__/ralph-prd-mandatory.test.js.map +1 -0
  129. package/dist/__tests__/rate-limit-wait/daemon-bootstrap.test.d.ts +2 -0
  130. package/dist/__tests__/rate-limit-wait/daemon-bootstrap.test.d.ts.map +1 -0
  131. package/dist/__tests__/rate-limit-wait/daemon-bootstrap.test.js +94 -0
  132. package/dist/__tests__/rate-limit-wait/daemon-bootstrap.test.js.map +1 -0
  133. package/dist/__tests__/rate-limit-wait/daemon.test.js.map +1 -1
  134. package/dist/__tests__/rate-limit-wait/integration.test.js +33 -25
  135. package/dist/__tests__/rate-limit-wait/integration.test.js.map +1 -1
  136. package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.js +34 -26
  137. package/dist/__tests__/rate-limit-wait/rate-limit-monitor.test.js.map +1 -1
  138. package/dist/__tests__/rate-limit-wait/tmux-detector.test.js.map +1 -1
  139. package/dist/__tests__/resolve-node.test.js.map +1 -1
  140. package/dist/__tests__/resolve-transcript-path.test.d.ts +12 -0
  141. package/dist/__tests__/resolve-transcript-path.test.d.ts.map +1 -0
  142. package/dist/__tests__/resolve-transcript-path.test.js +167 -0
  143. package/dist/__tests__/resolve-transcript-path.test.js.map +1 -0
  144. package/dist/__tests__/routing-force-inherit.test.d.ts +8 -0
  145. package/dist/__tests__/routing-force-inherit.test.d.ts.map +1 -0
  146. package/dist/__tests__/routing-force-inherit.test.js +180 -0
  147. package/dist/__tests__/routing-force-inherit.test.js.map +1 -0
  148. package/dist/__tests__/run-cjs-graceful-fallback.test.js +2 -2
  149. package/dist/__tests__/run-cjs-graceful-fallback.test.js.map +1 -1
  150. package/dist/__tests__/shared-memory-concurrency.test.d.ts +8 -0
  151. package/dist/__tests__/shared-memory-concurrency.test.d.ts.map +1 -0
  152. package/dist/__tests__/shared-memory-concurrency.test.js +132 -0
  153. package/dist/__tests__/shared-memory-concurrency.test.js.map +1 -0
  154. package/dist/__tests__/shared-memory.test.d.ts +2 -0
  155. package/dist/__tests__/shared-memory.test.d.ts.map +1 -0
  156. package/dist/__tests__/shared-memory.test.js +345 -0
  157. package/dist/__tests__/shared-memory.test.js.map +1 -0
  158. package/dist/__tests__/shell-path.test.d.ts +5 -0
  159. package/dist/__tests__/shell-path.test.d.ts.map +1 -0
  160. package/dist/__tests__/shell-path.test.js +70 -0
  161. package/dist/__tests__/shell-path.test.js.map +1 -0
  162. package/dist/__tests__/skills.test.js +13 -10
  163. package/dist/__tests__/skills.test.js.map +1 -1
  164. package/dist/__tests__/slack-socket.test.d.ts +5 -0
  165. package/dist/__tests__/slack-socket.test.d.ts.map +1 -0
  166. package/dist/__tests__/slack-socket.test.js +252 -0
  167. package/dist/__tests__/slack-socket.test.js.map +1 -0
  168. package/dist/__tests__/smoke-functional.test.d.ts +8 -0
  169. package/dist/__tests__/smoke-functional.test.d.ts.map +1 -0
  170. package/dist/__tests__/smoke-functional.test.js +450 -0
  171. package/dist/__tests__/smoke-functional.test.js.map +1 -0
  172. package/dist/__tests__/smoke-pipeline-edge.test.d.ts +8 -0
  173. package/dist/__tests__/smoke-pipeline-edge.test.d.ts.map +1 -0
  174. package/dist/__tests__/smoke-pipeline-edge.test.js +435 -0
  175. package/dist/__tests__/smoke-pipeline-edge.test.js.map +1 -0
  176. package/dist/__tests__/smoke-slack-and-state.test.d.ts +13 -0
  177. package/dist/__tests__/smoke-slack-and-state.test.d.ts.map +1 -0
  178. package/dist/__tests__/smoke-slack-and-state.test.js +632 -0
  179. package/dist/__tests__/smoke-slack-and-state.test.js.map +1 -0
  180. package/dist/__tests__/smoke-team-worker.test.d.ts +15 -0
  181. package/dist/__tests__/smoke-team-worker.test.d.ts.map +1 -0
  182. package/dist/__tests__/smoke-team-worker.test.js +483 -0
  183. package/dist/__tests__/smoke-team-worker.test.js.map +1 -0
  184. package/dist/__tests__/ssrf-guard.test.d.ts +2 -0
  185. package/dist/__tests__/ssrf-guard.test.d.ts.map +1 -0
  186. package/dist/__tests__/ssrf-guard.test.js +96 -0
  187. package/dist/__tests__/ssrf-guard.test.js.map +1 -0
  188. package/dist/__tests__/task-continuation.test.js +1 -1
  189. package/dist/__tests__/task-continuation.test.js.map +1 -1
  190. package/dist/__tests__/tier0-contracts.test.js +5 -1
  191. package/dist/__tests__/tier0-contracts.test.js.map +1 -1
  192. package/dist/__tests__/tier0-docs-consistency.test.js +3 -4
  193. package/dist/__tests__/tier0-docs-consistency.test.js.map +1 -1
  194. package/dist/__tests__/tools/trace-tools.test.js +7 -3
  195. package/dist/__tests__/tools/trace-tools.test.js.map +1 -1
  196. package/dist/__tests__/types.test.js +4 -4
  197. package/dist/__tests__/types.test.js.map +1 -1
  198. package/dist/__tests__/worker-adapter.test.d.ts +5 -0
  199. package/dist/__tests__/worker-adapter.test.d.ts.map +1 -0
  200. package/dist/__tests__/worker-adapter.test.js +211 -0
  201. package/dist/__tests__/worker-adapter.test.js.map +1 -0
  202. package/dist/agents/definitions.d.ts +6 -5
  203. package/dist/agents/definitions.d.ts.map +1 -1
  204. package/dist/agents/definitions.js +11 -6
  205. package/dist/agents/definitions.js.map +1 -1
  206. package/dist/agents/harsh-critic.d.ts +14 -0
  207. package/dist/agents/harsh-critic.d.ts.map +1 -0
  208. package/dist/agents/harsh-critic.js +42 -0
  209. package/dist/agents/harsh-critic.js.map +1 -0
  210. package/dist/agents/index.d.ts +1 -3
  211. package/dist/agents/index.d.ts.map +1 -1
  212. package/dist/agents/index.js +1 -4
  213. package/dist/agents/index.js.map +1 -1
  214. package/dist/agents/prompt-helpers.d.ts.map +1 -1
  215. package/dist/agents/prompt-helpers.js +21 -16
  216. package/dist/agents/prompt-helpers.js.map +1 -1
  217. package/dist/agents/prompt-sections/index.d.ts.map +1 -1
  218. package/dist/agents/prompt-sections/index.js +7 -3
  219. package/dist/agents/prompt-sections/index.js.map +1 -1
  220. package/dist/agents/utils.d.ts.map +1 -1
  221. package/dist/agents/utils.js +22 -13
  222. package/dist/agents/utils.js.map +1 -1
  223. package/dist/cli/__tests__/ask.test.d.ts +2 -0
  224. package/dist/cli/__tests__/ask.test.d.ts.map +1 -0
  225. package/dist/cli/__tests__/ask.test.js +282 -0
  226. package/dist/cli/__tests__/ask.test.js.map +1 -0
  227. package/dist/cli/__tests__/cli-boot.test.d.ts +8 -0
  228. package/dist/cli/__tests__/cli-boot.test.d.ts.map +1 -0
  229. package/dist/cli/__tests__/cli-boot.test.js +82 -0
  230. package/dist/cli/__tests__/cli-boot.test.js.map +1 -0
  231. package/dist/cli/__tests__/launch.test.js +11 -2
  232. package/dist/cli/__tests__/launch.test.js.map +1 -1
  233. package/dist/cli/__tests__/team-command-branding.test.d.ts +2 -0
  234. package/dist/cli/__tests__/team-command-branding.test.d.ts.map +1 -0
  235. package/dist/cli/__tests__/team-command-branding.test.js +14 -0
  236. package/dist/cli/__tests__/team-command-branding.test.js.map +1 -0
  237. package/dist/cli/__tests__/team-help.test.d.ts +2 -0
  238. package/dist/cli/__tests__/team-help.test.d.ts.map +1 -0
  239. package/dist/cli/__tests__/team-help.test.js +19 -0
  240. package/dist/cli/__tests__/team-help.test.js.map +1 -0
  241. package/dist/cli/__tests__/team-runtime-boundary.test.d.ts +2 -0
  242. package/dist/cli/__tests__/team-runtime-boundary.test.d.ts.map +1 -0
  243. package/dist/cli/__tests__/team-runtime-boundary.test.js +11 -0
  244. package/dist/cli/__tests__/team-runtime-boundary.test.js.map +1 -0
  245. package/dist/cli/__tests__/team.test.d.ts +2 -0
  246. package/dist/cli/__tests__/team.test.d.ts.map +1 -0
  247. package/dist/cli/__tests__/team.test.js +335 -0
  248. package/dist/cli/__tests__/team.test.js.map +1 -0
  249. package/dist/cli/__tests__/tmux-utils.test.d.ts +11 -0
  250. package/dist/cli/__tests__/tmux-utils.test.d.ts.map +1 -0
  251. package/dist/cli/__tests__/tmux-utils.test.js +145 -0
  252. package/dist/cli/__tests__/tmux-utils.test.js.map +1 -0
  253. package/dist/cli/ask.d.ts +13 -0
  254. package/dist/cli/ask.d.ts.map +1 -0
  255. package/dist/cli/ask.js +202 -0
  256. package/dist/cli/ask.js.map +1 -0
  257. package/dist/cli/commands/__tests__/team.test.d.ts +2 -0
  258. package/dist/cli/commands/__tests__/team.test.d.ts.map +1 -0
  259. package/dist/cli/commands/__tests__/team.test.js +177 -0
  260. package/dist/cli/commands/__tests__/team.test.js.map +1 -0
  261. package/dist/cli/commands/__tests__/teleport.test.js.map +1 -1
  262. package/dist/cli/commands/doctor-conflicts.d.ts +14 -1
  263. package/dist/cli/commands/doctor-conflicts.d.ts.map +1 -1
  264. package/dist/cli/commands/doctor-conflicts.js +126 -12
  265. package/dist/cli/commands/doctor-conflicts.js.map +1 -1
  266. package/dist/cli/commands/team.d.ts +19 -0
  267. package/dist/cli/commands/team.d.ts.map +1 -0
  268. package/dist/cli/commands/team.js +510 -0
  269. package/dist/cli/commands/team.js.map +1 -0
  270. package/dist/cli/commands/teleport.d.ts.map +1 -1
  271. package/dist/cli/commands/teleport.js +6 -4
  272. package/dist/cli/commands/teleport.js.map +1 -1
  273. package/dist/cli/index.js +58 -17
  274. package/dist/cli/index.js.map +1 -1
  275. package/dist/cli/launch.d.ts.map +1 -1
  276. package/dist/cli/launch.js +12 -6
  277. package/dist/cli/launch.js.map +1 -1
  278. package/dist/cli/team.d.ts +76 -0
  279. package/dist/cli/team.d.ts.map +1 -0
  280. package/dist/cli/team.js +1117 -0
  281. package/dist/cli/team.js.map +1 -0
  282. package/dist/cli/tmux-utils.d.ts +10 -0
  283. package/dist/cli/tmux-utils.d.ts.map +1 -1
  284. package/dist/cli/tmux-utils.js +20 -1
  285. package/dist/cli/tmux-utils.js.map +1 -1
  286. package/dist/config/loader.d.ts.map +1 -1
  287. package/dist/config/loader.js +134 -48
  288. package/dist/config/loader.js.map +1 -1
  289. package/dist/config/models.d.ts +36 -14
  290. package/dist/config/models.d.ts.map +1 -1
  291. package/dist/config/models.js +94 -0
  292. package/dist/config/models.js.map +1 -1
  293. package/dist/constants/names.d.ts +6 -3
  294. package/dist/constants/names.d.ts.map +1 -1
  295. package/dist/constants/names.js +7 -3
  296. package/dist/constants/names.js.map +1 -1
  297. package/dist/features/auto-update.js +5 -5
  298. package/dist/features/auto-update.js.map +1 -1
  299. package/dist/features/boulder-state/storage.d.ts +1 -1
  300. package/dist/features/boulder-state/storage.d.ts.map +1 -1
  301. package/dist/features/boulder-state/storage.js +20 -22
  302. package/dist/features/boulder-state/storage.js.map +1 -1
  303. package/dist/features/delegation-enforcer.d.ts +5 -0
  304. package/dist/features/delegation-enforcer.d.ts.map +1 -1
  305. package/dist/features/delegation-enforcer.js +58 -5
  306. package/dist/features/delegation-enforcer.js.map +1 -1
  307. package/dist/features/model-routing/router.d.ts.map +1 -1
  308. package/dist/features/model-routing/router.js +11 -0
  309. package/dist/features/model-routing/router.js.map +1 -1
  310. package/dist/features/model-routing/types.d.ts +6 -0
  311. package/dist/features/model-routing/types.d.ts.map +1 -1
  312. package/dist/features/model-routing/types.js.map +1 -1
  313. package/dist/features/rate-limit-wait/daemon.d.ts +5 -0
  314. package/dist/features/rate-limit-wait/daemon.d.ts.map +1 -1
  315. package/dist/features/rate-limit-wait/daemon.js +38 -9
  316. package/dist/features/rate-limit-wait/daemon.js.map +1 -1
  317. package/dist/features/rate-limit-wait/rate-limit-monitor.d.ts.map +1 -1
  318. package/dist/features/rate-limit-wait/rate-limit-monitor.js +3 -2
  319. package/dist/features/rate-limit-wait/rate-limit-monitor.js.map +1 -1
  320. package/dist/features/rate-limit-wait/tmux-detector.d.ts.map +1 -1
  321. package/dist/features/rate-limit-wait/tmux-detector.js +8 -2
  322. package/dist/features/rate-limit-wait/tmux-detector.js.map +1 -1
  323. package/dist/features/state-manager/__tests__/cache.test.js +161 -1
  324. package/dist/features/state-manager/__tests__/cache.test.js.map +1 -1
  325. package/dist/features/state-manager/index.d.ts +2 -0
  326. package/dist/features/state-manager/index.d.ts.map +1 -1
  327. package/dist/features/state-manager/index.js +167 -51
  328. package/dist/features/state-manager/index.js.map +1 -1
  329. package/dist/hooks/__tests__/bridge-routing.test.js +124 -1
  330. package/dist/hooks/__tests__/bridge-routing.test.js.map +1 -1
  331. package/dist/hooks/__tests__/bridge-security.test.js +1 -1
  332. package/dist/hooks/__tests__/bridge-security.test.js.map +1 -1
  333. package/dist/hooks/__tests__/bridge-team-worker-guard.test.d.ts +2 -0
  334. package/dist/hooks/__tests__/bridge-team-worker-guard.test.d.ts.map +1 -0
  335. package/dist/hooks/__tests__/bridge-team-worker-guard.test.js +52 -0
  336. package/dist/hooks/__tests__/bridge-team-worker-guard.test.js.map +1 -0
  337. package/dist/hooks/__tests__/bridge.test.js.map +1 -1
  338. package/dist/hooks/__tests__/codebase-map.test.js.map +1 -1
  339. package/dist/hooks/__tests__/compaction-concurrency.test.js.map +1 -1
  340. package/dist/hooks/__tests__/stop-hook-openclaw-cooldown.test.d.ts +2 -0
  341. package/dist/hooks/__tests__/stop-hook-openclaw-cooldown.test.d.ts.map +1 -0
  342. package/dist/hooks/__tests__/stop-hook-openclaw-cooldown.test.js +65 -0
  343. package/dist/hooks/__tests__/stop-hook-openclaw-cooldown.test.js.map +1 -0
  344. package/dist/hooks/auto-slash-command/live-data.d.ts.map +1 -1
  345. package/dist/hooks/auto-slash-command/live-data.js +54 -25
  346. package/dist/hooks/auto-slash-command/live-data.js.map +1 -1
  347. package/dist/hooks/autopilot/__tests__/cancel.test.js +1 -1
  348. package/dist/hooks/autopilot/__tests__/cancel.test.js.map +1 -1
  349. package/dist/hooks/autopilot/__tests__/pipeline.test.d.ts +2 -0
  350. package/dist/hooks/autopilot/__tests__/pipeline.test.d.ts.map +1 -0
  351. package/dist/hooks/autopilot/__tests__/pipeline.test.js +375 -0
  352. package/dist/hooks/autopilot/__tests__/pipeline.test.js.map +1 -0
  353. package/dist/hooks/autopilot/__tests__/state.test.js +2 -2
  354. package/dist/hooks/autopilot/__tests__/state.test.js.map +1 -1
  355. package/dist/hooks/autopilot/__tests__/summary.test.js.map +1 -1
  356. package/dist/hooks/autopilot/__tests__/transition.test.js.map +1 -1
  357. package/dist/hooks/autopilot/__tests__/validation.test.js +3 -3
  358. package/dist/hooks/autopilot/__tests__/validation.test.js.map +1 -1
  359. package/dist/hooks/autopilot/adapters/execution-adapter.d.ts +12 -0
  360. package/dist/hooks/autopilot/adapters/execution-adapter.d.ts.map +1 -0
  361. package/dist/hooks/autopilot/adapters/execution-adapter.js +110 -0
  362. package/dist/hooks/autopilot/adapters/execution-adapter.js.map +1 -0
  363. package/dist/hooks/autopilot/adapters/index.d.ts +22 -0
  364. package/dist/hooks/autopilot/adapters/index.d.ts.map +1 -0
  365. package/dist/hooks/autopilot/adapters/index.js +32 -0
  366. package/dist/hooks/autopilot/adapters/index.js.map +1 -0
  367. package/dist/hooks/autopilot/adapters/qa-adapter.d.ts +12 -0
  368. package/dist/hooks/autopilot/adapters/qa-adapter.d.ts.map +1 -0
  369. package/dist/hooks/autopilot/adapters/qa-adapter.js +33 -0
  370. package/dist/hooks/autopilot/adapters/qa-adapter.js.map +1 -0
  371. package/dist/hooks/autopilot/adapters/ralph-adapter.d.ts +15 -0
  372. package/dist/hooks/autopilot/adapters/ralph-adapter.d.ts.map +1 -0
  373. package/dist/hooks/autopilot/adapters/ralph-adapter.js +102 -0
  374. package/dist/hooks/autopilot/adapters/ralph-adapter.js.map +1 -0
  375. package/dist/hooks/autopilot/adapters/ralplan-adapter.d.ts +14 -0
  376. package/dist/hooks/autopilot/adapters/ralplan-adapter.d.ts.map +1 -0
  377. package/dist/hooks/autopilot/adapters/ralplan-adapter.js +81 -0
  378. package/dist/hooks/autopilot/adapters/ralplan-adapter.js.map +1 -0
  379. package/dist/hooks/autopilot/enforcement.d.ts.map +1 -1
  380. package/dist/hooks/autopilot/enforcement.js +162 -0
  381. package/dist/hooks/autopilot/enforcement.js.map +1 -1
  382. package/dist/hooks/autopilot/index.d.ts +4 -0
  383. package/dist/hooks/autopilot/index.d.ts.map +1 -1
  384. package/dist/hooks/autopilot/index.js +5 -0
  385. package/dist/hooks/autopilot/index.js.map +1 -1
  386. package/dist/hooks/autopilot/pipeline-types.d.ts +133 -0
  387. package/dist/hooks/autopilot/pipeline-types.d.ts.map +1 -0
  388. package/dist/hooks/autopilot/pipeline-types.js +44 -0
  389. package/dist/hooks/autopilot/pipeline-types.js.map +1 -0
  390. package/dist/hooks/autopilot/pipeline.d.ts +124 -0
  391. package/dist/hooks/autopilot/pipeline.d.ts.map +1 -0
  392. package/dist/hooks/autopilot/pipeline.js +407 -0
  393. package/dist/hooks/autopilot/pipeline.js.map +1 -0
  394. package/dist/hooks/autopilot/state.d.ts +6 -6
  395. package/dist/hooks/autopilot/state.d.ts.map +1 -1
  396. package/dist/hooks/autopilot/state.js +71 -129
  397. package/dist/hooks/autopilot/state.js.map +1 -1
  398. package/dist/hooks/autopilot/types.d.ts +21 -0
  399. package/dist/hooks/autopilot/types.d.ts.map +1 -1
  400. package/dist/hooks/autopilot/types.js.map +1 -1
  401. package/dist/hooks/bridge-normalize.d.ts.map +1 -1
  402. package/dist/hooks/bridge-normalize.js +13 -2
  403. package/dist/hooks/bridge-normalize.js.map +1 -1
  404. package/dist/hooks/bridge.d.ts.map +1 -1
  405. package/dist/hooks/bridge.js +151 -27
  406. package/dist/hooks/bridge.js.map +1 -1
  407. package/dist/hooks/comment-checker/index.js +1 -1
  408. package/dist/hooks/comment-checker/index.js.map +1 -1
  409. package/dist/hooks/empty-message-sanitizer/__tests__/index.test.js +2 -2
  410. package/dist/hooks/empty-message-sanitizer/__tests__/index.test.js.map +1 -1
  411. package/dist/hooks/factcheck/__tests__/factcheck.test.d.ts +7 -0
  412. package/dist/hooks/factcheck/__tests__/factcheck.test.d.ts.map +1 -0
  413. package/dist/hooks/factcheck/__tests__/factcheck.test.js +153 -0
  414. package/dist/hooks/factcheck/__tests__/factcheck.test.js.map +1 -0
  415. package/dist/hooks/factcheck/__tests__/sentinel-gate.test.d.ts +5 -0
  416. package/dist/hooks/factcheck/__tests__/sentinel-gate.test.d.ts.map +1 -0
  417. package/dist/hooks/factcheck/__tests__/sentinel-gate.test.js +159 -0
  418. package/dist/hooks/factcheck/__tests__/sentinel-gate.test.js.map +1 -0
  419. package/dist/hooks/factcheck/__tests__/sentinel.test.d.ts +7 -0
  420. package/dist/hooks/factcheck/__tests__/sentinel.test.d.ts.map +1 -0
  421. package/dist/hooks/factcheck/__tests__/sentinel.test.js +117 -0
  422. package/dist/hooks/factcheck/__tests__/sentinel.test.js.map +1 -0
  423. package/dist/hooks/factcheck/checks.d.ts +36 -0
  424. package/dist/hooks/factcheck/checks.d.ts.map +1 -0
  425. package/dist/hooks/factcheck/checks.js +144 -0
  426. package/dist/hooks/factcheck/checks.js.map +1 -0
  427. package/dist/hooks/factcheck/config.d.ts +25 -0
  428. package/dist/hooks/factcheck/config.d.ts.map +1 -0
  429. package/dist/hooks/factcheck/config.js +125 -0
  430. package/dist/hooks/factcheck/config.js.map +1 -0
  431. package/dist/hooks/factcheck/index.d.ts +34 -0
  432. package/dist/hooks/factcheck/index.d.ts.map +1 -0
  433. package/dist/hooks/factcheck/index.js +120 -0
  434. package/dist/hooks/factcheck/index.js.map +1 -0
  435. package/dist/hooks/factcheck/sentinel.d.ts +32 -0
  436. package/dist/hooks/factcheck/sentinel.d.ts.map +1 -0
  437. package/dist/hooks/factcheck/sentinel.js +153 -0
  438. package/dist/hooks/factcheck/sentinel.js.map +1 -0
  439. package/dist/hooks/factcheck/types.d.ts +99 -0
  440. package/dist/hooks/factcheck/types.d.ts.map +1 -0
  441. package/dist/hooks/factcheck/types.js +27 -0
  442. package/dist/hooks/factcheck/types.js.map +1 -0
  443. package/dist/hooks/keyword-detector/__tests__/index.test.js +29 -80
  444. package/dist/hooks/keyword-detector/__tests__/index.test.js.map +1 -1
  445. package/dist/hooks/keyword-detector/index.d.ts +1 -1
  446. package/dist/hooks/keyword-detector/index.d.ts.map +1 -1
  447. package/dist/hooks/keyword-detector/index.js +11 -21
  448. package/dist/hooks/keyword-detector/index.js.map +1 -1
  449. package/dist/hooks/learner/bridge.d.ts.map +1 -1
  450. package/dist/hooks/learner/bridge.js +8 -0
  451. package/dist/hooks/learner/bridge.js.map +1 -1
  452. package/dist/hooks/learner/index.d.ts +15 -15
  453. package/dist/hooks/learner/index.d.ts.map +1 -1
  454. package/dist/hooks/learner/index.js +44 -38
  455. package/dist/hooks/learner/index.js.map +1 -1
  456. package/dist/hooks/mode-registry/__tests__/session-isolation.test.js +4 -2
  457. package/dist/hooks/mode-registry/__tests__/session-isolation.test.js.map +1 -1
  458. package/dist/hooks/mode-registry/index.d.ts +2 -13
  459. package/dist/hooks/mode-registry/index.d.ts.map +1 -1
  460. package/dist/hooks/mode-registry/index.js +77 -174
  461. package/dist/hooks/mode-registry/index.js.map +1 -1
  462. package/dist/hooks/mode-registry/types.d.ts +1 -1
  463. package/dist/hooks/mode-registry/types.d.ts.map +1 -1
  464. package/dist/hooks/notepad/index.d.ts.map +1 -1
  465. package/dist/hooks/notepad/index.js +83 -73
  466. package/dist/hooks/notepad/index.js.map +1 -1
  467. package/dist/hooks/omc-orchestrator/index.d.ts.map +1 -1
  468. package/dist/hooks/omc-orchestrator/index.js +2 -1
  469. package/dist/hooks/omc-orchestrator/index.js.map +1 -1
  470. package/dist/hooks/permission-handler/__tests__/index.test.js +2 -2
  471. package/dist/hooks/permission-handler/__tests__/index.test.js.map +1 -1
  472. package/dist/hooks/permission-handler/index.d.ts +1 -1
  473. package/dist/hooks/permission-handler/index.d.ts.map +1 -1
  474. package/dist/hooks/permission-handler/index.js +4 -8
  475. package/dist/hooks/permission-handler/index.js.map +1 -1
  476. package/dist/hooks/persistent-mode/__tests__/rate-limit-stop.test.js +23 -0
  477. package/dist/hooks/persistent-mode/__tests__/rate-limit-stop.test.js.map +1 -1
  478. package/dist/hooks/persistent-mode/__tests__/skill-state-stop.test.js.map +1 -1
  479. package/dist/hooks/persistent-mode/__tests__/tool-error.test.js +1 -1
  480. package/dist/hooks/persistent-mode/__tests__/tool-error.test.js.map +1 -1
  481. package/dist/hooks/persistent-mode/index.d.ts +3 -3
  482. package/dist/hooks/persistent-mode/index.d.ts.map +1 -1
  483. package/dist/hooks/persistent-mode/index.js +25 -12
  484. package/dist/hooks/persistent-mode/index.js.map +1 -1
  485. package/dist/hooks/persistent-mode/session-isolation.test.js +20 -4
  486. package/dist/hooks/persistent-mode/session-isolation.test.js.map +1 -1
  487. package/dist/hooks/persistent-mode/stop-hook-blocking.test.d.ts +2 -0
  488. package/dist/hooks/persistent-mode/stop-hook-blocking.test.d.ts.map +1 -0
  489. package/dist/hooks/persistent-mode/stop-hook-blocking.test.js +367 -0
  490. package/dist/hooks/persistent-mode/stop-hook-blocking.test.js.map +1 -0
  491. package/dist/hooks/pre-compact/index.d.ts +2 -14
  492. package/dist/hooks/pre-compact/index.d.ts.map +1 -1
  493. package/dist/hooks/pre-compact/index.js +8 -49
  494. package/dist/hooks/pre-compact/index.js.map +1 -1
  495. package/dist/hooks/preemptive-compaction/index.js +1 -1
  496. package/dist/hooks/preemptive-compaction/index.js.map +1 -1
  497. package/dist/hooks/project-memory/__tests__/integration.test.js +4 -2
  498. package/dist/hooks/project-memory/__tests__/integration.test.js.map +1 -1
  499. package/dist/hooks/project-memory/index.d.ts +9 -9
  500. package/dist/hooks/project-memory/index.d.ts.map +1 -1
  501. package/dist/hooks/project-memory/index.js +25 -25
  502. package/dist/hooks/project-memory/index.js.map +1 -1
  503. package/dist/hooks/project-memory/learner.d.ts.map +1 -1
  504. package/dist/hooks/project-memory/learner.js +92 -86
  505. package/dist/hooks/project-memory/learner.js.map +1 -1
  506. package/dist/hooks/project-memory/storage.d.ts +9 -0
  507. package/dist/hooks/project-memory/storage.d.ts.map +1 -1
  508. package/dist/hooks/project-memory/storage.js +15 -0
  509. package/dist/hooks/project-memory/storage.js.map +1 -1
  510. package/dist/hooks/ralph/index.d.ts +1 -1
  511. package/dist/hooks/ralph/index.d.ts.map +1 -1
  512. package/dist/hooks/ralph/index.js +2 -0
  513. package/dist/hooks/ralph/index.js.map +1 -1
  514. package/dist/hooks/ralph/loop.d.ts +10 -2
  515. package/dist/hooks/ralph/loop.d.ts.map +1 -1
  516. package/dist/hooks/ralph/loop.js +64 -113
  517. package/dist/hooks/ralph/loop.js.map +1 -1
  518. package/dist/hooks/ralph/prd.d.ts.map +1 -1
  519. package/dist/hooks/ralph/prd.js +3 -2
  520. package/dist/hooks/ralph/prd.js.map +1 -1
  521. package/dist/hooks/ralph/progress.d.ts.map +1 -1
  522. package/dist/hooks/ralph/progress.js +6 -5
  523. package/dist/hooks/ralph/progress.js.map +1 -1
  524. package/dist/hooks/ralph/verifier.d.ts +3 -1
  525. package/dist/hooks/ralph/verifier.d.ts.map +1 -1
  526. package/dist/hooks/ralph/verifier.js +19 -7
  527. package/dist/hooks/ralph/verifier.js.map +1 -1
  528. package/dist/hooks/session-end/__tests__/openclaw-session-end.test.d.ts +2 -0
  529. package/dist/hooks/session-end/__tests__/openclaw-session-end.test.d.ts.map +1 -0
  530. package/dist/hooks/session-end/__tests__/openclaw-session-end.test.js +86 -0
  531. package/dist/hooks/session-end/__tests__/openclaw-session-end.test.js.map +1 -0
  532. package/dist/hooks/session-end/index.d.ts.map +1 -1
  533. package/dist/hooks/session-end/index.js +17 -17
  534. package/dist/hooks/session-end/index.js.map +1 -1
  535. package/dist/hooks/setup/index.d.ts.map +1 -1
  536. package/dist/hooks/setup/index.js +0 -2
  537. package/dist/hooks/setup/index.js.map +1 -1
  538. package/dist/hooks/skill-bridge.cjs +13 -4
  539. package/dist/hooks/skill-state/__tests__/skill-state.test.js.map +1 -1
  540. package/dist/hooks/skill-state/index.d.ts +0 -5
  541. package/dist/hooks/skill-state/index.d.ts.map +1 -1
  542. package/dist/hooks/skill-state/index.js +9 -55
  543. package/dist/hooks/skill-state/index.js.map +1 -1
  544. package/dist/hooks/subagent-tracker/__tests__/flush-race.test.js.map +1 -1
  545. package/dist/hooks/subagent-tracker/__tests__/index.test.js.map +1 -1
  546. package/dist/hooks/subagent-tracker/__tests__/session-replay.test.js +1 -1
  547. package/dist/hooks/subagent-tracker/__tests__/session-replay.test.js.map +1 -1
  548. package/dist/hooks/subagent-tracker/index.d.ts.map +1 -1
  549. package/dist/hooks/subagent-tracker/index.js +10 -22
  550. package/dist/hooks/subagent-tracker/index.js.map +1 -1
  551. package/dist/hooks/subagent-tracker/session-replay.d.ts.map +1 -1
  552. package/dist/hooks/subagent-tracker/session-replay.js +3 -2
  553. package/dist/hooks/subagent-tracker/session-replay.js.map +1 -1
  554. package/dist/hooks/task-size-detector/__tests__/index.test.js +7 -7
  555. package/dist/hooks/task-size-detector/__tests__/index.test.js.map +1 -1
  556. package/dist/hooks/task-size-detector/index.d.ts.map +1 -1
  557. package/dist/hooks/task-size-detector/index.js +0 -3
  558. package/dist/hooks/task-size-detector/index.js.map +1 -1
  559. package/dist/hooks/team-dispatch-hook.d.ts +65 -0
  560. package/dist/hooks/team-dispatch-hook.d.ts.map +1 -0
  561. package/dist/hooks/team-dispatch-hook.js +663 -0
  562. package/dist/hooks/team-dispatch-hook.js.map +1 -0
  563. package/dist/hooks/team-leader-nudge-hook.d.ts +36 -0
  564. package/dist/hooks/team-leader-nudge-hook.d.ts.map +1 -0
  565. package/dist/hooks/team-leader-nudge-hook.js +218 -0
  566. package/dist/hooks/team-leader-nudge-hook.js.map +1 -0
  567. package/dist/hooks/team-worker-hook.d.ts +45 -0
  568. package/dist/hooks/team-worker-hook.d.ts.map +1 -0
  569. package/dist/hooks/team-worker-hook.js +415 -0
  570. package/dist/hooks/team-worker-hook.js.map +1 -0
  571. package/dist/hooks/think-mode/__tests__/index.test.js.map +1 -1
  572. package/dist/hooks/todo-continuation/__tests__/isAuthenticationError.test.d.ts +2 -0
  573. package/dist/hooks/todo-continuation/__tests__/isAuthenticationError.test.d.ts.map +1 -0
  574. package/dist/hooks/todo-continuation/__tests__/isAuthenticationError.test.js +33 -0
  575. package/dist/hooks/todo-continuation/__tests__/isAuthenticationError.test.js.map +1 -0
  576. package/dist/hooks/todo-continuation/index.d.ts +12 -0
  577. package/dist/hooks/todo-continuation/index.d.ts.map +1 -1
  578. package/dist/hooks/todo-continuation/index.js +37 -1
  579. package/dist/hooks/todo-continuation/index.js.map +1 -1
  580. package/dist/hooks/ultrapilot/decomposer.d.ts.map +1 -1
  581. package/dist/hooks/ultrapilot/decomposer.js +3 -1
  582. package/dist/hooks/ultrapilot/decomposer.js.map +1 -1
  583. package/dist/hooks/ultrapilot/index.d.ts.map +1 -1
  584. package/dist/hooks/ultrapilot/index.js +3 -1
  585. package/dist/hooks/ultrapilot/index.js.map +1 -1
  586. package/dist/hooks/ultrapilot/state.d.ts +1 -1
  587. package/dist/hooks/ultrapilot/state.d.ts.map +1 -1
  588. package/dist/hooks/ultrapilot/state.js +45 -77
  589. package/dist/hooks/ultrapilot/state.js.map +1 -1
  590. package/dist/hooks/ultraqa/index.d.ts.map +1 -1
  591. package/dist/hooks/ultraqa/index.js +4 -77
  592. package/dist/hooks/ultraqa/index.js.map +1 -1
  593. package/dist/hooks/ultrawork/index.d.ts.map +1 -1
  594. package/dist/hooks/ultrawork/index.js +40 -82
  595. package/dist/hooks/ultrawork/index.js.map +1 -1
  596. package/dist/hooks/ultrawork/session-isolation.test.js +1 -1
  597. package/dist/hooks/ultrawork/session-isolation.test.js.map +1 -1
  598. package/dist/hud/elements/api-key-source.d.ts +30 -0
  599. package/dist/hud/elements/api-key-source.d.ts.map +1 -0
  600. package/dist/hud/elements/api-key-source.js +70 -0
  601. package/dist/hud/elements/api-key-source.js.map +1 -0
  602. package/dist/hud/elements/index.d.ts +1 -0
  603. package/dist/hud/elements/index.d.ts.map +1 -1
  604. package/dist/hud/elements/index.js +1 -0
  605. package/dist/hud/elements/index.js.map +1 -1
  606. package/dist/hud/elements/limits.d.ts +9 -1
  607. package/dist/hud/elements/limits.d.ts.map +1 -1
  608. package/dist/hud/elements/limits.js +18 -0
  609. package/dist/hud/elements/limits.js.map +1 -1
  610. package/dist/hud/index.d.ts.map +1 -1
  611. package/dist/hud/index.js +40 -25
  612. package/dist/hud/index.js.map +1 -1
  613. package/dist/hud/omc-state.d.ts.map +1 -1
  614. package/dist/hud/omc-state.js +6 -4
  615. package/dist/hud/omc-state.js.map +1 -1
  616. package/dist/hud/render.d.ts +9 -0
  617. package/dist/hud/render.d.ts.map +1 -1
  618. package/dist/hud/render.js +166 -15
  619. package/dist/hud/render.js.map +1 -1
  620. package/dist/hud/state.d.ts.map +1 -1
  621. package/dist/hud/state.js +23 -14
  622. package/dist/hud/state.js.map +1 -1
  623. package/dist/hud/stdin.d.ts.map +1 -1
  624. package/dist/hud/stdin.js +5 -2
  625. package/dist/hud/stdin.js.map +1 -1
  626. package/dist/hud/types.d.ts +34 -3
  627. package/dist/hud/types.d.ts.map +1 -1
  628. package/dist/hud/types.js +19 -0
  629. package/dist/hud/types.js.map +1 -1
  630. package/dist/hud/usage-api.d.ts +9 -6
  631. package/dist/hud/usage-api.d.ts.map +1 -1
  632. package/dist/hud/usage-api.js +115 -46
  633. package/dist/hud/usage-api.js.map +1 -1
  634. package/dist/index.d.ts +3 -1
  635. package/dist/index.d.ts.map +1 -1
  636. package/dist/index.js +6 -2
  637. package/dist/index.js.map +1 -1
  638. package/dist/installer/__tests__/claude-md-merge.test.js +29 -0
  639. package/dist/installer/__tests__/claude-md-merge.test.js.map +1 -1
  640. package/dist/installer/__tests__/safe-installer.test.js +1 -1
  641. package/dist/installer/__tests__/safe-installer.test.js.map +1 -1
  642. package/dist/installer/hooks.d.ts.map +1 -1
  643. package/dist/installer/hooks.js +11 -12
  644. package/dist/installer/hooks.js.map +1 -1
  645. package/dist/installer/index.d.ts.map +1 -1
  646. package/dist/installer/index.js +20 -16
  647. package/dist/installer/index.js.map +1 -1
  648. package/dist/interop/__tests__/worker-adapter-integration.test.d.ts +2 -0
  649. package/dist/interop/__tests__/worker-adapter-integration.test.d.ts.map +1 -0
  650. package/dist/interop/__tests__/worker-adapter-integration.test.js +219 -0
  651. package/dist/interop/__tests__/worker-adapter-integration.test.js.map +1 -0
  652. package/dist/interop/__tests__/worker-adapter.test.d.ts +2 -0
  653. package/dist/interop/__tests__/worker-adapter.test.d.ts.map +1 -0
  654. package/dist/interop/__tests__/worker-adapter.test.js +408 -0
  655. package/dist/interop/__tests__/worker-adapter.test.js.map +1 -0
  656. package/dist/interop/adapter-types.d.ts +39 -0
  657. package/dist/interop/adapter-types.d.ts.map +1 -0
  658. package/dist/interop/adapter-types.js +9 -0
  659. package/dist/interop/adapter-types.js.map +1 -0
  660. package/dist/interop/worker-adapter.d.ts +116 -0
  661. package/dist/interop/worker-adapter.d.ts.map +1 -0
  662. package/dist/interop/worker-adapter.js +324 -0
  663. package/dist/interop/worker-adapter.js.map +1 -0
  664. package/dist/lib/__tests__/mode-state-io.test.d.ts +2 -0
  665. package/dist/lib/__tests__/mode-state-io.test.d.ts.map +1 -0
  666. package/dist/lib/__tests__/mode-state-io.test.js +194 -0
  667. package/dist/lib/__tests__/mode-state-io.test.js.map +1 -0
  668. package/dist/lib/__tests__/payload-limits.test.d.ts +2 -0
  669. package/dist/lib/__tests__/payload-limits.test.d.ts.map +1 -0
  670. package/dist/lib/__tests__/payload-limits.test.js +124 -0
  671. package/dist/lib/__tests__/payload-limits.test.js.map +1 -0
  672. package/dist/lib/__tests__/worktree-paths.test.js +5 -4
  673. package/dist/lib/__tests__/worktree-paths.test.js.map +1 -1
  674. package/dist/lib/file-lock.d.ts +75 -0
  675. package/dist/lib/file-lock.d.ts.map +1 -0
  676. package/dist/lib/file-lock.js +246 -0
  677. package/dist/lib/file-lock.js.map +1 -0
  678. package/dist/lib/mode-names.d.ts +10 -3
  679. package/dist/lib/mode-names.d.ts.map +1 -1
  680. package/dist/lib/mode-names.js +12 -17
  681. package/dist/lib/mode-names.js.map +1 -1
  682. package/dist/lib/mode-state-io.d.ts +41 -0
  683. package/dist/lib/mode-state-io.d.ts.map +1 -0
  684. package/dist/lib/mode-state-io.js +127 -0
  685. package/dist/lib/mode-state-io.js.map +1 -0
  686. package/dist/lib/payload-limits.d.ts +31 -0
  687. package/dist/lib/payload-limits.d.ts.map +1 -0
  688. package/dist/lib/payload-limits.js +82 -0
  689. package/dist/lib/payload-limits.js.map +1 -0
  690. package/dist/lib/project-memory-merge.d.ts +36 -0
  691. package/dist/lib/project-memory-merge.d.ts.map +1 -0
  692. package/dist/lib/project-memory-merge.js +154 -0
  693. package/dist/lib/project-memory-merge.js.map +1 -0
  694. package/dist/lib/shared-memory.d.ts +82 -0
  695. package/dist/lib/shared-memory.d.ts.map +1 -0
  696. package/dist/lib/shared-memory.js +305 -0
  697. package/dist/lib/shared-memory.js.map +1 -0
  698. package/dist/lib/worktree-paths.d.ts +31 -3
  699. package/dist/lib/worktree-paths.d.ts.map +1 -1
  700. package/dist/lib/worktree-paths.js +147 -12
  701. package/dist/lib/worktree-paths.js.map +1 -1
  702. package/dist/mcp/__tests__/team-server-artifact-convergence.test.d.ts +2 -0
  703. package/dist/mcp/__tests__/team-server-artifact-convergence.test.d.ts.map +1 -0
  704. package/dist/mcp/__tests__/team-server-artifact-convergence.test.js +84 -0
  705. package/dist/mcp/__tests__/team-server-artifact-convergence.test.js.map +1 -0
  706. package/dist/mcp/__tests__/team-server-deprecation.test.d.ts +2 -0
  707. package/dist/mcp/__tests__/team-server-deprecation.test.d.ts.map +1 -0
  708. package/dist/mcp/__tests__/team-server-deprecation.test.js +54 -0
  709. package/dist/mcp/__tests__/team-server-deprecation.test.js.map +1 -0
  710. package/dist/mcp/omc-tools-server.d.ts +2 -0
  711. package/dist/mcp/omc-tools-server.d.ts.map +1 -1
  712. package/dist/mcp/omc-tools-server.js +9 -2
  713. package/dist/mcp/omc-tools-server.js.map +1 -1
  714. package/dist/mcp/team-job-convergence.d.ts +20 -0
  715. package/dist/mcp/team-job-convergence.d.ts.map +1 -0
  716. package/dist/mcp/team-job-convergence.js +101 -0
  717. package/dist/mcp/team-job-convergence.js.map +1 -0
  718. package/dist/mcp/team-server.d.ts +33 -10
  719. package/dist/mcp/team-server.d.ts.map +1 -1
  720. package/dist/mcp/team-server.js +219 -109
  721. package/dist/mcp/team-server.js.map +1 -1
  722. package/dist/notifications/__tests__/config.test.js +100 -6
  723. package/dist/notifications/__tests__/config.test.js.map +1 -1
  724. package/dist/notifications/__tests__/custom-integration.test.d.ts +8 -0
  725. package/dist/notifications/__tests__/custom-integration.test.d.ts.map +1 -0
  726. package/dist/notifications/__tests__/custom-integration.test.js +297 -0
  727. package/dist/notifications/__tests__/custom-integration.test.js.map +1 -0
  728. package/dist/notifications/__tests__/dispatcher.test.js +195 -0
  729. package/dist/notifications/__tests__/dispatcher.test.js.map +1 -1
  730. package/dist/notifications/__tests__/redact.test.d.ts +2 -0
  731. package/dist/notifications/__tests__/redact.test.d.ts.map +1 -0
  732. package/dist/notifications/__tests__/redact.test.js +111 -0
  733. package/dist/notifications/__tests__/redact.test.js.map +1 -0
  734. package/dist/notifications/__tests__/reply-listener.test.js +8 -1
  735. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
  736. package/dist/notifications/__tests__/slack-socket.test.d.ts +2 -0
  737. package/dist/notifications/__tests__/slack-socket.test.d.ts.map +1 -0
  738. package/dist/notifications/__tests__/slack-socket.test.js +293 -0
  739. package/dist/notifications/__tests__/slack-socket.test.js.map +1 -0
  740. package/dist/notifications/__tests__/template-engine.test.js +32 -0
  741. package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
  742. package/dist/notifications/config.d.ts +40 -0
  743. package/dist/notifications/config.d.ts.map +1 -1
  744. package/dist/notifications/config.js +201 -4
  745. package/dist/notifications/config.js.map +1 -1
  746. package/dist/notifications/dispatcher.d.ts +20 -1
  747. package/dist/notifications/dispatcher.d.ts.map +1 -1
  748. package/dist/notifications/dispatcher.js +183 -7
  749. package/dist/notifications/dispatcher.js.map +1 -1
  750. package/dist/notifications/hook-config-types.d.ts +1 -1
  751. package/dist/notifications/hook-config-types.d.ts.map +1 -1
  752. package/dist/notifications/index.d.ts +11 -2
  753. package/dist/notifications/index.d.ts.map +1 -1
  754. package/dist/notifications/index.js +13 -3
  755. package/dist/notifications/index.js.map +1 -1
  756. package/dist/notifications/presets.d.ts +43 -0
  757. package/dist/notifications/presets.d.ts.map +1 -0
  758. package/dist/notifications/presets.js +122 -0
  759. package/dist/notifications/presets.js.map +1 -0
  760. package/dist/notifications/redact.d.ts +21 -0
  761. package/dist/notifications/redact.d.ts.map +1 -0
  762. package/dist/notifications/redact.js +33 -0
  763. package/dist/notifications/redact.js.map +1 -0
  764. package/dist/notifications/reply-listener.d.ts +54 -2
  765. package/dist/notifications/reply-listener.d.ts.map +1 -1
  766. package/dist/notifications/reply-listener.js +178 -15
  767. package/dist/notifications/reply-listener.js.map +1 -1
  768. package/dist/notifications/session-registry.d.ts +1 -1
  769. package/dist/notifications/session-registry.d.ts.map +1 -1
  770. package/dist/notifications/slack-socket.d.ts +242 -0
  771. package/dist/notifications/slack-socket.d.ts.map +1 -0
  772. package/dist/notifications/slack-socket.js +603 -0
  773. package/dist/notifications/slack-socket.js.map +1 -0
  774. package/dist/notifications/template-engine.d.ts.map +1 -1
  775. package/dist/notifications/template-engine.js +4 -0
  776. package/dist/notifications/template-engine.js.map +1 -1
  777. package/dist/notifications/template-variables.d.ts +26 -0
  778. package/dist/notifications/template-variables.d.ts.map +1 -0
  779. package/dist/notifications/template-variables.js +139 -0
  780. package/dist/notifications/template-variables.js.map +1 -0
  781. package/dist/notifications/types.d.ts +75 -2
  782. package/dist/notifications/types.d.ts.map +1 -1
  783. package/dist/notifications/validation.d.ts +24 -0
  784. package/dist/notifications/validation.d.ts.map +1 -0
  785. package/dist/notifications/validation.js +167 -0
  786. package/dist/notifications/validation.js.map +1 -0
  787. package/dist/openclaw/__tests__/dispatcher.test.js +0 -1
  788. package/dist/openclaw/__tests__/dispatcher.test.js.map +1 -1
  789. package/dist/openclaw/__tests__/index.test.js +82 -0
  790. package/dist/openclaw/__tests__/index.test.js.map +1 -1
  791. package/dist/openclaw/index.d.ts.map +1 -1
  792. package/dist/openclaw/index.js +24 -1
  793. package/dist/openclaw/index.js.map +1 -1
  794. package/dist/openclaw/types.d.ts +12 -0
  795. package/dist/openclaw/types.d.ts.map +1 -1
  796. package/dist/shared/types.d.ts +84 -20
  797. package/dist/shared/types.d.ts.map +1 -1
  798. package/dist/team/__tests__/api-interop.command-dialect.test.d.ts +2 -0
  799. package/dist/team/__tests__/api-interop.command-dialect.test.d.ts.map +1 -0
  800. package/dist/team/__tests__/api-interop.command-dialect.test.js +26 -0
  801. package/dist/team/__tests__/api-interop.command-dialect.test.js.map +1 -0
  802. package/dist/team/__tests__/api-interop.compatibility.test.d.ts +2 -0
  803. package/dist/team/__tests__/api-interop.compatibility.test.d.ts.map +1 -0
  804. package/dist/team/__tests__/api-interop.compatibility.test.js +93 -0
  805. package/dist/team/__tests__/api-interop.compatibility.test.js.map +1 -0
  806. package/dist/team/__tests__/cli-path-resolution.test.d.ts +2 -0
  807. package/dist/team/__tests__/cli-path-resolution.test.d.ts.map +1 -0
  808. package/dist/team/__tests__/cli-path-resolution.test.js +281 -0
  809. package/dist/team/__tests__/cli-path-resolution.test.js.map +1 -0
  810. package/dist/team/__tests__/index.compat-exports.test.d.ts +2 -0
  811. package/dist/team/__tests__/index.compat-exports.test.d.ts.map +1 -0
  812. package/dist/team/__tests__/index.compat-exports.test.js +20 -0
  813. package/dist/team/__tests__/index.compat-exports.test.js.map +1 -0
  814. package/dist/team/__tests__/layout-stabilizer.test.d.ts +2 -0
  815. package/dist/team/__tests__/layout-stabilizer.test.d.ts.map +1 -0
  816. package/dist/team/__tests__/layout-stabilizer.test.js +217 -0
  817. package/dist/team/__tests__/layout-stabilizer.test.js.map +1 -0
  818. package/dist/team/__tests__/mcp-team-bridge.spawn-args.test.js +8 -4
  819. package/dist/team/__tests__/mcp-team-bridge.spawn-args.test.js.map +1 -1
  820. package/dist/team/__tests__/mcp-team-bridge.usage.test.js +4 -2
  821. package/dist/team/__tests__/mcp-team-bridge.usage.test.js.map +1 -1
  822. package/dist/team/__tests__/model-contract.test.js +84 -8
  823. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  824. package/dist/team/__tests__/pane-readiness.test.d.ts +2 -0
  825. package/dist/team/__tests__/pane-readiness.test.d.ts.map +1 -0
  826. package/dist/team/__tests__/pane-readiness.test.js +185 -0
  827. package/dist/team/__tests__/pane-readiness.test.js.map +1 -0
  828. package/dist/team/__tests__/prompt-sanitization.test.js +1 -1
  829. package/dist/team/__tests__/prompt-sanitization.test.js.map +1 -1
  830. package/dist/team/__tests__/runtime-cli.test.d.ts +2 -0
  831. package/dist/team/__tests__/runtime-cli.test.d.ts.map +1 -0
  832. package/dist/team/__tests__/runtime-cli.test.js +159 -0
  833. package/dist/team/__tests__/runtime-cli.test.js.map +1 -0
  834. package/dist/team/__tests__/runtime-done-recovery.test.d.ts +2 -0
  835. package/dist/team/__tests__/runtime-done-recovery.test.d.ts.map +1 -0
  836. package/dist/team/__tests__/runtime-done-recovery.test.js +77 -0
  837. package/dist/team/__tests__/runtime-done-recovery.test.js.map +1 -0
  838. package/dist/team/__tests__/runtime-interop-spawn-regression.test.d.ts +2 -0
  839. package/dist/team/__tests__/runtime-interop-spawn-regression.test.d.ts.map +1 -0
  840. package/dist/team/__tests__/runtime-interop-spawn-regression.test.js +139 -0
  841. package/dist/team/__tests__/runtime-interop-spawn-regression.test.js.map +1 -0
  842. package/dist/team/__tests__/runtime-prompt-mode.test.js +167 -14
  843. package/dist/team/__tests__/runtime-prompt-mode.test.js.map +1 -1
  844. package/dist/team/__tests__/runtime-v2.feature-flag.test.d.ts +2 -0
  845. package/dist/team/__tests__/runtime-v2.feature-flag.test.d.ts.map +1 -0
  846. package/dist/team/__tests__/runtime-v2.feature-flag.test.js +20 -0
  847. package/dist/team/__tests__/runtime-v2.feature-flag.test.js.map +1 -0
  848. package/dist/team/__tests__/runtime-watchdog-retry.test.d.ts +2 -0
  849. package/dist/team/__tests__/runtime-watchdog-retry.test.d.ts.map +1 -0
  850. package/dist/team/__tests__/runtime-watchdog-retry.test.js +408 -0
  851. package/dist/team/__tests__/runtime-watchdog-retry.test.js.map +1 -0
  852. package/dist/team/__tests__/shell-path.test.d.ts +2 -0
  853. package/dist/team/__tests__/shell-path.test.d.ts.map +1 -0
  854. package/dist/team/__tests__/shell-path.test.js +193 -0
  855. package/dist/team/__tests__/shell-path.test.js.map +1 -0
  856. package/dist/team/__tests__/state-paths.test.d.ts +2 -0
  857. package/dist/team/__tests__/state-paths.test.d.ts.map +1 -0
  858. package/dist/team/__tests__/state-paths.test.js +16 -0
  859. package/dist/team/__tests__/state-paths.test.js.map +1 -0
  860. package/dist/team/__tests__/task-file-ops.test.js +8 -2
  861. package/dist/team/__tests__/task-file-ops.test.js.map +1 -1
  862. package/dist/team/__tests__/tmux-session.create-team.test.js +15 -17
  863. package/dist/team/__tests__/tmux-session.create-team.test.js.map +1 -1
  864. package/dist/team/__tests__/tmux-session.kill-team-session.test.d.ts +2 -0
  865. package/dist/team/__tests__/tmux-session.kill-team-session.test.d.ts.map +1 -0
  866. package/dist/team/__tests__/tmux-session.kill-team-session.test.js +56 -0
  867. package/dist/team/__tests__/tmux-session.kill-team-session.test.js.map +1 -0
  868. package/dist/team/__tests__/tmux-session.spawn.test.js +9 -0
  869. package/dist/team/__tests__/tmux-session.spawn.test.js.map +1 -1
  870. package/dist/team/__tests__/tmux-session.test.js +83 -5
  871. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  872. package/dist/team/__tests__/wait-for-shell-ready.test.d.ts +2 -0
  873. package/dist/team/__tests__/wait-for-shell-ready.test.d.ts.map +1 -0
  874. package/dist/team/__tests__/wait-for-shell-ready.test.js +242 -0
  875. package/dist/team/__tests__/wait-for-shell-ready.test.js.map +1 -0
  876. package/dist/team/__tests__/worker-bootstrap.test.js +11 -0
  877. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  878. package/dist/team/api-interop.d.ts +20 -0
  879. package/dist/team/api-interop.d.ts.map +1 -0
  880. package/dist/team/api-interop.js +601 -0
  881. package/dist/team/api-interop.js.map +1 -0
  882. package/dist/team/contracts.d.ts +14 -0
  883. package/dist/team/contracts.d.ts.map +1 -0
  884. package/dist/team/contracts.js +32 -0
  885. package/dist/team/contracts.js.map +1 -0
  886. package/dist/team/dispatch-queue.d.ts +64 -0
  887. package/dist/team/dispatch-queue.d.ts.map +1 -0
  888. package/dist/team/dispatch-queue.js +288 -0
  889. package/dist/team/dispatch-queue.js.map +1 -0
  890. package/dist/team/events.d.ts +49 -0
  891. package/dist/team/events.d.ts.map +1 -0
  892. package/dist/team/events.js +113 -0
  893. package/dist/team/events.js.map +1 -0
  894. package/dist/team/index.d.ts +15 -2
  895. package/dist/team/index.d.ts.map +1 -1
  896. package/dist/team/index.js +14 -1
  897. package/dist/team/index.js.map +1 -1
  898. package/dist/team/layout-stabilizer.d.ts +23 -0
  899. package/dist/team/layout-stabilizer.d.ts.map +1 -0
  900. package/dist/team/layout-stabilizer.js +117 -0
  901. package/dist/team/layout-stabilizer.js.map +1 -0
  902. package/dist/team/mcp-comm.d.ts +99 -0
  903. package/dist/team/mcp-comm.d.ts.map +1 -0
  904. package/dist/team/mcp-comm.js +235 -0
  905. package/dist/team/mcp-comm.js.map +1 -0
  906. package/dist/team/mcp-team-bridge.d.ts +2 -2
  907. package/dist/team/mcp-team-bridge.d.ts.map +1 -1
  908. package/dist/team/mcp-team-bridge.js +263 -144
  909. package/dist/team/mcp-team-bridge.js.map +1 -1
  910. package/dist/team/model-contract.d.ts +28 -1
  911. package/dist/team/model-contract.d.ts.map +1 -1
  912. package/dist/team/model-contract.js +143 -5
  913. package/dist/team/model-contract.js.map +1 -1
  914. package/dist/team/monitor.d.ts +45 -0
  915. package/dist/team/monitor.d.ts.map +1 -0
  916. package/dist/team/monitor.js +339 -0
  917. package/dist/team/monitor.js.map +1 -0
  918. package/dist/team/runtime-cli.d.ts +24 -0
  919. package/dist/team/runtime-cli.d.ts.map +1 -1
  920. package/dist/team/runtime-cli.js +230 -12
  921. package/dist/team/runtime-cli.js.map +1 -1
  922. package/dist/team/runtime-v2.d.ts +122 -0
  923. package/dist/team/runtime-v2.d.ts.map +1 -0
  924. package/dist/team/runtime-v2.js +766 -0
  925. package/dist/team/runtime-v2.js.map +1 -0
  926. package/dist/team/runtime.d.ts +2 -0
  927. package/dist/team/runtime.d.ts.map +1 -1
  928. package/dist/team/runtime.js +145 -52
  929. package/dist/team/runtime.js.map +1 -1
  930. package/dist/team/scaling.d.ts +59 -0
  931. package/dist/team/scaling.d.ts.map +1 -0
  932. package/dist/team/scaling.js +311 -0
  933. package/dist/team/scaling.js.map +1 -0
  934. package/dist/team/sentinel-gate.d.ts +23 -0
  935. package/dist/team/sentinel-gate.d.ts.map +1 -0
  936. package/dist/team/sentinel-gate.js +127 -0
  937. package/dist/team/sentinel-gate.js.map +1 -0
  938. package/dist/team/shell-path.d.ts +21 -0
  939. package/dist/team/shell-path.d.ts.map +1 -0
  940. package/dist/team/shell-path.js +73 -0
  941. package/dist/team/shell-path.js.map +1 -0
  942. package/dist/team/state/tasks.d.ts +48 -0
  943. package/dist/team/state/tasks.d.ts.map +1 -0
  944. package/dist/team/state/tasks.js +184 -0
  945. package/dist/team/state/tasks.js.map +1 -0
  946. package/dist/team/state-paths.d.ts +20 -4
  947. package/dist/team/state-paths.d.ts.map +1 -1
  948. package/dist/team/state-paths.js +29 -6
  949. package/dist/team/state-paths.js.map +1 -1
  950. package/dist/team/task-file-ops.d.ts +2 -1
  951. package/dist/team/task-file-ops.d.ts.map +1 -1
  952. package/dist/team/task-file-ops.js +19 -0
  953. package/dist/team/task-file-ops.js.map +1 -1
  954. package/dist/team/team-ops.d.ts +44 -0
  955. package/dist/team/team-ops.d.ts.map +1 -0
  956. package/dist/team/team-ops.js +547 -0
  957. package/dist/team/team-ops.js.map +1 -0
  958. package/dist/team/tmux-comm.d.ts.map +1 -1
  959. package/dist/team/tmux-comm.js +107 -44
  960. package/dist/team/tmux-comm.js.map +1 -1
  961. package/dist/team/tmux-session.d.ts +5 -0
  962. package/dist/team/tmux-session.d.ts.map +1 -1
  963. package/dist/team/tmux-session.js +81 -10
  964. package/dist/team/tmux-session.js.map +1 -1
  965. package/dist/team/types.d.ts +303 -8
  966. package/dist/team/types.d.ts.map +1 -1
  967. package/dist/team/types.js +2 -1
  968. package/dist/team/types.js.map +1 -1
  969. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  970. package/dist/team/worker-bootstrap.js +73 -21
  971. package/dist/team/worker-bootstrap.js.map +1 -1
  972. package/dist/tools/__tests__/cancel-integration.test.d.ts +2 -0
  973. package/dist/tools/__tests__/cancel-integration.test.d.ts.map +1 -0
  974. package/dist/tools/__tests__/cancel-integration.test.js +248 -0
  975. package/dist/tools/__tests__/cancel-integration.test.js.map +1 -0
  976. package/dist/tools/__tests__/memory-tools.test.d.ts +2 -0
  977. package/dist/tools/__tests__/memory-tools.test.d.ts.map +1 -0
  978. package/dist/tools/__tests__/memory-tools.test.js +66 -0
  979. package/dist/tools/__tests__/memory-tools.test.js.map +1 -0
  980. package/dist/tools/__tests__/state-tools.test.js +73 -5
  981. package/dist/tools/__tests__/state-tools.test.js.map +1 -1
  982. package/dist/tools/lsp/__tests__/client-eviction.test.js +6 -6
  983. package/dist/tools/lsp/__tests__/client-eviction.test.js.map +1 -1
  984. package/dist/tools/lsp/__tests__/client-timeout-env.test.d.ts +2 -0
  985. package/dist/tools/lsp/__tests__/client-timeout-env.test.d.ts.map +1 -0
  986. package/dist/tools/lsp/__tests__/client-timeout-env.test.js +39 -0
  987. package/dist/tools/lsp/__tests__/client-timeout-env.test.js.map +1 -0
  988. package/dist/tools/lsp/client.d.ts +2 -0
  989. package/dist/tools/lsp/client.d.ts.map +1 -1
  990. package/dist/tools/lsp/client.js +11 -1
  991. package/dist/tools/lsp/client.js.map +1 -1
  992. package/dist/tools/lsp/index.d.ts +1 -1
  993. package/dist/tools/lsp/index.d.ts.map +1 -1
  994. package/dist/tools/lsp/index.js +1 -1
  995. package/dist/tools/lsp/index.js.map +1 -1
  996. package/dist/tools/memory-tools.d.ts.map +1 -1
  997. package/dist/tools/memory-tools.js +2 -1
  998. package/dist/tools/memory-tools.js.map +1 -1
  999. package/dist/tools/python-repl/__tests__/tcp-fallback.test.d.ts +2 -0
  1000. package/dist/tools/python-repl/__tests__/tcp-fallback.test.d.ts.map +1 -0
  1001. package/dist/tools/python-repl/__tests__/tcp-fallback.test.js +138 -0
  1002. package/dist/tools/python-repl/__tests__/tcp-fallback.test.js.map +1 -0
  1003. package/dist/tools/python-repl/bridge-manager.d.ts.map +1 -1
  1004. package/dist/tools/python-repl/bridge-manager.js +104 -24
  1005. package/dist/tools/python-repl/bridge-manager.js.map +1 -1
  1006. package/dist/tools/python-repl/paths.d.ts +8 -0
  1007. package/dist/tools/python-repl/paths.d.ts.map +1 -1
  1008. package/dist/tools/python-repl/paths.js +10 -0
  1009. package/dist/tools/python-repl/paths.js.map +1 -1
  1010. package/dist/tools/python-repl/socket-client.d.ts.map +1 -1
  1011. package/dist/tools/python-repl/socket-client.js +9 -2
  1012. package/dist/tools/python-repl/socket-client.js.map +1 -1
  1013. package/dist/tools/shared-memory-tools.d.ts +55 -0
  1014. package/dist/tools/shared-memory-tools.d.ts.map +1 -0
  1015. package/dist/tools/shared-memory-tools.js +250 -0
  1016. package/dist/tools/shared-memory-tools.js.map +1 -0
  1017. package/dist/tools/state-tools.d.ts.map +1 -1
  1018. package/dist/tools/state-tools.js +126 -101
  1019. package/dist/tools/state-tools.js.map +1 -1
  1020. package/dist/utils/daemon-module-path.d.ts +9 -0
  1021. package/dist/utils/daemon-module-path.d.ts.map +1 -0
  1022. package/dist/utils/daemon-module-path.js +23 -0
  1023. package/dist/utils/daemon-module-path.js.map +1 -0
  1024. package/dist/utils/jsonc.d.ts +16 -0
  1025. package/dist/utils/jsonc.d.ts.map +1 -0
  1026. package/dist/utils/jsonc.js +64 -0
  1027. package/dist/utils/jsonc.js.map +1 -0
  1028. package/dist/utils/paths.js +1 -1
  1029. package/dist/utils/paths.js.map +1 -1
  1030. package/dist/utils/ssrf-guard.d.ts +26 -0
  1031. package/dist/utils/ssrf-guard.d.ts.map +1 -0
  1032. package/dist/utils/ssrf-guard.js +103 -0
  1033. package/dist/utils/ssrf-guard.js.map +1 -0
  1034. package/dist/verification/tier-selector.d.ts +1 -1
  1035. package/dist/verification/tier-selector.js +1 -1
  1036. package/docs/ANALYTICS-SYSTEM.md +2 -5
  1037. package/docs/CLAUDE.md +88 -212
  1038. package/docs/MIGRATION.md +138 -161
  1039. package/docs/PERFORMANCE-MONITORING.md +5 -5
  1040. package/docs/REFERENCE.md +351 -286
  1041. package/docs/fixes/agent-prefix-routing-fix.md +105 -0
  1042. package/docs/ko/ARCHITECTURE.md +152 -0
  1043. package/docs/ko/FEATURES.md +582 -0
  1044. package/docs/ko/MIGRATION.md +1027 -0
  1045. package/docs/ko/REFERENCE.md +745 -0
  1046. package/docs/partials/mode-selection-guide.md +22 -12
  1047. package/docs/shared/mode-selection-guide.md +22 -12
  1048. package/package.json +11 -6
  1049. package/scripts/ask-codex.sh +24 -0
  1050. package/scripts/ask-gemini.sh +24 -0
  1051. package/scripts/build-cli.mjs +47 -0
  1052. package/scripts/build-runtime-cli.mjs +2 -0
  1053. package/scripts/context-guard-stop.mjs +66 -3
  1054. package/scripts/context-safety.mjs +67 -2
  1055. package/scripts/keyword-detector.mjs +14 -36
  1056. package/scripts/persistent-mode.cjs +106 -1
  1057. package/scripts/persistent-mode.mjs +88 -2
  1058. package/scripts/plugin-setup.mjs +46 -4
  1059. package/scripts/pre-tool-enforcer.mjs +1 -0
  1060. package/scripts/qa-tests/test-custom-integration.mjs +144 -0
  1061. package/scripts/run-provider-advisor.js +220 -0
  1062. package/scripts/session-start.mjs +42 -2
  1063. package/skills/AGENTS.md +16 -20
  1064. package/skills/ask-codex/SKILL.md +47 -0
  1065. package/skills/ask-gemini/SKILL.md +47 -0
  1066. package/skills/autopilot/SKILL.md +39 -5
  1067. package/skills/cancel/SKILL.md +23 -105
  1068. package/skills/ccg/SKILL.md +58 -75
  1069. package/skills/configure-notifications/SKILL.md +276 -0
  1070. package/skills/configure-openclaw/SKILL.md +63 -0
  1071. package/skills/deep-interview/SKILL.md +551 -0
  1072. package/skills/deepinit/SKILL.md +1 -1
  1073. package/skills/hud/SKILL.md +35 -3
  1074. package/skills/omc-doctor/SKILL.md +30 -13
  1075. package/skills/omc-help/SKILL.md +1 -1
  1076. package/skills/omc-setup/SKILL.md +20 -20
  1077. package/skills/omc-teams/SKILL.md +60 -112
  1078. package/skills/plan/SKILL.md +5 -5
  1079. package/skills/quick-init-project/SKILL.md +333 -0
  1080. package/skills/ralph/SKILL.md +96 -70
  1081. package/skills/ralplan/SKILL.md +7 -7
  1082. package/skills/security-review/SKILL.md +2 -2
  1083. package/skills/team/SKILL.md +36 -2
  1084. package/skills/ultrawork/SKILL.md +7 -7
  1085. package/templates/hooks/keyword-detector.mjs +20 -28
  1086. package/templates/hooks/persistent-mode.mjs +89 -2
  1087. package/templates/hooks/pre-tool-use.mjs +79 -0
  1088. package/templates/hooks/session-start.mjs +3 -3
  1089. package/skills/pipeline/SKILL.md +0 -434
  1090. package/skills/review/SKILL.md +0 -30
  1091. package/skills/ultrapilot/SKILL.md +0 -632
@@ -5,6 +5,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
8
15
  var __copyProps = (to, from, except, desc) => {
9
16
  if (from && typeof from === "object" || typeof from === "function") {
10
17
  for (let key of __getOwnPropNames(from))
@@ -21,22 +28,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
28
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
29
  mod
23
30
  ));
24
-
25
- // src/team/runtime-cli.ts
26
- var import_fs7 = require("fs");
27
- var import_promises4 = require("fs/promises");
28
- var import_path10 = require("path");
29
-
30
- // src/team/runtime.ts
31
- var import_promises3 = require("fs/promises");
32
- var import_path9 = require("path");
33
- var import_fs6 = require("fs");
34
-
35
- // src/team/model-contract.ts
36
- var import_child_process = require("child_process");
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
32
 
38
33
  // src/team/team-name.ts
39
- var TEAM_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,48}[a-z0-9]$/;
40
34
  function validateTeamName(teamName) {
41
35
  if (!TEAM_NAME_PATTERN.test(teamName)) {
42
36
  throw new Error(
@@ -45,130 +39,40 @@ function validateTeamName(teamName) {
45
39
  }
46
40
  return teamName;
47
41
  }
48
-
49
- // src/team/model-contract.ts
50
- var CONTRACTS = {
51
- claude: {
52
- agentType: "claude",
53
- binary: "claude",
54
- installInstructions: "Install Claude CLI: https://claude.ai/download",
55
- buildLaunchArgs(model, extraFlags = []) {
56
- const args = ["--dangerously-skip-permissions"];
57
- if (model) args.push("--model", model);
58
- return [...args, ...extraFlags];
59
- },
60
- parseOutput(rawOutput) {
61
- return rawOutput.trim();
62
- }
63
- },
64
- codex: {
65
- agentType: "codex",
66
- binary: "codex",
67
- installInstructions: "Install Codex CLI: npm install -g @openai/codex",
68
- supportsPromptMode: true,
69
- // Codex accepts prompt as a positional argument (no flag needed):
70
- // codex [OPTIONS] [PROMPT]
71
- buildLaunchArgs(model, extraFlags = []) {
72
- const args = ["--dangerously-bypass-approvals-and-sandbox"];
73
- if (model) args.push("--model", model);
74
- return [...args, ...extraFlags];
75
- },
76
- parseOutput(rawOutput) {
77
- const lines = rawOutput.trim().split("\n").filter(Boolean);
78
- for (let i = lines.length - 1; i >= 0; i--) {
79
- try {
80
- const parsed = JSON.parse(lines[i]);
81
- if (parsed.type === "message" && parsed.role === "assistant") {
82
- return parsed.content ?? rawOutput;
83
- }
84
- if (parsed.type === "result" || parsed.output) {
85
- return parsed.output ?? parsed.result ?? rawOutput;
86
- }
87
- } catch {
88
- }
89
- }
90
- return rawOutput.trim();
91
- }
92
- },
93
- gemini: {
94
- agentType: "gemini",
95
- binary: "gemini",
96
- installInstructions: "Install Gemini CLI: npm install -g @google/gemini-cli",
97
- supportsPromptMode: true,
98
- promptModeFlag: "-p",
99
- buildLaunchArgs(model, extraFlags = []) {
100
- const args = ["--yolo"];
101
- if (model) args.push("--model", model);
102
- return [...args, ...extraFlags];
103
- },
104
- parseOutput(rawOutput) {
105
- return rawOutput.trim();
106
- }
107
- }
108
- };
109
- function getContract(agentType) {
110
- const contract = CONTRACTS[agentType];
111
- if (!contract) {
112
- throw new Error(`Unknown agent type: ${agentType}. Supported: ${Object.keys(CONTRACTS).join(", ")}`);
113
- }
114
- return contract;
115
- }
116
- function isCliAvailable(agentType) {
117
- const contract = getContract(agentType);
118
- try {
119
- const result = (0, import_child_process.spawnSync)(contract.binary, ["--version"], { timeout: 5e3, shell: true });
120
- return result.status === 0;
121
- } catch {
122
- return false;
123
- }
124
- }
125
- function validateCliAvailable(agentType) {
126
- if (!isCliAvailable(agentType)) {
127
- const contract = getContract(agentType);
128
- throw new Error(
129
- `CLI agent '${agentType}' not found. ${contract.installInstructions}`
130
- );
131
- }
132
- }
133
- function buildLaunchArgs(agentType, config) {
134
- return getContract(agentType).buildLaunchArgs(config.model, config.extraFlags);
135
- }
136
- function buildWorkerArgv(agentType, config) {
137
- validateTeamName(config.teamName);
138
- const contract = getContract(agentType);
139
- const args = buildLaunchArgs(agentType, config);
140
- return [contract.binary, ...args];
141
- }
142
- function getWorkerEnv(teamName, workerName2, agentType) {
143
- validateTeamName(teamName);
144
- return {
145
- OMC_TEAM_WORKER: `${teamName}/${workerName2}`,
146
- OMC_TEAM_NAME: teamName,
147
- OMC_WORKER_AGENT_TYPE: agentType
148
- };
149
- }
150
- function isPromptModeAgent(agentType) {
151
- const contract = getContract(agentType);
152
- return !!contract.supportsPromptMode;
153
- }
154
- function getPromptModeArgs(agentType, instruction) {
155
- const contract = getContract(agentType);
156
- if (!contract.supportsPromptMode) {
157
- return [];
158
- }
159
- if (contract.promptModeFlag) {
160
- return [contract.promptModeFlag, instruction];
42
+ var TEAM_NAME_PATTERN;
43
+ var init_team_name = __esm({
44
+ "src/team/team-name.ts"() {
45
+ "use strict";
46
+ TEAM_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,48}[a-z0-9]$/;
161
47
  }
162
- return [instruction];
163
- }
48
+ });
164
49
 
165
50
  // src/team/tmux-session.ts
166
- var import_child_process2 = require("child_process");
167
- var import_path = require("path");
168
- var import_util = require("util");
169
- var import_promises = __toESM(require("fs/promises"), 1);
170
- var promisifiedExec = (0, import_util.promisify)(import_child_process2.exec);
171
- var promisifiedExecFile = (0, import_util.promisify)(import_child_process2.execFile);
51
+ var tmux_session_exports = {};
52
+ __export(tmux_session_exports, {
53
+ buildWorkerStartCommand: () => buildWorkerStartCommand,
54
+ createSession: () => createSession,
55
+ createTeamSession: () => createTeamSession,
56
+ getDefaultShell: () => getDefaultShell,
57
+ injectToLeaderPane: () => injectToLeaderPane,
58
+ isSessionAlive: () => isSessionAlive,
59
+ isUnixLikeOnWindows: () => isUnixLikeOnWindows,
60
+ isWorkerAlive: () => isWorkerAlive,
61
+ killSession: () => killSession,
62
+ killTeamSession: () => killTeamSession,
63
+ killWorkerPanes: () => killWorkerPanes,
64
+ listActiveSessions: () => listActiveSessions,
65
+ paneHasActiveTask: () => paneHasActiveTask,
66
+ paneLooksReady: () => paneLooksReady,
67
+ sanitizeName: () => sanitizeName,
68
+ sendToWorker: () => sendToWorker,
69
+ sessionName: () => sessionName,
70
+ shouldAttemptAdaptiveRetry: () => shouldAttemptAdaptiveRetry,
71
+ spawnBridgeInSession: () => spawnBridgeInSession,
72
+ spawnWorkerInPane: () => spawnWorkerInPane,
73
+ validateTmux: () => validateTmux,
74
+ waitForPaneReady: () => waitForPaneReady
75
+ });
172
76
  function isUnixLikeOnWindows() {
173
77
  return process.platform === "win32" && !!(process.env.MSYSTEM || process.env.MINGW_PREFIX);
174
78
  }
@@ -189,7 +93,7 @@ function escapeForCmdSet(value) {
189
93
  return value.replace(/"/g, '""');
190
94
  }
191
95
  function shellNameFromPath(shellPath) {
192
- const shellName = (0, import_path.basename)(shellPath.replace(/\\/g, "/"));
96
+ const shellName = (0, import_path2.basename)(shellPath.replace(/\\/g, "/"));
193
97
  return shellName.replace(/\.(exe|cmd|bat)$/i, "");
194
98
  }
195
99
  function shellEscape(value) {
@@ -200,8 +104,26 @@ function assertSafeEnvKey(key) {
200
104
  throw new Error(`Invalid environment key: "${key}"`);
201
105
  }
202
106
  }
107
+ function isAbsoluteLaunchBinaryPath(value) {
108
+ return (0, import_path2.isAbsolute)(value) || import_path2.win32.isAbsolute(value);
109
+ }
110
+ function assertSafeLaunchBinary(launchBinary) {
111
+ if (launchBinary.trim().length === 0) {
112
+ throw new Error("Invalid launchBinary: value cannot be empty");
113
+ }
114
+ if (launchBinary !== launchBinary.trim()) {
115
+ throw new Error("Invalid launchBinary: value cannot have leading/trailing whitespace");
116
+ }
117
+ if (DANGEROUS_LAUNCH_BINARY_CHARS.test(launchBinary)) {
118
+ throw new Error("Invalid launchBinary: contains dangerous shell metacharacters");
119
+ }
120
+ if (/\s/.test(launchBinary) && !isAbsoluteLaunchBinaryPath(launchBinary)) {
121
+ throw new Error("Invalid launchBinary: paths with spaces must be absolute");
122
+ }
123
+ }
203
124
  function getLaunchWords(config) {
204
125
  if (config.launchBinary) {
126
+ assertSafeLaunchBinary(config.launchBinary);
205
127
  return [config.launchBinary, ...config.launchArgs ?? []];
206
128
  }
207
129
  if (config.launchCmd) {
@@ -212,6 +134,7 @@ function getLaunchWords(config) {
212
134
  function buildWorkerStartCommand(config) {
213
135
  const shell = getDefaultShell();
214
136
  const launchWords = getLaunchWords(config);
137
+ const shouldSourceRc = process.env.OMC_TEAM_NO_RC !== "1";
215
138
  if (process.platform === "win32" && !isUnixLikeOnWindows()) {
216
139
  const envPrefix = Object.entries(config.envVars).map(([k, v]) => {
217
140
  assertSafeEnvKey(k);
@@ -227,8 +150,9 @@ function buildWorkerStartCommand(config) {
227
150
  return `${key}=${shellEscape(value)}`;
228
151
  });
229
152
  const shellName2 = shellNameFromPath(shell) || "bash";
153
+ const execArgsCommand = shellName2 === "fish" ? "exec $argv" : 'exec "$@"';
230
154
  const rcFile2 = process.env.HOME ? `${process.env.HOME}/.${shellName2}rc` : "";
231
- const script = rcFile2 ? `[ -f ${shellEscape(rcFile2)} ] && . ${shellEscape(rcFile2)}; exec "$@"` : 'exec "$@"';
155
+ const script = shouldSourceRc && rcFile2 ? `[ -f ${shellEscape(rcFile2)} ] && . ${shellEscape(rcFile2)}; ${execArgsCommand}` : execArgsCommand;
232
156
  return [
233
157
  "env",
234
158
  ...envAssignments,
@@ -245,9 +169,18 @@ function buildWorkerStartCommand(config) {
245
169
  }).join(" ");
246
170
  const shellName = shellNameFromPath(shell) || "bash";
247
171
  const rcFile = process.env.HOME ? `${process.env.HOME}/.${shellName}rc` : "";
248
- const sourceCmd = rcFile ? `[ -f "${rcFile}" ] && source "${rcFile}"; ` : "";
172
+ const sourceCmd = shouldSourceRc && rcFile ? `[ -f "${rcFile}" ] && source "${rcFile}"; ` : "";
249
173
  return `env ${envString} ${shell} -c "${sourceCmd}exec ${launchWords[0]}"`;
250
174
  }
175
+ function validateTmux() {
176
+ try {
177
+ (0, import_child_process2.execSync)("tmux -V", { encoding: "utf-8", timeout: 5e3, stdio: "pipe" });
178
+ } catch {
179
+ throw new Error(
180
+ "tmux is not available. Install it:\n macOS: brew install tmux\n Ubuntu/Debian: sudo apt-get install tmux\n Fedora: sudo dnf install tmux\n Arch: sudo pacman -S tmux"
181
+ );
182
+ }
183
+ }
251
184
  function sanitizeName(name) {
252
185
  const sanitized = name.replace(/[^a-zA-Z0-9-]/g, "");
253
186
  if (sanitized.length === 0) {
@@ -258,18 +191,88 @@ function sanitizeName(name) {
258
191
  }
259
192
  return sanitized.slice(0, 50);
260
193
  }
194
+ function sessionName(teamName, workerName2) {
195
+ return `${TMUX_SESSION_PREFIX}-${sanitizeName(teamName)}-${sanitizeName(workerName2)}`;
196
+ }
197
+ function createSession(teamName, workerName2, workingDirectory) {
198
+ const name = sessionName(teamName, workerName2);
199
+ try {
200
+ (0, import_child_process2.execFileSync)("tmux", ["kill-session", "-t", name], { stdio: "pipe", timeout: 5e3 });
201
+ } catch {
202
+ }
203
+ const args = ["new-session", "-d", "-s", name, "-x", "200", "-y", "50"];
204
+ if (workingDirectory) {
205
+ args.push("-c", workingDirectory);
206
+ }
207
+ (0, import_child_process2.execFileSync)("tmux", args, { stdio: "pipe", timeout: 5e3 });
208
+ return name;
209
+ }
210
+ function killSession(teamName, workerName2) {
211
+ const name = sessionName(teamName, workerName2);
212
+ try {
213
+ (0, import_child_process2.execFileSync)("tmux", ["kill-session", "-t", name], { stdio: "pipe", timeout: 5e3 });
214
+ } catch {
215
+ }
216
+ }
217
+ function isSessionAlive(teamName, workerName2) {
218
+ const name = sessionName(teamName, workerName2);
219
+ try {
220
+ (0, import_child_process2.execFileSync)("tmux", ["has-session", "-t", name], { stdio: "pipe", timeout: 5e3 });
221
+ return true;
222
+ } catch {
223
+ return false;
224
+ }
225
+ }
226
+ function listActiveSessions(teamName) {
227
+ const prefix = `${TMUX_SESSION_PREFIX}-${sanitizeName(teamName)}-`;
228
+ try {
229
+ const fmtArgs = ["list-sessions", "-F", "#{session_name}"];
230
+ const shellCmd = "tmux " + fmtArgs.map((a) => `"${a.replace(/"/g, '\\"')}"`).join(" ");
231
+ const output = (0, import_child_process2.execSync)(shellCmd, {
232
+ encoding: "utf-8",
233
+ timeout: 5e3,
234
+ stdio: ["pipe", "pipe", "pipe"]
235
+ });
236
+ return output.trim().split("\n").filter((s) => s.startsWith(prefix)).map((s) => s.slice(prefix.length));
237
+ } catch {
238
+ return [];
239
+ }
240
+ }
241
+ function spawnBridgeInSession(tmuxSession, bridgeScriptPath, configFilePath) {
242
+ const cmd = `node "${bridgeScriptPath}" --config "${configFilePath}"`;
243
+ (0, import_child_process2.execFileSync)("tmux", ["send-keys", "-t", tmuxSession, cmd, "Enter"], { stdio: "pipe", timeout: 5e3 });
244
+ }
261
245
  async function createTeamSession(teamName, workerCount, cwd) {
262
246
  const { execFile: execFile2 } = await import("child_process");
263
247
  const { promisify: promisify2 } = await import("util");
264
248
  const execFileAsync = promisify2(execFile2);
265
- if (!process.env.TMUX) {
266
- throw new Error("Team mode requires running inside tmux. Start one: tmux new-session");
267
- }
249
+ const inTmux = Boolean(process.env.TMUX);
268
250
  const envPaneIdRaw = (process.env.TMUX_PANE ?? "").trim();
269
251
  const envPaneId = /^%\d+$/.test(envPaneIdRaw) ? envPaneIdRaw : "";
270
252
  let sessionAndWindow = "";
271
253
  let leaderPaneId = envPaneId;
272
- if (envPaneId) {
254
+ if (!inTmux) {
255
+ const detachedSessionName = `${TMUX_SESSION_PREFIX}-${sanitizeName(teamName)}-${Date.now().toString(36)}`;
256
+ const detachedResult = await execFileAsync("tmux", [
257
+ "new-session",
258
+ "-d",
259
+ "-P",
260
+ "-F",
261
+ "#S:0 #{pane_id}",
262
+ "-s",
263
+ detachedSessionName,
264
+ "-c",
265
+ cwd
266
+ ]);
267
+ const detachedLine = detachedResult.stdout.trim();
268
+ const detachedMatch = detachedLine.match(/^(\S+)\s+(%\d+)$/);
269
+ if (!detachedMatch) {
270
+ throw new Error(`Failed to create detached tmux session: "${detachedLine}"`);
271
+ }
272
+ sessionAndWindow = detachedMatch[1];
273
+ leaderPaneId = detachedMatch[2];
274
+ }
275
+ if (inTmux && envPaneId) {
273
276
  try {
274
277
  const targetedContextResult = await execFileAsync("tmux", [
275
278
  "display-message",
@@ -364,7 +367,7 @@ async function createTeamSession(teamName, workerCount, cwd) {
364
367
  await new Promise((r) => setTimeout(r, 300));
365
368
  return { sessionName: teamTarget, leaderPaneId, workerPaneIds };
366
369
  }
367
- async function spawnWorkerInPane(sessionName, paneId, config) {
370
+ async function spawnWorkerInPane(sessionName2, paneId, config) {
368
371
  const { execFile: execFile2 } = await import("child_process");
369
372
  const { promisify: promisify2 } = await import("util");
370
373
  const execFileAsync = promisify2(execFile2);
@@ -415,6 +418,23 @@ function paneLooksReady(captured) {
415
418
  );
416
419
  return hasCodexHint;
417
420
  }
421
+ async function waitForPaneReady(paneId, opts = {}) {
422
+ const envTimeout = Number.parseInt(process.env.OMC_SHELL_READY_TIMEOUT_MS ?? "", 10);
423
+ const timeoutMs = Number.isFinite(opts.timeoutMs) && (opts.timeoutMs ?? 0) > 0 ? Number(opts.timeoutMs) : Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : 1e4;
424
+ const pollIntervalMs = Number.isFinite(opts.pollIntervalMs) && (opts.pollIntervalMs ?? 0) > 0 ? Number(opts.pollIntervalMs) : 250;
425
+ const deadline = Date.now() + timeoutMs;
426
+ while (Date.now() < deadline) {
427
+ const captured = await capturePaneAsync(paneId, promisifiedExecFile);
428
+ if (paneLooksReady(captured) && !paneHasActiveTask(captured)) {
429
+ return true;
430
+ }
431
+ await sleep(pollIntervalMs);
432
+ }
433
+ console.warn(
434
+ `[tmux-session] waitForPaneReady: pane ${paneId} timed out after ${timeoutMs}ms (set OMC_SHELL_READY_TIMEOUT_MS to tune)`
435
+ );
436
+ return false;
437
+ }
418
438
  function paneTailContainsLiteralLine(captured, text) {
419
439
  return normalizeTmuxCapture(captured).includes(normalizeTmuxCapture(text));
420
440
  }
@@ -427,7 +447,7 @@ async function paneInCopyMode(paneId, execFileAsync) {
427
447
  }
428
448
  }
429
449
  function shouldAttemptAdaptiveRetry(args) {
430
- if (process.env.OMX_TEAM_AUTO_INTERRUPT_RETRY === "0") return false;
450
+ if (process.env.OMC_TEAM_AUTO_INTERRUPT_RETRY === "0") return false;
431
451
  if (args.retriesAttempted >= 1) return false;
432
452
  if (args.paneInCopyMode) return false;
433
453
  if (!args.paneBusy) return false;
@@ -446,7 +466,7 @@ async function sendToWorker(_sessionName, paneId, message) {
446
466
  const { execFile: execFile2 } = await import("child_process");
447
467
  const { promisify: promisify2 } = await import("util");
448
468
  const execFileAsync = promisify2(execFile2);
449
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
469
+ const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
450
470
  const sendKey = async (key) => {
451
471
  await execFileAsync("tmux", ["send-keys", "-t", paneId, key]);
452
472
  };
@@ -457,28 +477,28 @@ async function sendToWorker(_sessionName, paneId, message) {
457
477
  const paneBusy = paneHasActiveTask(initialCapture);
458
478
  if (paneHasTrustPrompt(initialCapture)) {
459
479
  await sendKey("C-m");
460
- await sleep(120);
480
+ await sleep2(120);
461
481
  await sendKey("C-m");
462
- await sleep(200);
482
+ await sleep2(200);
463
483
  }
464
484
  await execFileAsync("tmux", ["send-keys", "-t", paneId, "-l", "--", message]);
465
- await sleep(150);
485
+ await sleep2(150);
466
486
  const submitRounds = 6;
467
487
  for (let round = 0; round < submitRounds; round++) {
468
- await sleep(100);
488
+ await sleep2(100);
469
489
  if (round === 0 && paneBusy) {
470
490
  await sendKey("Tab");
471
- await sleep(80);
491
+ await sleep2(80);
472
492
  await sendKey("C-m");
473
493
  } else {
474
494
  await sendKey("C-m");
475
- await sleep(200);
495
+ await sleep2(200);
476
496
  await sendKey("C-m");
477
497
  }
478
- await sleep(140);
498
+ await sleep2(140);
479
499
  const checkCapture = await capturePaneAsync(paneId, execFileAsync);
480
500
  if (!paneTailContainsLiteralLine(checkCapture, message)) return true;
481
- await sleep(140);
501
+ await sleep2(140);
482
502
  }
483
503
  if (await paneInCopyMode(paneId, execFileAsync)) {
484
504
  return false;
@@ -496,17 +516,17 @@ async function sendToWorker(_sessionName, paneId, message) {
496
516
  return false;
497
517
  }
498
518
  await sendKey("C-u");
499
- await sleep(80);
519
+ await sleep2(80);
500
520
  if (await paneInCopyMode(paneId, execFileAsync)) {
501
521
  return false;
502
522
  }
503
523
  await execFileAsync("tmux", ["send-keys", "-t", paneId, "-l", "--", message]);
504
- await sleep(120);
524
+ await sleep2(120);
505
525
  for (let round = 0; round < 4; round++) {
506
526
  await sendKey("C-m");
507
- await sleep(180);
527
+ await sleep2(180);
508
528
  await sendKey("C-m");
509
- await sleep(140);
529
+ await sleep2(140);
510
530
  const retryCapture = await capturePaneAsync(paneId, execFileAsync);
511
531
  if (!paneTailContainsLiteralLine(retryCapture, message)) return true;
512
532
  }
@@ -515,13 +535,31 @@ async function sendToWorker(_sessionName, paneId, message) {
515
535
  return false;
516
536
  }
517
537
  await sendKey("C-m");
518
- await sleep(120);
538
+ await sleep2(120);
519
539
  await sendKey("C-m");
520
540
  return true;
521
541
  } catch {
522
542
  return false;
523
543
  }
524
544
  }
545
+ async function injectToLeaderPane(sessionName2, leaderPaneId, message) {
546
+ const prefixed = `[OMC_TMUX_INJECT] ${message}`.slice(0, 200);
547
+ try {
548
+ const { execFile: execFile2 } = await import("child_process");
549
+ const { promisify: promisify2 } = await import("util");
550
+ const execFileAsync = promisify2(execFile2);
551
+ if (await paneInCopyMode(leaderPaneId, execFileAsync)) {
552
+ return false;
553
+ }
554
+ const captured = await capturePaneAsync(leaderPaneId, execFileAsync);
555
+ if (paneHasActiveTask(captured)) {
556
+ await execFileAsync("tmux", ["send-keys", "-t", leaderPaneId, "C-c"]);
557
+ await new Promise((r) => setTimeout(r, 250));
558
+ }
559
+ } catch {
560
+ }
561
+ return sendToWorker(sessionName2, leaderPaneId, prefixed);
562
+ }
525
563
  async function isWorkerAlive(paneId) {
526
564
  try {
527
565
  const { execFile: execFile2 } = await import("child_process");
@@ -539,11 +577,31 @@ async function isWorkerAlive(paneId) {
539
577
  return false;
540
578
  }
541
579
  }
542
- async function killTeamSession(sessionName, workerPaneIds, leaderPaneId) {
580
+ async function killWorkerPanes(opts) {
581
+ const { paneIds, leaderPaneId, teamName, cwd, graceMs = 1e4 } = opts;
582
+ if (!paneIds.length) return;
583
+ const shutdownPath = (0, import_path2.join)(cwd, ".omc", "state", "team", teamName, "shutdown.json");
584
+ try {
585
+ await import_promises.default.writeFile(shutdownPath, JSON.stringify({ requestedAt: Date.now() }));
586
+ await sleep(graceMs);
587
+ } catch {
588
+ }
589
+ const { execFile: execFile2 } = await import("child_process");
590
+ const { promisify: promisify2 } = await import("util");
591
+ const execFileAsync = promisify2(execFile2);
592
+ for (const paneId of paneIds) {
593
+ if (paneId === leaderPaneId) continue;
594
+ try {
595
+ await execFileAsync("tmux", ["kill-pane", "-t", paneId]);
596
+ } catch {
597
+ }
598
+ }
599
+ }
600
+ async function killTeamSession(sessionName2, workerPaneIds, leaderPaneId) {
543
601
  const { execFile: execFile2 } = await import("child_process");
544
602
  const { promisify: promisify2 } = await import("util");
545
603
  const execFileAsync = promisify2(execFile2);
546
- if (sessionName.includes(":")) {
604
+ if (sessionName2.includes(":")) {
547
605
  if (!workerPaneIds?.length) return;
548
606
  for (const id of workerPaneIds) {
549
607
  if (id === leaderPaneId) continue;
@@ -554,81 +612,347 @@ async function killTeamSession(sessionName, workerPaneIds, leaderPaneId) {
554
612
  }
555
613
  return;
556
614
  }
615
+ if (process.env.OMC_TEAM_ALLOW_KILL_CURRENT_SESSION !== "1" && process.env.TMUX) {
616
+ try {
617
+ const current = await tmuxAsync(["display-message", "-p", "#S"]);
618
+ const currentSessionName = current.stdout.trim();
619
+ if (currentSessionName && currentSessionName === sessionName2) {
620
+ return;
621
+ }
622
+ } catch {
623
+ }
624
+ }
557
625
  try {
558
- await execFileAsync("tmux", ["kill-session", "-t", sessionName]);
626
+ await execFileAsync("tmux", ["kill-session", "-t", sessionName2]);
559
627
  } catch {
560
628
  }
561
629
  }
630
+ var import_child_process2, import_path2, import_util, import_promises, sleep, TMUX_SESSION_PREFIX, promisifiedExec, promisifiedExecFile, DANGEROUS_LAUNCH_BINARY_CHARS;
631
+ var init_tmux_session = __esm({
632
+ "src/team/tmux-session.ts"() {
633
+ "use strict";
634
+ import_child_process2 = require("child_process");
635
+ import_path2 = require("path");
636
+ import_util = require("util");
637
+ import_promises = __toESM(require("fs/promises"), 1);
638
+ init_team_name();
639
+ sleep = (ms) => new Promise((r) => setTimeout(r, ms));
640
+ TMUX_SESSION_PREFIX = "omc-team";
641
+ promisifiedExec = (0, import_util.promisify)(import_child_process2.exec);
642
+ promisifiedExecFile = (0, import_util.promisify)(import_child_process2.execFile);
643
+ DANGEROUS_LAUNCH_BINARY_CHARS = /[;&|`$()<>\n\r\t\0]/;
644
+ }
645
+ });
562
646
 
563
- // src/team/worker-bootstrap.ts
564
- var import_promises2 = require("fs/promises");
565
- var import_path4 = require("path");
566
-
567
- // src/agents/prompt-helpers.ts
568
- var import_fs2 = require("fs");
569
- var import_path3 = require("path");
570
- var import_url2 = require("url");
647
+ // src/team/runtime-cli.ts
648
+ var runtime_cli_exports = {};
649
+ __export(runtime_cli_exports, {
650
+ checkWatchdogFailedMarker: () => checkWatchdogFailedMarker,
651
+ getTerminalStatus: () => getTerminalStatus,
652
+ writeResultArtifact: () => writeResultArtifact
653
+ });
654
+ module.exports = __toCommonJS(runtime_cli_exports);
655
+ var import_fs13 = require("fs");
656
+ var import_promises7 = require("fs/promises");
657
+ var import_path16 = require("path");
571
658
 
572
- // src/agents/utils.ts
573
- var import_fs = require("fs");
574
- var import_path2 = require("path");
575
- var import_url = require("url");
659
+ // src/team/runtime.ts
660
+ var import_promises3 = require("fs/promises");
661
+ var import_path10 = require("path");
662
+ var import_fs6 = require("fs");
576
663
 
577
- // src/agents/prompt-helpers.ts
578
- var import_meta = {};
579
- function getPackageDir() {
580
- try {
581
- if (import_meta?.url) {
582
- const __filename = (0, import_url2.fileURLToPath)(import_meta.url);
583
- const __dirname2 = (0, import_path3.dirname)(__filename);
584
- return (0, import_path3.join)(__dirname2, "..", "..");
585
- }
586
- } catch {
664
+ // src/team/model-contract.ts
665
+ var import_child_process = require("child_process");
666
+ var import_path = require("path");
667
+ init_team_name();
668
+ var resolvedPathCache = /* @__PURE__ */ new Map();
669
+ var UNTRUSTED_PATH_PATTERNS = [
670
+ /^\/tmp(\/|$)/,
671
+ /^\/var\/tmp(\/|$)/,
672
+ /^\/dev\/shm(\/|$)/
673
+ ];
674
+ function getTrustedPrefixes() {
675
+ const trusted = [
676
+ "/usr/local/bin",
677
+ "/usr/bin",
678
+ "/opt/homebrew/"
679
+ ];
680
+ const home = process.env.HOME;
681
+ if (home) {
682
+ trusted.push(`${home}/.local/bin`);
683
+ trusted.push(`${home}/.nvm/`);
684
+ trusted.push(`${home}/.cargo/bin`);
685
+ }
686
+ const custom = (process.env.OMC_TRUSTED_CLI_DIRS ?? "").split(":").map((part) => part.trim()).filter(Boolean).filter((part) => (0, import_path.isAbsolute)(part));
687
+ trusted.push(...custom);
688
+ return trusted;
689
+ }
690
+ function isTrustedPrefix(resolvedPath) {
691
+ const normalized = (0, import_path.normalize)(resolvedPath);
692
+ return getTrustedPrefixes().some((prefix) => normalized.startsWith((0, import_path.normalize)(prefix)));
693
+ }
694
+ function assertBinaryName(binary) {
695
+ if (!/^[A-Za-z0-9._-]+$/.test(binary)) {
696
+ throw new Error(`Invalid CLI binary name: ${binary}`);
697
+ }
698
+ }
699
+ function resolveCliBinaryPath(binary) {
700
+ assertBinaryName(binary);
701
+ const cached = resolvedPathCache.get(binary);
702
+ if (cached) return cached;
703
+ const finder = process.platform === "win32" ? "where" : "which";
704
+ const result = (0, import_child_process.spawnSync)(finder, [binary], {
705
+ timeout: 5e3,
706
+ env: process.env
707
+ });
708
+ if (result.status !== 0) {
709
+ throw new Error(`CLI binary '${binary}' not found in PATH`);
587
710
  }
588
- if (typeof __dirname !== "undefined") {
589
- return (0, import_path3.join)(__dirname, "..");
711
+ const stdout = result.stdout?.toString().trim() ?? "";
712
+ const firstLine = stdout.split("\n").map((line) => line.trim()).find(Boolean) ?? "";
713
+ if (!firstLine) {
714
+ throw new Error(`CLI binary '${binary}' not found in PATH`);
590
715
  }
591
- return process.cwd();
592
- }
593
- var _cachedRoles = null;
594
- function getValidAgentRoles() {
595
- if (_cachedRoles) return _cachedRoles;
596
- try {
597
- if (typeof __AGENT_ROLES__ !== "undefined" && Array.isArray(__AGENT_ROLES__) && __AGENT_ROLES__.length > 0) {
598
- _cachedRoles = __AGENT_ROLES__;
599
- return _cachedRoles;
600
- }
601
- } catch {
716
+ const resolvedPath = (0, import_path.normalize)(firstLine);
717
+ if (!(0, import_path.isAbsolute)(resolvedPath)) {
718
+ throw new Error(`Resolved CLI binary '${binary}' to relative path`);
602
719
  }
603
- try {
604
- const agentsDir = (0, import_path3.join)(getPackageDir(), "agents");
605
- const files = (0, import_fs2.readdirSync)(agentsDir);
606
- _cachedRoles = files.filter((f) => f.endsWith(".md")).map((f) => (0, import_path3.basename)(f, ".md")).sort();
607
- } catch (err) {
608
- console.error("[prompt-injection] CRITICAL: Could not scan agents/ directory for role discovery:", err);
609
- _cachedRoles = [];
720
+ if (UNTRUSTED_PATH_PATTERNS.some((pattern) => pattern.test(resolvedPath))) {
721
+ throw new Error(`Resolved CLI binary '${binary}' to untrusted location: ${resolvedPath}`);
610
722
  }
611
- return _cachedRoles;
612
- }
613
- var VALID_AGENT_ROLES = getValidAgentRoles();
614
- function sanitizePromptContent(content, maxLength = 4e3) {
615
- if (!content) return "";
616
- let sanitized = content.length > maxLength ? content.slice(0, maxLength) : content;
617
- if (sanitized.length > 0) {
618
- const lastCode = sanitized.charCodeAt(sanitized.length - 1);
619
- if (lastCode >= 55296 && lastCode <= 56319) {
620
- sanitized = sanitized.slice(0, -1);
621
- }
723
+ if (!isTrustedPrefix(resolvedPath)) {
724
+ console.warn(`[omc:cli-security] CLI binary '${binary}' resolved to non-standard path: ${resolvedPath}`);
622
725
  }
623
- sanitized = sanitized.replace(/<(\/?)(TASK_SUBJECT)[^>]*>/gi, "[$1$2]");
624
- sanitized = sanitized.replace(/<(\/?)(TASK_DESCRIPTION)[^>]*>/gi, "[$1$2]");
625
- sanitized = sanitized.replace(/<(\/?)(INBOX_MESSAGE)[^>]*>/gi, "[$1$2]");
626
- sanitized = sanitized.replace(/<(\/?)(INSTRUCTIONS)[^>]*>/gi, "[$1$2]");
627
- sanitized = sanitized.replace(/<(\/?)(SYSTEM)[^>]*>/gi, "[$1$2]");
628
- return sanitized;
726
+ resolvedPathCache.set(binary, resolvedPath);
727
+ return resolvedPath;
728
+ }
729
+ var CONTRACTS = {
730
+ claude: {
731
+ agentType: "claude",
732
+ binary: "claude",
733
+ installInstructions: "Install Claude CLI: https://claude.ai/download",
734
+ buildLaunchArgs(model, extraFlags = []) {
735
+ const args = ["--dangerously-skip-permissions"];
736
+ if (model) args.push("--model", model);
737
+ return [...args, ...extraFlags];
738
+ },
739
+ parseOutput(rawOutput) {
740
+ return rawOutput.trim();
741
+ }
742
+ },
743
+ codex: {
744
+ agentType: "codex",
745
+ binary: "codex",
746
+ installInstructions: "Install Codex CLI: npm install -g @openai/codex",
747
+ supportsPromptMode: true,
748
+ // Codex accepts prompt as a positional argument (no flag needed):
749
+ // codex [OPTIONS] [PROMPT]
750
+ buildLaunchArgs(model, extraFlags = []) {
751
+ const args = ["--dangerously-bypass-approvals-and-sandbox"];
752
+ if (model) args.push("--model", model);
753
+ return [...args, ...extraFlags];
754
+ },
755
+ parseOutput(rawOutput) {
756
+ const lines = rawOutput.trim().split("\n").filter(Boolean);
757
+ for (let i = lines.length - 1; i >= 0; i--) {
758
+ try {
759
+ const parsed = JSON.parse(lines[i]);
760
+ if (parsed.type === "message" && parsed.role === "assistant") {
761
+ return parsed.content ?? rawOutput;
762
+ }
763
+ if (parsed.type === "result" || parsed.output) {
764
+ return parsed.output ?? parsed.result ?? rawOutput;
765
+ }
766
+ } catch {
767
+ }
768
+ }
769
+ return rawOutput.trim();
770
+ }
771
+ },
772
+ gemini: {
773
+ agentType: "gemini",
774
+ binary: "gemini",
775
+ installInstructions: "Install Gemini CLI: npm install -g @google/gemini-cli",
776
+ supportsPromptMode: true,
777
+ promptModeFlag: "-i",
778
+ buildLaunchArgs(model, extraFlags = []) {
779
+ const args = ["--approval-mode", "yolo"];
780
+ if (model) args.push("--model", model);
781
+ return [...args, ...extraFlags];
782
+ },
783
+ parseOutput(rawOutput) {
784
+ return rawOutput.trim();
785
+ }
786
+ }
787
+ };
788
+ function getContract(agentType) {
789
+ const contract = CONTRACTS[agentType];
790
+ if (!contract) {
791
+ throw new Error(`Unknown agent type: ${agentType}. Supported: ${Object.keys(CONTRACTS).join(", ")}`);
792
+ }
793
+ return contract;
794
+ }
795
+ function validateBinaryRef(binary) {
796
+ if ((0, import_path.isAbsolute)(binary)) return;
797
+ if (/^[A-Za-z0-9._-]+$/.test(binary)) return;
798
+ throw new Error(`Unsafe CLI binary reference: ${binary}`);
799
+ }
800
+ function resolveBinaryPath(binary) {
801
+ validateBinaryRef(binary);
802
+ if ((0, import_path.isAbsolute)(binary)) return binary;
803
+ try {
804
+ const resolver = process.platform === "win32" ? "where" : "which";
805
+ const result = (0, import_child_process.spawnSync)(resolver, [binary], { timeout: 5e3, encoding: "utf8" });
806
+ if (result.status !== 0) return binary;
807
+ const lines = result.stdout?.split(/\r?\n/).map((line) => line.trim()).filter(Boolean) ?? [];
808
+ const firstPath = lines[0];
809
+ const isResolvedAbsolute = !!firstPath && ((0, import_path.isAbsolute)(firstPath) || import_path.win32.isAbsolute(firstPath));
810
+ return isResolvedAbsolute ? firstPath : binary;
811
+ } catch {
812
+ return binary;
813
+ }
814
+ }
815
+ function resolveValidatedBinaryPath(agentType) {
816
+ const contract = getContract(agentType);
817
+ return resolveCliBinaryPath(contract.binary);
818
+ }
819
+ function buildLaunchArgs(agentType, config) {
820
+ return getContract(agentType).buildLaunchArgs(config.model, config.extraFlags);
821
+ }
822
+ function buildWorkerArgv(agentType, config) {
823
+ validateTeamName(config.teamName);
824
+ const contract = getContract(agentType);
825
+ const binary = config.resolvedBinaryPath ? (() => {
826
+ validateBinaryRef(config.resolvedBinaryPath);
827
+ return config.resolvedBinaryPath;
828
+ })() : resolveBinaryPath(contract.binary);
829
+ const args = buildLaunchArgs(agentType, config);
830
+ return [binary, ...args];
831
+ }
832
+ function getWorkerEnv(teamName, workerName2, agentType) {
833
+ validateTeamName(teamName);
834
+ return {
835
+ OMC_TEAM_WORKER: `${teamName}/${workerName2}`,
836
+ OMC_TEAM_NAME: teamName,
837
+ OMC_WORKER_AGENT_TYPE: agentType
838
+ };
839
+ }
840
+ function isPromptModeAgent(agentType) {
841
+ const contract = getContract(agentType);
842
+ return !!contract.supportsPromptMode;
843
+ }
844
+ function getPromptModeArgs(agentType, instruction) {
845
+ const contract = getContract(agentType);
846
+ if (!contract.supportsPromptMode) {
847
+ return [];
848
+ }
849
+ if (contract.promptModeFlag) {
850
+ return [contract.promptModeFlag, instruction];
851
+ }
852
+ return [instruction];
853
+ }
854
+
855
+ // src/team/runtime.ts
856
+ init_team_name();
857
+ init_tmux_session();
858
+
859
+ // src/team/worker-bootstrap.ts
860
+ var import_promises2 = require("fs/promises");
861
+ var import_path5 = require("path");
862
+
863
+ // src/agents/prompt-helpers.ts
864
+ var import_fs2 = require("fs");
865
+ var import_path4 = require("path");
866
+ var import_url2 = require("url");
867
+
868
+ // src/agents/utils.ts
869
+ var import_fs = require("fs");
870
+ var import_path3 = require("path");
871
+ var import_url = require("url");
872
+
873
+ // src/agents/prompt-helpers.ts
874
+ var import_meta = {};
875
+ function getPackageDir() {
876
+ if (typeof __dirname !== "undefined" && __dirname) {
877
+ const currentDirName = (0, import_path4.basename)(__dirname);
878
+ const parentDirName = (0, import_path4.basename)((0, import_path4.dirname)(__dirname));
879
+ if (currentDirName === "bridge") {
880
+ return (0, import_path4.join)(__dirname, "..");
881
+ }
882
+ if (currentDirName === "agents" && (parentDirName === "src" || parentDirName === "dist")) {
883
+ return (0, import_path4.join)(__dirname, "..", "..");
884
+ }
885
+ }
886
+ try {
887
+ const __filename = (0, import_url2.fileURLToPath)(import_meta.url);
888
+ const __dirname2 = (0, import_path4.dirname)(__filename);
889
+ return (0, import_path4.join)(__dirname2, "..", "..");
890
+ } catch {
891
+ }
892
+ return process.cwd();
893
+ }
894
+ var _cachedRoles = null;
895
+ function getValidAgentRoles() {
896
+ if (_cachedRoles) return _cachedRoles;
897
+ try {
898
+ if (typeof __AGENT_ROLES__ !== "undefined" && Array.isArray(__AGENT_ROLES__) && __AGENT_ROLES__.length > 0) {
899
+ _cachedRoles = __AGENT_ROLES__;
900
+ return _cachedRoles;
901
+ }
902
+ } catch {
903
+ }
904
+ try {
905
+ const agentsDir = (0, import_path4.join)(getPackageDir(), "agents");
906
+ const files = (0, import_fs2.readdirSync)(agentsDir);
907
+ _cachedRoles = files.filter((f) => f.endsWith(".md")).map((f) => (0, import_path4.basename)(f, ".md")).sort();
908
+ } catch (err) {
909
+ console.error("[prompt-injection] CRITICAL: Could not scan agents/ directory for role discovery:", err);
910
+ _cachedRoles = [];
911
+ }
912
+ return _cachedRoles;
913
+ }
914
+ var VALID_AGENT_ROLES = getValidAgentRoles();
915
+ function sanitizePromptContent(content, maxLength = 4e3) {
916
+ if (!content) return "";
917
+ let sanitized = content.length > maxLength ? content.slice(0, maxLength) : content;
918
+ if (sanitized.length > 0) {
919
+ const lastCode = sanitized.charCodeAt(sanitized.length - 1);
920
+ if (lastCode >= 55296 && lastCode <= 56319) {
921
+ sanitized = sanitized.slice(0, -1);
922
+ }
923
+ }
924
+ sanitized = sanitized.replace(/<(\/?)(TASK_SUBJECT)[^>]*>/gi, "[$1$2]");
925
+ sanitized = sanitized.replace(/<(\/?)(TASK_DESCRIPTION)[^>]*>/gi, "[$1$2]");
926
+ sanitized = sanitized.replace(/<(\/?)(INBOX_MESSAGE)[^>]*>/gi, "[$1$2]");
927
+ sanitized = sanitized.replace(/<(\/?)(INSTRUCTIONS)[^>]*>/gi, "[$1$2]");
928
+ sanitized = sanitized.replace(/<(\/?)(SYSTEM)[^>]*>/gi, "[$1$2]");
929
+ return sanitized;
629
930
  }
630
931
 
631
932
  // src/team/worker-bootstrap.ts
933
+ function agentTypeGuidance(agentType) {
934
+ switch (agentType) {
935
+ case "codex":
936
+ return [
937
+ "### Agent-Type Guidance (codex)",
938
+ "- Prefer short, explicit `omc team api ... --json` commands and parse outputs before next step.",
939
+ "- If a command fails, report the exact stderr to leader-fixed before retrying."
940
+ ].join("\n");
941
+ case "gemini":
942
+ return [
943
+ "### Agent-Type Guidance (gemini)",
944
+ "- Execute task work in small, verifiable increments and report each milestone to leader-fixed.",
945
+ "- Keep commit-sized changes scoped to assigned files only; no broad refactors."
946
+ ].join("\n");
947
+ case "claude":
948
+ default:
949
+ return [
950
+ "### Agent-Type Guidance (claude)",
951
+ "- Keep reasoning focused on assigned task IDs and send concise progress acks to leader-fixed.",
952
+ "- Before any risky command, send a blocker/proposal message to leader-fixed and wait for updated inbox instructions."
953
+ ].join("\n");
954
+ }
955
+ }
632
956
  function generateWorkerOverlay(params) {
633
957
  const { teamName, workerName: workerName2, agentType, tasks, bootstrapInstructions } = params;
634
958
  const sanitizedTasks = tasks.map((t) => ({
@@ -639,11 +963,15 @@ function generateWorkerOverlay(params) {
639
963
  const sentinelPath = `.omc/state/team/${teamName}/workers/${workerName2}/.ready`;
640
964
  const heartbeatPath = `.omc/state/team/${teamName}/workers/${workerName2}/heartbeat.json`;
641
965
  const inboxPath = `.omc/state/team/${teamName}/workers/${workerName2}/inbox.md`;
966
+ const statusPath = `.omc/state/team/${teamName}/workers/${workerName2}/status.json`;
642
967
  const taskDir = `.omc/state/team/${teamName}/tasks`;
643
- const donePath = `.omc/state/team/${teamName}/workers/${workerName2}/done.json`;
644
- const taskList = sanitizedTasks.length > 0 ? sanitizedTasks.map((t) => `- **Task ${t.id}**: ${t.subject}`).join("\n") : "- No tasks assigned yet. Check your inbox for assignments.";
968
+ const taskList = sanitizedTasks.length > 0 ? sanitizedTasks.map((t) => `- **Task ${t.id}**: ${t.subject}
969
+ Description: ${t.description}
970
+ Status: pending`).join("\n") : "- No tasks assigned yet. Check your inbox for assignments.";
645
971
  return `# Team Worker Protocol
646
972
 
973
+ You are a **team worker**, not the team leader. Operate strictly within worker protocol.
974
+
647
975
  ## FIRST ACTION REQUIRED
648
976
  Before doing anything else, write your ready sentinel file:
649
977
  \`\`\`bash
@@ -659,89 +987,132 @@ mkdir -p $(dirname ${sentinelPath}) && touch ${sentinelPath}
659
987
  ## Your Tasks
660
988
  ${taskList}
661
989
 
662
- ## Task Claiming Protocol
663
- To claim a task, update the task file atomically:
664
- 1. Read task from: ${taskDir}/{taskId}.json
665
- 2. Update status to "in_progress", set owner to "${workerName2}"
666
- 3. Write back to task file
667
- 4. Do the work
668
- 5. Update status to "completed", write result to task file
990
+ ## Task Lifecycle Protocol (CLI API)
991
+ Use the CLI API for all task lifecycle operations. Do NOT directly edit task files.
992
+
993
+ 1. Read your task file at \`${taskDir}/task-{taskId}.json\`
994
+ 2. Task id format: State/CLI APIs use task_id: "<id>" (example: "1"), not "task-1"
995
+ 3. Claim a task via CLI interop:
996
+ \`omc team api claim-task --input "{\\"team_name\\":\\"${teamName}\\",\\"task_id\\":\\"<id>\\",\\"worker\\":\\"${workerName2}\\"}" --json\`
997
+ 4. Do the work described in the task
998
+ 5. On completion, transition via CLI interop (use the claim_token from step 3):
999
+ \`omc team api transition-task-status --input "{\\"team_name\\":\\"${teamName}\\",\\"task_id\\":\\"<id>\\",\\"from\\":\\"in_progress\\",\\"to\\":\\"completed\\",\\"claim_token\\":\\"<claim_token from step 3>\\"}" --json\`
1000
+ 6. On failure, transition to "failed" with error (use the claim_token from step 3):
1001
+ \`omc team api transition-task-status --input "{\\"team_name\\":\\"${teamName}\\",\\"task_id\\":\\"<id>\\",\\"from\\":\\"in_progress\\",\\"to\\":\\"failed\\",\\"claim_token\\":\\"<claim_token from step 3>\\"}" --json\`
1002
+ 7. Use \`omc team api release-task-claim --json\` only for rollback to pending
669
1003
 
670
1004
  ## Communication Protocol
671
1005
  - **Inbox**: Read ${inboxPath} for new instructions
1006
+ - **Status**: Write to ${statusPath}:
1007
+ \`\`\`json
1008
+ {"state": "idle", "updated_at": "<ISO timestamp>"}
1009
+ \`\`\`
1010
+ States: "idle" | "working" | "blocked" | "done" | "failed"
672
1011
  - **Heartbeat**: Update ${heartbeatPath} every few minutes:
673
1012
  \`\`\`json
674
- {"workerName":"${workerName2}","status":"working","updatedAt":"<ISO timestamp>","currentTaskId":"<id or null>"}
1013
+ {"pid":<pid>,"last_turn_at":"<ISO timestamp>","turn_count":<n>,"alive":true}
675
1014
  \`\`\`
676
1015
 
677
- ## Task Completion Protocol
678
- When you finish a task (success or failure), write a done signal file:
679
- - Path: ${donePath}
680
- - Content (JSON, one line):
681
- {"taskId":"<id>","status":"completed","summary":"<1-2 sentence summary>","completedAt":"<ISO timestamp>"}
682
- - For failures, set status to "failed" and include the error in summary.
683
- - Use "completed" or "failed" only for status.
1016
+ ## Message Protocol
1017
+ Send messages via CLI API:
1018
+ - To leader: \`omc team api send-message --input "{\\"team_name\\":\\"${teamName}\\",\\"from_worker\\":\\"${workerName2}\\",\\"to_worker\\":\\"leader-fixed\\",\\"body\\":\\"<message>\\"}" --json\`
1019
+ - Check mailbox: \`omc team api mailbox-list --input "{\\"team_name\\":\\"${teamName}\\",\\"worker\\":\\"${workerName2}\\"}" --json\`
1020
+ - Mark delivered: \`omc team api mailbox-mark-delivered --input "{\\"team_name\\":\\"${teamName}\\",\\"worker\\":\\"${workerName2}\\",\\"message_id\\":\\"<id>\\"}" --json\`
1021
+
1022
+ ## Startup Handshake (Required)
1023
+ Before doing any task work, send exactly one startup ACK to the leader:
1024
+ \`omc team api send-message --input "{\\"team_name\\":\\"${teamName}\\",\\"from_worker\\":\\"${workerName2}\\",\\"to_worker\\":\\"leader-fixed\\",\\"body\\":\\"ACK: ${workerName2} initialized\\"}" --json\`
684
1025
 
685
1026
  ## Shutdown Protocol
686
- When you see a shutdown request (check .omc/state/team/${teamName}/shutdown.json):
687
- 1. Finish your current task if close to completion
688
- 2. Write an ACK file: .omc/state/team/${teamName}/workers/${workerName2}/shutdown-ack.json
689
- 3. Exit
1027
+ When you see a shutdown request in your inbox:
1028
+ 1. Write your decision to: .omc/state/team/${teamName}/workers/${workerName2}/shutdown-ack.json
1029
+ 2. Format:
1030
+ - Accept: {"status":"accept","reason":"ok","updated_at":"<iso>"}
1031
+ - Reject: {"status":"reject","reason":"still working","updated_at":"<iso>"}
1032
+ 3. Exit your session
1033
+
1034
+ ## Rules
1035
+ - You are NOT the leader. Never run leader orchestration workflows.
1036
+ - Do NOT edit files outside the paths listed in your task description
1037
+ - Do NOT write lifecycle fields (status, owner, result, error) directly in task files; use CLI API
1038
+ - Do NOT spawn sub-agents. Complete work in this worker session only.
1039
+ - Do NOT create tmux panes/sessions (\`tmux split-window\`, \`tmux new-session\`, etc.).
1040
+ - Do NOT run team spawning/orchestration commands (for example: \`omc team ...\`, \`omx team ...\`, \`$team\`, \`$ultrawork\`, \`$autopilot\`, \`$ralph\`).
1041
+ - Worker-allowed control surface is only: \`omc team api ... --json\` (and equivalent \`omx team api ... --json\` where configured).
1042
+ - If blocked, write {"state": "blocked", "reason": "..."} to your status file
1043
+
1044
+ ${agentTypeGuidance(agentType)}
690
1045
 
691
1046
  ${bootstrapInstructions ? `## Additional Instructions
692
1047
  ${bootstrapInstructions}
693
1048
  ` : ""}`;
694
1049
  }
695
1050
  async function composeInitialInbox(teamName, workerName2, content, cwd) {
696
- const inboxPath = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/workers/${workerName2}/inbox.md`);
697
- await (0, import_promises2.mkdir)((0, import_path4.dirname)(inboxPath), { recursive: true });
1051
+ const inboxPath = (0, import_path5.join)(cwd, `.omc/state/team/${teamName}/workers/${workerName2}/inbox.md`);
1052
+ await (0, import_promises2.mkdir)((0, import_path5.dirname)(inboxPath), { recursive: true });
698
1053
  await (0, import_promises2.writeFile)(inboxPath, content, "utf-8");
699
1054
  }
700
1055
  async function ensureWorkerStateDir(teamName, workerName2, cwd) {
701
- const workerDir = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/workers/${workerName2}`);
1056
+ const workerDir = (0, import_path5.join)(cwd, `.omc/state/team/${teamName}/workers/${workerName2}`);
702
1057
  await (0, import_promises2.mkdir)(workerDir, { recursive: true });
703
- const mailboxDir = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/mailbox`);
1058
+ const mailboxDir = (0, import_path5.join)(cwd, `.omc/state/team/${teamName}/mailbox`);
704
1059
  await (0, import_promises2.mkdir)(mailboxDir, { recursive: true });
705
- const tasksDir = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/tasks`);
1060
+ const tasksDir = (0, import_path5.join)(cwd, `.omc/state/team/${teamName}/tasks`);
706
1061
  await (0, import_promises2.mkdir)(tasksDir, { recursive: true });
707
1062
  }
708
1063
  async function writeWorkerOverlay(params) {
709
1064
  const { teamName, workerName: workerName2, cwd } = params;
710
1065
  const overlay = generateWorkerOverlay(params);
711
- const overlayPath = (0, import_path4.join)(cwd, `.omc/state/team/${teamName}/workers/${workerName2}/AGENTS.md`);
712
- await (0, import_promises2.mkdir)((0, import_path4.dirname)(overlayPath), { recursive: true });
1066
+ const overlayPath = (0, import_path5.join)(cwd, `.omc/state/team/${teamName}/workers/${workerName2}/AGENTS.md`);
1067
+ await (0, import_promises2.mkdir)((0, import_path5.dirname)(overlayPath), { recursive: true });
713
1068
  await (0, import_promises2.writeFile)(overlayPath, overlay, "utf-8");
714
1069
  return overlayPath;
715
1070
  }
716
1071
 
717
1072
  // src/team/task-file-ops.ts
718
1073
  var import_fs5 = require("fs");
719
- var import_path8 = require("path");
1074
+ var import_path9 = require("path");
720
1075
 
721
1076
  // src/utils/paths.ts
722
- var import_path5 = require("path");
1077
+ var import_path6 = require("path");
723
1078
  var import_fs3 = require("fs");
724
1079
  var import_os = require("os");
1080
+ function getConfigDir2() {
1081
+ if (process.platform === "win32") {
1082
+ return process.env.APPDATA || (0, import_path6.join)((0, import_os.homedir)(), "AppData", "Roaming");
1083
+ }
1084
+ return process.env.XDG_CONFIG_HOME || (0, import_path6.join)((0, import_os.homedir)(), ".config");
1085
+ }
725
1086
  var STALE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
726
1087
 
1088
+ // src/team/task-file-ops.ts
1089
+ init_tmux_session();
1090
+
727
1091
  // src/team/fs-utils.ts
728
1092
  var import_fs4 = require("fs");
729
- var import_path6 = require("path");
1093
+ var import_path7 = require("path");
1094
+ function atomicWriteJson(filePath, data, mode = 384) {
1095
+ const dir = (0, import_path7.dirname)(filePath);
1096
+ if (!(0, import_fs4.existsSync)(dir)) (0, import_fs4.mkdirSync)(dir, { recursive: true, mode: 448 });
1097
+ const tmpPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
1098
+ (0, import_fs4.writeFileSync)(tmpPath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode });
1099
+ (0, import_fs4.renameSync)(tmpPath, filePath);
1100
+ }
730
1101
  function ensureDirWithMode(dirPath, mode = 448) {
731
1102
  if (!(0, import_fs4.existsSync)(dirPath)) (0, import_fs4.mkdirSync)(dirPath, { recursive: true, mode });
732
1103
  }
733
1104
  function canonicalizePath(p) {
734
- const absInput = (0, import_path6.resolve)(p);
1105
+ const absInput = (0, import_path7.resolve)(p);
735
1106
  const tail = [];
736
1107
  let probe = absInput;
737
1108
  while (true) {
738
1109
  try {
739
1110
  const realBase = (0, import_fs4.realpathSync)(probe);
740
- return tail.reduce((acc, seg) => (0, import_path6.resolve)(acc, seg), realBase);
1111
+ return tail.reduce((acc, seg) => (0, import_path7.resolve)(acc, seg), realBase);
741
1112
  } catch {
742
- const parent = (0, import_path6.dirname)(probe);
1113
+ const parent = (0, import_path7.dirname)(probe);
743
1114
  if (parent === probe) return absInput;
744
- tail.unshift((0, import_path6.basename)(probe));
1115
+ tail.unshift((0, import_path7.basename)(probe));
745
1116
  probe = parent;
746
1117
  }
747
1118
  }
@@ -749,20 +1120,26 @@ function canonicalizePath(p) {
749
1120
  function validateResolvedPath(resolvedPath, expectedBase) {
750
1121
  const absResolved = canonicalizePath(resolvedPath);
751
1122
  const absBase = canonicalizePath(expectedBase);
752
- const rel = (0, import_path6.relative)(absBase, absResolved);
753
- if (rel !== "" && (rel.startsWith("..") || (0, import_path6.isAbsolute)(rel) || (0, import_path6.resolve)(absBase, rel) !== absResolved)) {
1123
+ const rel = (0, import_path7.relative)(absBase, absResolved);
1124
+ if (rel !== "" && (rel.startsWith("..") || (0, import_path7.isAbsolute)(rel) || (0, import_path7.resolve)(absBase, rel) !== absResolved)) {
754
1125
  throw new Error(`Path traversal detected: "${resolvedPath}" escapes base "${expectedBase}"`);
755
1126
  }
756
1127
  }
757
1128
 
758
1129
  // src/team/state-paths.ts
759
- var import_path7 = require("path");
1130
+ var import_path8 = require("path");
1131
+ function normalizeTaskFileStem(taskId) {
1132
+ const trimmed = String(taskId).trim().replace(/\.json$/i, "");
1133
+ if (/^task-\d+$/.test(trimmed)) return trimmed;
1134
+ if (/^\d+$/.test(trimmed)) return `task-${trimmed}`;
1135
+ return trimmed;
1136
+ }
760
1137
  var TeamPaths = {
761
1138
  root: (teamName) => `.omc/state/team/${teamName}`,
762
1139
  config: (teamName) => `.omc/state/team/${teamName}/config.json`,
763
1140
  shutdown: (teamName) => `.omc/state/team/${teamName}/shutdown.json`,
764
1141
  tasks: (teamName) => `.omc/state/team/${teamName}/tasks`,
765
- taskFile: (teamName, taskId) => `.omc/state/team/${teamName}/tasks/${taskId}.json`,
1142
+ taskFile: (teamName, taskId) => `.omc/state/team/${teamName}/tasks/${normalizeTaskFileStem(taskId)}.json`,
766
1143
  workers: (teamName) => `.omc/state/team/${teamName}/workers`,
767
1144
  workerDir: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}`,
768
1145
  heartbeat: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/heartbeat.json`,
@@ -771,14 +1148,35 @@ var TeamPaths = {
771
1148
  ready: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/.ready`,
772
1149
  overlay: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/AGENTS.md`,
773
1150
  shutdownAck: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/shutdown-ack.json`,
774
- done: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/done.json`,
775
- mailbox: (teamName, workerName2) => `.omc/state/team/${teamName}/mailbox/${workerName2}.jsonl`
1151
+ mailbox: (teamName, workerName2) => `.omc/state/team/${teamName}/mailbox/${workerName2}.json`,
1152
+ mailboxLockDir: (teamName, workerName2) => `.omc/state/team/${teamName}/mailbox/.lock-${workerName2}`,
1153
+ dispatchRequests: (teamName) => `.omc/state/team/${teamName}/dispatch/requests.json`,
1154
+ dispatchLockDir: (teamName) => `.omc/state/team/${teamName}/dispatch/.lock`,
1155
+ workerStatus: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/status.json`,
1156
+ workerIdleNotify: (teamName) => `.omc/state/team/${teamName}/worker-idle-notify.json`,
1157
+ workerPrevNotifyState: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/prev-notify-state.json`,
1158
+ events: (teamName) => `.omc/state/team/${teamName}/events.jsonl`,
1159
+ approval: (teamName, taskId) => `.omc/state/team/${teamName}/approvals/${taskId}.json`,
1160
+ manifest: (teamName) => `.omc/state/team/${teamName}/manifest.json`,
1161
+ monitorSnapshot: (teamName) => `.omc/state/team/${teamName}/monitor-snapshot.json`,
1162
+ summarySnapshot: (teamName) => `.omc/state/team/${teamName}/summary-snapshot.json`,
1163
+ phaseState: (teamName) => `.omc/state/team/${teamName}/phase-state.json`,
1164
+ scalingLock: (teamName) => `.omc/state/team/${teamName}/.scaling-lock`,
1165
+ workerIdentity: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/identity.json`,
1166
+ workerAgentsMd: (teamName) => `.omc/state/team/${teamName}/worker-agents.md`,
1167
+ shutdownRequest: (teamName, workerName2) => `.omc/state/team/${teamName}/workers/${workerName2}/shutdown-request.json`
776
1168
  };
1169
+ function absPath(cwd, relativePath) {
1170
+ return (0, import_path8.join)(cwd, relativePath);
1171
+ }
1172
+ function teamStateRoot(cwd, teamName) {
1173
+ return (0, import_path8.join)(cwd, TeamPaths.root(teamName));
1174
+ }
777
1175
  function getTaskStoragePath(cwd, teamName, taskId) {
778
1176
  if (taskId !== void 0) {
779
- return (0, import_path7.join)(cwd, TeamPaths.taskFile(teamName, taskId));
1177
+ return (0, import_path8.join)(cwd, TeamPaths.taskFile(teamName, taskId));
780
1178
  }
781
- return (0, import_path7.join)(cwd, TeamPaths.tasks(teamName));
1179
+ return (0, import_path8.join)(cwd, TeamPaths.tasks(teamName));
782
1180
  }
783
1181
 
784
1182
  // src/team/task-file-ops.ts
@@ -797,7 +1195,7 @@ function acquireTaskLock(teamName, taskId, opts) {
797
1195
  const staleLockMs = opts?.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
798
1196
  const dir = canonicalTasksDir(teamName, opts?.cwd);
799
1197
  ensureDirWithMode(dir);
800
- const lockPath = (0, import_path8.join)(dir, `${sanitizeTaskId(taskId)}.lock`);
1198
+ const lockPath = (0, import_path9.join)(dir, `${sanitizeTaskId(taskId)}.lock`);
801
1199
  for (let attempt = 0; attempt < 2; attempt++) {
802
1200
  try {
803
1201
  const fd = (0, import_fs5.openSync)(lockPath, import_fs5.constants.O_CREAT | import_fs5.constants.O_EXCL | import_fs5.constants.O_WRONLY, 384);
@@ -868,9 +1266,35 @@ function sanitizeTaskId(taskId) {
868
1266
  function canonicalTasksDir(teamName, cwd) {
869
1267
  const root = cwd ?? process.cwd();
870
1268
  const dir = getTaskStoragePath(root, sanitizeName(teamName));
871
- validateResolvedPath(dir, (0, import_path8.join)(root, ".omc", "state", "team"));
1269
+ validateResolvedPath(dir, (0, import_path9.join)(root, ".omc", "state", "team"));
872
1270
  return dir;
873
1271
  }
1272
+ function failureSidecarPath(teamName, taskId, cwd) {
1273
+ return (0, import_path9.join)(canonicalTasksDir(teamName, cwd), `${sanitizeTaskId(taskId)}.failure.json`);
1274
+ }
1275
+ function writeTaskFailure(teamName, taskId, error, opts) {
1276
+ const filePath = failureSidecarPath(teamName, taskId, opts?.cwd);
1277
+ const existing = readTaskFailure(teamName, taskId, opts);
1278
+ const sidecar = {
1279
+ taskId,
1280
+ lastError: error,
1281
+ retryCount: existing ? existing.retryCount + 1 : 1,
1282
+ lastFailedAt: (/* @__PURE__ */ new Date()).toISOString()
1283
+ };
1284
+ atomicWriteJson(filePath, sidecar);
1285
+ return sidecar;
1286
+ }
1287
+ function readTaskFailure(teamName, taskId, opts) {
1288
+ const filePath = failureSidecarPath(teamName, taskId, opts?.cwd);
1289
+ if (!(0, import_fs5.existsSync)(filePath)) return null;
1290
+ try {
1291
+ const raw = (0, import_fs5.readFileSync)(filePath, "utf-8");
1292
+ return JSON.parse(raw);
1293
+ } catch {
1294
+ return null;
1295
+ }
1296
+ }
1297
+ var DEFAULT_MAX_TASK_RETRIES = 5;
874
1298
 
875
1299
  // src/team/runtime.ts
876
1300
  function workerName(index) {
@@ -878,19 +1302,37 @@ function workerName(index) {
878
1302
  }
879
1303
  function stateRoot(cwd, teamName) {
880
1304
  validateTeamName(teamName);
881
- return (0, import_path9.join)(cwd, `.omc/state/team/${teamName}`);
1305
+ return (0, import_path10.join)(cwd, `.omc/state/team/${teamName}`);
882
1306
  }
883
1307
  async function writeJson(filePath, data) {
884
- await (0, import_promises3.mkdir)((0, import_path9.join)(filePath, ".."), { recursive: true });
1308
+ await (0, import_promises3.mkdir)((0, import_path10.join)(filePath, ".."), { recursive: true });
885
1309
  await (0, import_promises3.writeFile)(filePath, JSON.stringify(data, null, 2), "utf-8");
886
1310
  }
887
1311
  async function readJsonSafe(filePath) {
888
- try {
889
- const content = await (0, import_promises3.readFile)(filePath, "utf-8");
890
- return JSON.parse(content);
891
- } catch {
892
- return null;
1312
+ const isDoneSignalPath = filePath.endsWith("done.json");
1313
+ const maxAttempts = isDoneSignalPath ? 4 : 1;
1314
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1315
+ try {
1316
+ const content = await (0, import_promises3.readFile)(filePath, "utf-8");
1317
+ try {
1318
+ return JSON.parse(content);
1319
+ } catch {
1320
+ if (!isDoneSignalPath || attempt === maxAttempts) {
1321
+ return null;
1322
+ }
1323
+ }
1324
+ } catch (error) {
1325
+ const isMissingDoneSignal = isDoneSignalPath && typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
1326
+ if (isMissingDoneSignal) {
1327
+ return null;
1328
+ }
1329
+ if (!isDoneSignalPath || attempt === maxAttempts) {
1330
+ return null;
1331
+ }
1332
+ }
1333
+ await new Promise((resolve5) => setTimeout(resolve5, 25));
893
1334
  }
1335
+ return null;
894
1336
  }
895
1337
  function parseWorkerIndex(workerNameValue) {
896
1338
  const match = workerNameValue.match(/^worker-(\d+)$/);
@@ -899,13 +1341,13 @@ function parseWorkerIndex(workerNameValue) {
899
1341
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
900
1342
  }
901
1343
  function taskPath(root, taskId) {
902
- return (0, import_path9.join)(root, "tasks", `${taskId}.json`);
1344
+ return (0, import_path10.join)(root, "tasks", `${taskId}.json`);
903
1345
  }
904
1346
  async function writePanesTrackingFileIfPresent(runtime) {
905
1347
  const jobId = process.env.OMC_JOB_ID;
906
1348
  const omcJobsDir = process.env.OMC_JOBS_DIR;
907
1349
  if (!jobId || !omcJobsDir) return;
908
- const panesPath = (0, import_path9.join)(omcJobsDir, `${jobId}-panes.json`);
1350
+ const panesPath = (0, import_path10.join)(omcJobsDir, `${jobId}-panes.json`);
909
1351
  const tempPath = `${panesPath}.tmp`;
910
1352
  await (0, import_promises3.writeFile)(
911
1353
  tempPath,
@@ -932,48 +1374,87 @@ async function markTaskInProgress(root, taskId, owner, teamName, cwd) {
932
1374
  }, { cwd });
933
1375
  return result ?? false;
934
1376
  }
935
- async function resetTaskToPending(root, taskId) {
936
- const task = await readTask(root, taskId);
937
- if (!task) return;
938
- task.status = "pending";
939
- task.owner = null;
940
- task.assignedAt = void 0;
941
- await writeTask(root, task);
942
- }
943
- async function markTaskFromDone(root, taskId, status, summary) {
944
- const task = await readTask(root, taskId);
945
- if (!task) return;
946
- task.status = status;
947
- task.result = summary;
948
- task.summary = summary;
949
- if (status === "completed") {
950
- task.completedAt = (/* @__PURE__ */ new Date()).toISOString();
951
- } else {
952
- task.failedAt = (/* @__PURE__ */ new Date()).toISOString();
953
- }
954
- await writeTask(root, task);
955
- }
956
- async function markTaskFailedDeadPane(root, taskId, workerNameValue) {
957
- const task = await readTask(root, taskId);
958
- if (!task) return;
959
- task.status = "failed";
960
- task.owner = workerNameValue;
961
- task.summary = `Worker pane died before done.json was written (${workerNameValue})`;
962
- task.result = task.summary;
963
- task.failedAt = (/* @__PURE__ */ new Date()).toISOString();
964
- await writeTask(root, task);
1377
+ async function resetTaskToPending(root, taskId, teamName, cwd) {
1378
+ await withTaskLock(teamName, taskId, async () => {
1379
+ const task = await readTask(root, taskId);
1380
+ if (!task) return;
1381
+ task.status = "pending";
1382
+ task.owner = null;
1383
+ task.assignedAt = void 0;
1384
+ await writeTask(root, task);
1385
+ }, { cwd });
1386
+ }
1387
+ async function markTaskFromDone(root, teamName, cwd, taskId, status, summary) {
1388
+ await withTaskLock(teamName, taskId, async () => {
1389
+ const task = await readTask(root, taskId);
1390
+ if (!task) return;
1391
+ task.status = status;
1392
+ task.result = summary;
1393
+ task.summary = summary;
1394
+ if (status === "completed") {
1395
+ task.completedAt = (/* @__PURE__ */ new Date()).toISOString();
1396
+ } else {
1397
+ task.failedAt = (/* @__PURE__ */ new Date()).toISOString();
1398
+ }
1399
+ await writeTask(root, task);
1400
+ }, { cwd });
1401
+ }
1402
+ async function applyDeadPaneTransition(runtime, workerNameValue, taskId) {
1403
+ const root = stateRoot(runtime.cwd, runtime.teamName);
1404
+ const transition = await withTaskLock(runtime.teamName, taskId, async () => {
1405
+ const task = await readTask(root, taskId);
1406
+ if (!task) return { action: "skipped" };
1407
+ if (task.status === "completed" || task.status === "failed") {
1408
+ return { action: "skipped" };
1409
+ }
1410
+ if (task.status !== "in_progress" || task.owner !== workerNameValue) {
1411
+ return { action: "skipped" };
1412
+ }
1413
+ const failure = await writeTaskFailure(
1414
+ runtime.teamName,
1415
+ taskId,
1416
+ `Worker pane died before done.json was written (${workerNameValue})`,
1417
+ { cwd: runtime.cwd }
1418
+ );
1419
+ const retryCount = failure.retryCount;
1420
+ if (retryCount >= DEFAULT_MAX_TASK_RETRIES) {
1421
+ task.status = "failed";
1422
+ task.owner = workerNameValue;
1423
+ task.summary = `Worker pane died before done.json was written (${workerNameValue})`;
1424
+ task.result = task.summary;
1425
+ task.failedAt = (/* @__PURE__ */ new Date()).toISOString();
1426
+ await writeTask(root, task);
1427
+ return { action: "failed", retryCount };
1428
+ }
1429
+ task.status = "pending";
1430
+ task.owner = null;
1431
+ task.assignedAt = void 0;
1432
+ await writeTask(root, task);
1433
+ return { action: "requeued", retryCount };
1434
+ }, { cwd: runtime.cwd });
1435
+ return transition ?? { action: "skipped" };
965
1436
  }
966
1437
  async function nextPendingTaskIndex(runtime) {
967
1438
  const root = stateRoot(runtime.cwd, runtime.teamName);
1439
+ const transientReadRetryAttempts = 3;
1440
+ const transientReadRetryDelayMs = 15;
968
1441
  for (let i = 0; i < runtime.config.tasks.length; i++) {
969
- const task = await readTask(root, String(i + 1));
1442
+ const taskId = String(i + 1);
1443
+ let task = await readTask(root, taskId);
1444
+ if (!task) {
1445
+ for (let attempt = 1; attempt < transientReadRetryAttempts; attempt++) {
1446
+ await new Promise((resolve5) => setTimeout(resolve5, transientReadRetryDelayMs));
1447
+ task = await readTask(root, taskId);
1448
+ if (task) break;
1449
+ }
1450
+ }
970
1451
  if (task?.status === "pending") return i;
971
1452
  }
972
1453
  return null;
973
1454
  }
974
- async function notifyPaneWithRetry(sessionName, paneId, message, maxAttempts = 6, retryDelayMs = 350) {
1455
+ async function notifyPaneWithRetry(sessionName2, paneId, message, maxAttempts = 6, retryDelayMs = 350) {
975
1456
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
976
- if (await sendToWorker(sessionName, paneId, message)) {
1457
+ if (await sendToWorker(sessionName2, paneId, message)) {
977
1458
  return true;
978
1459
  }
979
1460
  if (attempt < maxAttempts) {
@@ -1010,16 +1491,17 @@ function buildInitialTaskInstruction(teamName, workerName2, task, taskId) {
1010
1491
  async function startTeam(config) {
1011
1492
  const { teamName, agentTypes, tasks, cwd } = config;
1012
1493
  validateTeamName(teamName);
1494
+ const resolvedBinaryPaths = {};
1013
1495
  for (const agentType of [...new Set(agentTypes)]) {
1014
- validateCliAvailable(agentType);
1496
+ resolvedBinaryPaths[agentType] = resolveValidatedBinaryPath(agentType);
1015
1497
  }
1016
1498
  const root = stateRoot(cwd, teamName);
1017
- await (0, import_promises3.mkdir)((0, import_path9.join)(root, "tasks"), { recursive: true });
1018
- await (0, import_promises3.mkdir)((0, import_path9.join)(root, "mailbox"), { recursive: true });
1019
- await writeJson((0, import_path9.join)(root, "config.json"), config);
1499
+ await (0, import_promises3.mkdir)((0, import_path10.join)(root, "tasks"), { recursive: true });
1500
+ await (0, import_promises3.mkdir)((0, import_path10.join)(root, "mailbox"), { recursive: true });
1501
+ await writeJson((0, import_path10.join)(root, "config.json"), config);
1020
1502
  for (let i = 0; i < tasks.length; i++) {
1021
1503
  const taskId = String(i + 1);
1022
- await writeJson((0, import_path9.join)(root, "tasks", `${taskId}.json`), {
1504
+ await writeJson((0, import_path10.join)(root, "tasks", `${taskId}.json`), {
1023
1505
  id: taskId,
1024
1506
  subject: tasks[i].subject,
1025
1507
  description: tasks[i].description,
@@ -1053,7 +1535,8 @@ async function startTeam(config) {
1053
1535
  workerPaneIds: session.workerPaneIds,
1054
1536
  // initially empty []
1055
1537
  activeWorkers: /* @__PURE__ */ new Map(),
1056
- cwd
1538
+ cwd,
1539
+ resolvedBinaryPaths
1057
1540
  };
1058
1541
  const maxConcurrentWorkers = agentTypes.length;
1059
1542
  for (let i = 0; i < maxConcurrentWorkers; i++) {
@@ -1071,10 +1554,10 @@ async function monitorTeam(teamName, cwd, workerPaneIds) {
1071
1554
  const taskScanStartedAt = Date.now();
1072
1555
  const taskCounts = { pending: 0, inProgress: 0, completed: 0, failed: 0 };
1073
1556
  try {
1074
- const { readdir } = await import("fs/promises");
1075
- const taskFiles = await readdir((0, import_path9.join)(root, "tasks"));
1557
+ const { readdir: readdir2 } = await import("fs/promises");
1558
+ const taskFiles = await readdir2((0, import_path10.join)(root, "tasks"));
1076
1559
  for (const f of taskFiles.filter((f2) => f2.endsWith(".json"))) {
1077
- const task = await readJsonSafe((0, import_path9.join)(root, "tasks", f));
1560
+ const task = await readJsonSafe((0, import_path10.join)(root, "tasks", f));
1078
1561
  if (task?.status === "pending") taskCounts.pending++;
1079
1562
  else if (task?.status === "in_progress") taskCounts.inProgress++;
1080
1563
  else if (task?.status === "completed") taskCounts.completed++;
@@ -1090,7 +1573,7 @@ async function monitorTeam(teamName, cwd, workerPaneIds) {
1090
1573
  const wName = `worker-${i + 1}`;
1091
1574
  const paneId = workerPaneIds[i];
1092
1575
  const alive = await isWorkerAlive(paneId);
1093
- const heartbeatPath = (0, import_path9.join)(root, "workers", wName, "heartbeat.json");
1576
+ const heartbeatPath = (0, import_path10.join)(root, "workers", wName, "heartbeat.json");
1094
1577
  const heartbeat = await readJsonSafe(heartbeatPath);
1095
1578
  let stalled = false;
1096
1579
  if (heartbeat?.updatedAt) {
@@ -1145,21 +1628,21 @@ function watchdogCliWorkers(runtime, intervalMs) {
1145
1628
  const root = stateRoot(runtime.cwd, runtime.teamName);
1146
1629
  const [doneSignals, aliveResults] = await Promise.all([
1147
1630
  Promise.all(workers.map(([wName]) => {
1148
- const donePath = (0, import_path9.join)(root, "workers", wName, "done.json");
1631
+ const donePath = (0, import_path10.join)(root, "workers", wName, "done.json");
1149
1632
  return readJsonSafe(donePath);
1150
1633
  })),
1151
1634
  Promise.all(workers.map(([, active]) => isWorkerAlive(active.paneId)))
1152
1635
  ]);
1153
1636
  for (let i = 0; i < workers.length; i++) {
1154
1637
  const [wName, active] = workers[i];
1155
- const donePath = (0, import_path9.join)(root, "workers", wName, "done.json");
1638
+ const donePath = (0, import_path10.join)(root, "workers", wName, "done.json");
1156
1639
  const signal = doneSignals[i];
1157
1640
  if (signal) {
1158
1641
  unresponsiveCounts.delete(wName);
1159
- await markTaskFromDone(root, signal.taskId || active.taskId, signal.status, signal.summary);
1642
+ await markTaskFromDone(root, runtime.teamName, runtime.cwd, signal.taskId || active.taskId, signal.status, signal.summary);
1160
1643
  try {
1161
- const { unlink } = await import("fs/promises");
1162
- await unlink(donePath);
1644
+ const { unlink: unlink2 } = await import("fs/promises");
1645
+ await unlink2(donePath);
1163
1646
  } catch {
1164
1647
  }
1165
1648
  await killWorkerPane(runtime, wName, active.paneId);
@@ -1174,7 +1657,11 @@ function watchdogCliWorkers(runtime, intervalMs) {
1174
1657
  const alive = aliveResults[i];
1175
1658
  if (!alive) {
1176
1659
  unresponsiveCounts.delete(wName);
1177
- await markTaskFailedDeadPane(root, active.taskId, wName);
1660
+ const transition = await applyDeadPaneTransition(runtime, wName, active.taskId);
1661
+ if (transition.action === "requeued") {
1662
+ const retryCount = transition.retryCount ?? 1;
1663
+ console.warn(`[watchdog] worker ${wName} dead pane \u2014 requeuing task ${active.taskId} (retry ${retryCount}/${DEFAULT_MAX_TASK_RETRIES})`);
1664
+ }
1178
1665
  await killWorkerPane(runtime, wName, active.paneId);
1179
1666
  if (!await allTasksTerminal(runtime)) {
1180
1667
  const nextTaskIndexValue = await nextPendingTaskIndex(runtime);
@@ -1184,7 +1671,7 @@ function watchdogCliWorkers(runtime, intervalMs) {
1184
1671
  }
1185
1672
  continue;
1186
1673
  }
1187
- const heartbeatPath = (0, import_path9.join)(root, "workers", wName, "heartbeat.json");
1674
+ const heartbeatPath = (0, import_path10.join)(root, "workers", wName, "heartbeat.json");
1188
1675
  const heartbeat = await readJsonSafe(heartbeatPath);
1189
1676
  const isStalled = heartbeat?.updatedAt ? Date.now() - new Date(heartbeat.updatedAt).getTime() > 6e4 : false;
1190
1677
  if (isStalled) {
@@ -1195,7 +1682,10 @@ function watchdogCliWorkers(runtime, intervalMs) {
1195
1682
  } else {
1196
1683
  console.warn(`[watchdog] worker ${wName} unresponsive ${count} consecutive ticks \u2014 killing and reassigning task ${active.taskId}`);
1197
1684
  unresponsiveCounts.delete(wName);
1198
- await markTaskFailedDeadPane(root, active.taskId, wName);
1685
+ const transition = await applyDeadPaneTransition(runtime, wName, active.taskId);
1686
+ if (transition.action === "requeued") {
1687
+ console.warn(`[watchdog] worker ${wName} stall-killed \u2014 requeuing task ${active.taskId} (retry ${transition.retryCount}/${DEFAULT_MAX_TASK_RETRIES})`);
1688
+ }
1199
1689
  await killWorkerPane(runtime, wName, active.paneId);
1200
1690
  if (!await allTasksTerminal(runtime)) {
1201
1691
  const nextTaskIndexValue = await nextPendingTaskIndex(runtime);
@@ -1216,7 +1706,7 @@ function watchdogCliWorkers(runtime, intervalMs) {
1216
1706
  console.warn(`[watchdog] ${consecutiveFailures} consecutive failures \u2014 marking team as failed`);
1217
1707
  try {
1218
1708
  const root = stateRoot(runtime.cwd, runtime.teamName);
1219
- await writeJson((0, import_path9.join)(root, "watchdog-failed.json"), {
1709
+ await writeJson((0, import_path10.join)(root, "watchdog-failed.json"), {
1220
1710
  failedAt: (/* @__PURE__ */ new Date()).toISOString(),
1221
1711
  consecutiveFailures,
1222
1712
  lastError: err instanceof Error ? err.message : String(err)
@@ -1267,10 +1757,26 @@ async function spawnWorkerForTask(runtime, workerNameValue, taskIndex) {
1267
1757
  await composeInitialInbox(runtime.teamName, workerNameValue, instruction, runtime.cwd);
1268
1758
  const relInboxPath = `.omc/state/team/${runtime.teamName}/workers/${workerNameValue}/inbox.md`;
1269
1759
  const envVars = getWorkerEnv(runtime.teamName, workerNameValue, agentType);
1760
+ const resolvedBinaryPath = runtime.resolvedBinaryPaths?.[agentType] ?? resolveValidatedBinaryPath(agentType);
1761
+ if (!runtime.resolvedBinaryPaths) {
1762
+ runtime.resolvedBinaryPaths = {};
1763
+ }
1764
+ runtime.resolvedBinaryPaths[agentType] = resolvedBinaryPath;
1765
+ const modelForAgent = (() => {
1766
+ if (agentType === "codex") {
1767
+ return process.env.OMC_EXTERNAL_MODELS_DEFAULT_CODEX_MODEL || process.env.OMC_CODEX_DEFAULT_MODEL || void 0;
1768
+ }
1769
+ if (agentType === "gemini") {
1770
+ return process.env.OMC_EXTERNAL_MODELS_DEFAULT_GEMINI_MODEL || process.env.OMC_GEMINI_DEFAULT_MODEL || void 0;
1771
+ }
1772
+ return void 0;
1773
+ })();
1270
1774
  const [launchBinary, ...launchArgs] = buildWorkerArgv(agentType, {
1271
1775
  teamName: runtime.teamName,
1272
1776
  workerName: workerNameValue,
1273
- cwd: runtime.cwd
1777
+ cwd: runtime.cwd,
1778
+ resolvedBinaryPath,
1779
+ model: modelForAgent
1274
1780
  });
1275
1781
  if (usePromptMode) {
1276
1782
  const promptArgs = getPromptModeArgs(agentType, `Read and execute your task from: ${relInboxPath}`);
@@ -1296,12 +1802,17 @@ async function spawnWorkerForTask(runtime, workerNameValue, taskIndex) {
1296
1802
  } catch {
1297
1803
  }
1298
1804
  if (!usePromptMode) {
1299
- await new Promise((r) => setTimeout(r, 4e3));
1805
+ const paneReady = await waitForPaneReady(paneId);
1806
+ if (!paneReady) {
1807
+ await killWorkerPane(runtime, workerNameValue, paneId);
1808
+ await resetTaskToPending(root, taskId, runtime.teamName, runtime.cwd);
1809
+ throw new Error(`worker_pane_not_ready:${workerNameValue}`);
1810
+ }
1300
1811
  if (agentType === "gemini") {
1301
1812
  const confirmed = await notifyPaneWithRetry(runtime.sessionName, paneId, "1");
1302
1813
  if (!confirmed) {
1303
1814
  await killWorkerPane(runtime, workerNameValue, paneId);
1304
- await resetTaskToPending(root, taskId);
1815
+ await resetTaskToPending(root, taskId, runtime.teamName, runtime.cwd);
1305
1816
  throw new Error(`worker_notify_failed:${workerNameValue}:trust-confirm`);
1306
1817
  }
1307
1818
  await new Promise((r) => setTimeout(r, 800));
@@ -1313,7 +1824,7 @@ async function spawnWorkerForTask(runtime, workerNameValue, taskIndex) {
1313
1824
  );
1314
1825
  if (!notified) {
1315
1826
  await killWorkerPane(runtime, workerNameValue, paneId);
1316
- await resetTaskToPending(root, taskId);
1827
+ await resetTaskToPending(root, taskId, runtime.teamName, runtime.cwd);
1317
1828
  throw new Error(`worker_notify_failed:${workerNameValue}:initial-inbox`);
1318
1829
  }
1319
1830
  }
@@ -1337,13 +1848,13 @@ async function killWorkerPane(runtime, workerNameValue, paneId) {
1337
1848
  } catch {
1338
1849
  }
1339
1850
  }
1340
- async function shutdownTeam(teamName, sessionName, cwd, timeoutMs = 3e4, workerPaneIds, leaderPaneId) {
1851
+ async function shutdownTeam(teamName, sessionName2, cwd, timeoutMs = 3e4, workerPaneIds, leaderPaneId) {
1341
1852
  const root = stateRoot(cwd, teamName);
1342
- await writeJson((0, import_path9.join)(root, "shutdown.json"), {
1853
+ await writeJson((0, import_path10.join)(root, "shutdown.json"), {
1343
1854
  requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
1344
1855
  teamName
1345
1856
  });
1346
- const configData = await readJsonSafe((0, import_path9.join)(root, "config.json"));
1857
+ const configData = await readJsonSafe((0, import_path10.join)(root, "config.json"));
1347
1858
  const CLI_AGENT_TYPES = /* @__PURE__ */ new Set(["claude", "codex", "gemini"]);
1348
1859
  const agentTypes = configData?.agentTypes ?? [];
1349
1860
  const isCliWorkerTeam = agentTypes.length > 0 && agentTypes.every((t) => CLI_AGENT_TYPES.has(t));
@@ -1353,7 +1864,7 @@ async function shutdownTeam(teamName, sessionName, cwd, timeoutMs = 3e4, workerP
1353
1864
  const expectedAcks = Array.from({ length: workerCount }, (_, i) => `worker-${i + 1}`);
1354
1865
  while (Date.now() < deadline && expectedAcks.length > 0) {
1355
1866
  for (const wName of [...expectedAcks]) {
1356
- const ackPath = (0, import_path9.join)(root, "workers", wName, "shutdown-ack.json");
1867
+ const ackPath = (0, import_path10.join)(root, "workers", wName, "shutdown-ack.json");
1357
1868
  if ((0, import_fs6.existsSync)(ackPath)) {
1358
1869
  expectedAcks.splice(expectedAcks.indexOf(wName), 1);
1359
1870
  }
@@ -1363,31 +1874,1852 @@ async function shutdownTeam(teamName, sessionName, cwd, timeoutMs = 3e4, workerP
1363
1874
  }
1364
1875
  }
1365
1876
  }
1366
- await killTeamSession(sessionName, workerPaneIds, leaderPaneId);
1877
+ await killTeamSession(sessionName2, workerPaneIds, leaderPaneId);
1367
1878
  try {
1368
1879
  await (0, import_promises3.rm)(root, { recursive: true, force: true });
1369
1880
  } catch {
1370
1881
  }
1371
1882
  }
1372
1883
 
1373
- // src/team/runtime-cli.ts
1374
- async function writePanesFile(jobId, paneIds, leaderPaneId) {
1375
- const omcJobsDir = process.env.OMC_JOBS_DIR;
1376
- if (!jobId || !omcJobsDir) return;
1377
- const panesPath = (0, import_path10.join)(omcJobsDir, `${jobId}-panes.json`);
1378
- await (0, import_promises4.writeFile)(
1379
- panesPath + ".tmp",
1380
- JSON.stringify({ paneIds: [...paneIds], leaderPaneId })
1381
- );
1382
- await (0, import_promises4.rename)(panesPath + ".tmp", panesPath);
1383
- }
1384
- function collectTaskResults(stateRoot2) {
1385
- const tasksDir = (0, import_path10.join)(stateRoot2, "tasks");
1386
- try {
1387
- const files = (0, import_fs7.readdirSync)(tasksDir).filter((f) => f.endsWith(".json"));
1388
- return files.map((f) => {
1389
- try {
1390
- const raw = (0, import_fs7.readFileSync)((0, import_path10.join)(tasksDir, f), "utf-8");
1884
+ // src/hooks/factcheck/checks.ts
1885
+ var import_fs7 = require("fs");
1886
+ var import_path11 = require("path");
1887
+
1888
+ // src/hooks/factcheck/types.ts
1889
+ var REQUIRED_FIELDS = /* @__PURE__ */ new Set([
1890
+ "schema_version",
1891
+ "run_id",
1892
+ "ts",
1893
+ "cwd",
1894
+ "mode",
1895
+ "files_modified",
1896
+ "files_created",
1897
+ "artifacts_expected",
1898
+ "gates"
1899
+ ]);
1900
+ var REQUIRED_GATES = /* @__PURE__ */ new Set([
1901
+ "selftest_ran",
1902
+ "goldens_ran",
1903
+ "sentinel_stop_smoke_ran",
1904
+ "shadow_leak_check_ran"
1905
+ ]);
1906
+
1907
+ // src/hooks/factcheck/checks.ts
1908
+ function checkMissingFields(claims) {
1909
+ const missing = [];
1910
+ for (const field of REQUIRED_FIELDS) {
1911
+ if (!(field in claims)) {
1912
+ missing.push(field);
1913
+ }
1914
+ }
1915
+ return missing.sort();
1916
+ }
1917
+ function checkMissingGates(claims) {
1918
+ const gates = claims.gates ?? {};
1919
+ const missing = [];
1920
+ for (const gate of REQUIRED_GATES) {
1921
+ if (!(gate in gates)) {
1922
+ missing.push(gate);
1923
+ }
1924
+ }
1925
+ return missing.sort();
1926
+ }
1927
+ function getFalseGates(claims) {
1928
+ const gates = claims.gates ?? {};
1929
+ const falseGates = [];
1930
+ for (const gate of REQUIRED_GATES) {
1931
+ if (gate in gates && !gates[gate]) {
1932
+ falseGates.push(gate);
1933
+ }
1934
+ }
1935
+ return falseGates.sort();
1936
+ }
1937
+ function sourceFileCount(claims) {
1938
+ const modified = claims.files_modified ?? [];
1939
+ const created = claims.files_created ?? [];
1940
+ return modified.length + created.length;
1941
+ }
1942
+ function checkPaths(claims, policy) {
1943
+ const out = [];
1944
+ const allPaths = [
1945
+ ...claims.files_modified ?? [],
1946
+ ...claims.files_created ?? [],
1947
+ ...claims.artifacts_expected ?? []
1948
+ ];
1949
+ const deleted = new Set(claims.files_deleted ?? []);
1950
+ for (const pathStr of allPaths) {
1951
+ if (deleted.has(pathStr)) continue;
1952
+ let prefixBlocked = false;
1953
+ for (const prefix of policy.forbidden_path_prefixes) {
1954
+ if (pathStr.startsWith(prefix)) {
1955
+ out.push({ check: "H", severity: "FAIL", detail: `Forbidden path prefix: ${pathStr}` });
1956
+ prefixBlocked = true;
1957
+ break;
1958
+ }
1959
+ }
1960
+ if (!prefixBlocked) {
1961
+ for (const fragment of policy.forbidden_path_substrings) {
1962
+ if (pathStr.includes(fragment)) {
1963
+ out.push({ check: "H", severity: "FAIL", detail: `Forbidden path fragment: ${pathStr}` });
1964
+ break;
1965
+ }
1966
+ }
1967
+ }
1968
+ if (!(0, import_fs7.existsSync)(pathStr)) {
1969
+ out.push({ check: "C", severity: "FAIL", detail: `File not found: ${pathStr}` });
1970
+ }
1971
+ }
1972
+ return out;
1973
+ }
1974
+ function checkCommands(claims, policy) {
1975
+ const out = [];
1976
+ const commands = (claims.commands_executed ?? []).map(String);
1977
+ for (const cmd of commands) {
1978
+ const hitPrefix = policy.forbidden_path_prefixes.some(
1979
+ (forbidden) => cmd.includes(forbidden)
1980
+ );
1981
+ if (!hitPrefix) continue;
1982
+ const stripped = cmd.trim().replace(/^\(/, "");
1983
+ const isReadOnly = policy.readonly_command_prefixes.some(
1984
+ (prefix) => stripped.startsWith(prefix)
1985
+ );
1986
+ if (!isReadOnly) {
1987
+ out.push({ check: "H", severity: "FAIL", detail: `Forbidden mutating command: ${cmd}` });
1988
+ }
1989
+ }
1990
+ return out;
1991
+ }
1992
+ function checkCwdParity(claimsCwd, runtimeCwd, mode, policy) {
1993
+ const enforceCwd = policy.warn_on_cwd_mismatch && (mode !== "quick" || policy.enforce_cwd_parity_in_quick);
1994
+ if (!enforceCwd || !claimsCwd) return null;
1995
+ const claimsCwdCanonical = (0, import_path11.resolve)(claimsCwd);
1996
+ const runtimeCwdCanonical = (0, import_path11.resolve)(runtimeCwd);
1997
+ if (claimsCwdCanonical !== runtimeCwdCanonical) {
1998
+ const severity = mode === "strict" ? "FAIL" : "WARN";
1999
+ return {
2000
+ check: "argv_parity",
2001
+ severity,
2002
+ detail: `claims.cwd=${claimsCwdCanonical} runtime.cwd=${runtimeCwdCanonical}`
2003
+ };
2004
+ }
2005
+ return null;
2006
+ }
2007
+
2008
+ // src/hooks/factcheck/config.ts
2009
+ var import_os2 = require("os");
2010
+
2011
+ // src/config/loader.ts
2012
+ var import_fs8 = require("fs");
2013
+ var import_path12 = require("path");
2014
+
2015
+ // src/utils/jsonc.ts
2016
+ function parseJsonc(content) {
2017
+ const cleaned = stripJsoncComments(content);
2018
+ return JSON.parse(cleaned);
2019
+ }
2020
+ function stripJsoncComments(content) {
2021
+ let result = "";
2022
+ let i = 0;
2023
+ while (i < content.length) {
2024
+ if (content[i] === "/" && content[i + 1] === "/") {
2025
+ while (i < content.length && content[i] !== "\n") {
2026
+ i++;
2027
+ }
2028
+ continue;
2029
+ }
2030
+ if (content[i] === "/" && content[i + 1] === "*") {
2031
+ i += 2;
2032
+ while (i < content.length && !(content[i] === "*" && content[i + 1] === "/")) {
2033
+ i++;
2034
+ }
2035
+ i += 2;
2036
+ continue;
2037
+ }
2038
+ if (content[i] === '"') {
2039
+ result += content[i];
2040
+ i++;
2041
+ while (i < content.length && content[i] !== '"') {
2042
+ if (content[i] === "\\" && content[i + 1] === '"') {
2043
+ result += content[i];
2044
+ i++;
2045
+ }
2046
+ result += content[i];
2047
+ i++;
2048
+ }
2049
+ if (i < content.length) {
2050
+ result += content[i];
2051
+ i++;
2052
+ }
2053
+ continue;
2054
+ }
2055
+ result += content[i];
2056
+ i++;
2057
+ }
2058
+ return result;
2059
+ }
2060
+
2061
+ // src/utils/ssrf-guard.ts
2062
+ var BLOCKED_HOST_PATTERNS = [
2063
+ // Exact matches
2064
+ /^localhost$/i,
2065
+ /^127\.[0-9]+\.[0-9]+\.[0-9]+$/,
2066
+ // Loopback
2067
+ /^10\.[0-9]+\.[0-9]+\.[0-9]+$/,
2068
+ // Class A private
2069
+ /^172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]+\.[0-9]+$/,
2070
+ // Class B private
2071
+ /^192\.168\.[0-9]+\.[0-9]+$/,
2072
+ // Class C private
2073
+ /^169\.254\.[0-9]+\.[0-9]+$/,
2074
+ // Link-local
2075
+ /^(0|22[4-9]|23[0-9])\.[0-9]+\.[0-9]+\.[0-9]+$/,
2076
+ // Multicast, reserved
2077
+ /^\[?::1\]?$/,
2078
+ // IPv6 loopback
2079
+ /^\[?fc00:/i,
2080
+ // IPv6 unique local
2081
+ /^\[?fe80:/i
2082
+ // IPv6 link-local
2083
+ ];
2084
+ var ALLOWED_SCHEMES = ["https:", "http:"];
2085
+ function validateUrlForSSRF(urlString) {
2086
+ if (!urlString || typeof urlString !== "string") {
2087
+ return { allowed: false, reason: "URL is empty or invalid" };
2088
+ }
2089
+ let parsed;
2090
+ try {
2091
+ parsed = new URL(urlString);
2092
+ } catch {
2093
+ return { allowed: false, reason: "Invalid URL format" };
2094
+ }
2095
+ if (!ALLOWED_SCHEMES.includes(parsed.protocol)) {
2096
+ return { allowed: false, reason: `Protocol '${parsed.protocol}' is not allowed` };
2097
+ }
2098
+ const hostname = parsed.hostname.toLowerCase();
2099
+ for (const pattern of BLOCKED_HOST_PATTERNS) {
2100
+ if (pattern.test(hostname)) {
2101
+ return {
2102
+ allowed: false,
2103
+ reason: `Hostname '${hostname}' resolves to a blocked internal/private address`
2104
+ };
2105
+ }
2106
+ }
2107
+ if (parsed.username || parsed.password) {
2108
+ return { allowed: false, reason: "URLs with embedded credentials are not allowed" };
2109
+ }
2110
+ const dangerousPaths = [
2111
+ "/metadata",
2112
+ "/meta-data",
2113
+ "/latest/meta-data",
2114
+ "/computeMetadata"
2115
+ ];
2116
+ const pathLower = parsed.pathname.toLowerCase();
2117
+ for (const dangerous of dangerousPaths) {
2118
+ if (pathLower.startsWith(dangerous)) {
2119
+ return {
2120
+ allowed: false,
2121
+ reason: `Path '${parsed.pathname}' is blocked (cloud metadata access)`
2122
+ };
2123
+ }
2124
+ }
2125
+ return { allowed: true };
2126
+ }
2127
+ function validateAnthropicBaseUrl(urlString) {
2128
+ const result = validateUrlForSSRF(urlString);
2129
+ if (!result.allowed) {
2130
+ return result;
2131
+ }
2132
+ let parsed;
2133
+ try {
2134
+ parsed = new URL(urlString);
2135
+ } catch {
2136
+ return { allowed: false, reason: "Invalid URL" };
2137
+ }
2138
+ if (parsed.protocol === "http:") {
2139
+ console.warn("[SSRF Guard] Warning: Using HTTP instead of HTTPS for ANTHROPIC_BASE_URL");
2140
+ }
2141
+ return { allowed: true };
2142
+ }
2143
+
2144
+ // src/config/models.ts
2145
+ var BUILTIN_MODEL_HIGH = "claude-opus-4-6-20260205";
2146
+ var BUILTIN_MODEL_MEDIUM = "claude-sonnet-4-6-20260217";
2147
+ var BUILTIN_MODEL_LOW = "claude-haiku-4-5-20251001";
2148
+ function getDefaultModelHigh() {
2149
+ return process.env.OMC_MODEL_HIGH || BUILTIN_MODEL_HIGH;
2150
+ }
2151
+ function getDefaultModelMedium() {
2152
+ return process.env.OMC_MODEL_MEDIUM || BUILTIN_MODEL_MEDIUM;
2153
+ }
2154
+ function getDefaultModelLow() {
2155
+ return process.env.OMC_MODEL_LOW || BUILTIN_MODEL_LOW;
2156
+ }
2157
+ function isBedrock() {
2158
+ if (process.env.CLAUDE_CODE_USE_BEDROCK === "1") {
2159
+ return true;
2160
+ }
2161
+ const modelId = process.env.CLAUDE_MODEL || process.env.ANTHROPIC_MODEL || "";
2162
+ if (modelId && /^((us|eu|ap|global)\.anthropic\.|anthropic\.claude)/i.test(modelId)) {
2163
+ return true;
2164
+ }
2165
+ return false;
2166
+ }
2167
+ function isVertexAI() {
2168
+ if (process.env.CLAUDE_CODE_USE_VERTEX === "1") {
2169
+ return true;
2170
+ }
2171
+ const modelId = process.env.CLAUDE_MODEL || process.env.ANTHROPIC_MODEL || "";
2172
+ if (modelId && modelId.toLowerCase().startsWith("vertex_ai/")) {
2173
+ return true;
2174
+ }
2175
+ return false;
2176
+ }
2177
+ function isNonClaudeProvider() {
2178
+ if (process.env.OMC_ROUTING_FORCE_INHERIT === "true") {
2179
+ return true;
2180
+ }
2181
+ if (isBedrock()) {
2182
+ return true;
2183
+ }
2184
+ if (isVertexAI()) {
2185
+ return true;
2186
+ }
2187
+ const modelId = process.env.CLAUDE_MODEL || process.env.ANTHROPIC_MODEL || "";
2188
+ if (modelId && !modelId.toLowerCase().includes("claude")) {
2189
+ return true;
2190
+ }
2191
+ const baseUrl = process.env.ANTHROPIC_BASE_URL || "";
2192
+ if (baseUrl) {
2193
+ const validation = validateAnthropicBaseUrl(baseUrl);
2194
+ if (!validation.allowed) {
2195
+ console.error(`[SSRF Guard] Rejecting ANTHROPIC_BASE_URL: ${validation.reason}`);
2196
+ return true;
2197
+ }
2198
+ if (!baseUrl.includes("anthropic.com")) {
2199
+ return true;
2200
+ }
2201
+ }
2202
+ return false;
2203
+ }
2204
+
2205
+ // src/config/loader.ts
2206
+ var DEFAULT_CONFIG = {
2207
+ agents: {
2208
+ omc: { model: getDefaultModelHigh() },
2209
+ explore: { model: getDefaultModelLow() },
2210
+ analyst: { model: getDefaultModelHigh() },
2211
+ planner: { model: getDefaultModelHigh() },
2212
+ architect: { model: getDefaultModelHigh() },
2213
+ debugger: { model: getDefaultModelMedium() },
2214
+ executor: { model: getDefaultModelMedium() },
2215
+ verifier: { model: getDefaultModelMedium() },
2216
+ qualityReviewer: { model: getDefaultModelMedium() },
2217
+ securityReviewer: { model: getDefaultModelMedium() },
2218
+ codeReviewer: { model: getDefaultModelHigh() },
2219
+ deepExecutor: { model: getDefaultModelHigh() },
2220
+ testEngineer: { model: getDefaultModelMedium() },
2221
+ buildFixer: { model: getDefaultModelMedium() },
2222
+ designer: { model: getDefaultModelMedium() },
2223
+ writer: { model: getDefaultModelLow() },
2224
+ qaTester: { model: getDefaultModelMedium() },
2225
+ scientist: { model: getDefaultModelMedium() },
2226
+ gitMaster: { model: getDefaultModelMedium() },
2227
+ codeSimplifier: { model: getDefaultModelHigh() },
2228
+ critic: { model: getDefaultModelHigh() },
2229
+ documentSpecialist: { model: getDefaultModelMedium() }
2230
+ },
2231
+ features: {
2232
+ parallelExecution: true,
2233
+ lspTools: true,
2234
+ // Real LSP integration with language servers
2235
+ astTools: true,
2236
+ // Real AST tools using ast-grep
2237
+ continuationEnforcement: true,
2238
+ autoContextInjection: true
2239
+ },
2240
+ mcpServers: {
2241
+ exa: { enabled: true },
2242
+ context7: { enabled: true }
2243
+ },
2244
+ permissions: {
2245
+ allowBash: true,
2246
+ allowEdit: true,
2247
+ allowWrite: true,
2248
+ maxBackgroundTasks: 5
2249
+ },
2250
+ magicKeywords: {
2251
+ ultrawork: ["ultrawork", "ulw", "uw"],
2252
+ search: ["search", "find", "locate"],
2253
+ analyze: ["analyze", "investigate", "examine"],
2254
+ ultrathink: ["ultrathink", "think", "reason", "ponder"]
2255
+ },
2256
+ // Intelligent model routing configuration
2257
+ routing: {
2258
+ enabled: true,
2259
+ defaultTier: "MEDIUM",
2260
+ forceInherit: false,
2261
+ escalationEnabled: true,
2262
+ maxEscalations: 2,
2263
+ tierModels: {
2264
+ LOW: getDefaultModelLow(),
2265
+ MEDIUM: getDefaultModelMedium(),
2266
+ HIGH: getDefaultModelHigh()
2267
+ },
2268
+ agentOverrides: {
2269
+ architect: { tier: "HIGH", reason: "Advisory agent requires deep reasoning" },
2270
+ planner: { tier: "HIGH", reason: "Strategic planning requires deep reasoning" },
2271
+ critic: { tier: "HIGH", reason: "Critical review requires deep reasoning" },
2272
+ analyst: { tier: "HIGH", reason: "Pre-planning analysis requires deep reasoning" },
2273
+ explore: { tier: "LOW", reason: "Exploration is search-focused" },
2274
+ "writer": { tier: "LOW", reason: "Documentation is straightforward" }
2275
+ },
2276
+ escalationKeywords: [
2277
+ "critical",
2278
+ "production",
2279
+ "urgent",
2280
+ "security",
2281
+ "breaking",
2282
+ "architecture",
2283
+ "refactor",
2284
+ "redesign",
2285
+ "root cause"
2286
+ ],
2287
+ simplificationKeywords: [
2288
+ "find",
2289
+ "list",
2290
+ "show",
2291
+ "where",
2292
+ "search",
2293
+ "locate",
2294
+ "grep"
2295
+ ]
2296
+ },
2297
+ // External models configuration (Codex, Gemini)
2298
+ // Static defaults only — env var overrides applied in loadEnvConfig()
2299
+ externalModels: {
2300
+ defaults: {
2301
+ codexModel: "gpt-5.3-codex",
2302
+ geminiModel: "gemini-3.1-pro-preview"
2303
+ },
2304
+ fallbackPolicy: {
2305
+ onModelFailure: "provider_chain",
2306
+ allowCrossProvider: false,
2307
+ crossProviderOrder: ["codex", "gemini"]
2308
+ }
2309
+ },
2310
+ // Delegation routing configuration (opt-in feature for external model routing)
2311
+ delegationRouting: {
2312
+ enabled: false,
2313
+ // Opt-in feature
2314
+ defaultProvider: "claude",
2315
+ roles: {}
2316
+ },
2317
+ // Startup codebase map injection (issue #804)
2318
+ startupCodebaseMap: {
2319
+ enabled: true,
2320
+ maxFiles: 200,
2321
+ maxDepth: 4
2322
+ },
2323
+ // Task size detection (issue #790): prevent over-orchestration for small tasks
2324
+ taskSizeDetection: {
2325
+ enabled: true,
2326
+ smallWordLimit: 50,
2327
+ largeWordLimit: 200,
2328
+ suppressHeavyModesForSmallTasks: true
2329
+ }
2330
+ };
2331
+ function getConfigPaths() {
2332
+ const userConfigDir = getConfigDir2();
2333
+ return {
2334
+ user: (0, import_path12.join)(userConfigDir, "claude-omc", "config.jsonc"),
2335
+ project: (0, import_path12.join)(process.cwd(), ".claude", "omc.jsonc")
2336
+ };
2337
+ }
2338
+ function loadJsoncFile(path) {
2339
+ if (!(0, import_fs8.existsSync)(path)) {
2340
+ return null;
2341
+ }
2342
+ try {
2343
+ const content = (0, import_fs8.readFileSync)(path, "utf-8");
2344
+ const result = parseJsonc(content);
2345
+ return result;
2346
+ } catch (error) {
2347
+ console.error(`Error loading config from ${path}:`, error);
2348
+ return null;
2349
+ }
2350
+ }
2351
+ function deepMerge(target, source) {
2352
+ const result = { ...target };
2353
+ for (const key of Object.keys(source)) {
2354
+ const sourceValue = source[key];
2355
+ const targetValue = result[key];
2356
+ if (sourceValue !== void 0 && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
2357
+ result[key] = deepMerge(
2358
+ targetValue,
2359
+ sourceValue
2360
+ );
2361
+ } else if (sourceValue !== void 0) {
2362
+ result[key] = sourceValue;
2363
+ }
2364
+ }
2365
+ return result;
2366
+ }
2367
+ function loadEnvConfig() {
2368
+ const config = {};
2369
+ if (process.env.EXA_API_KEY) {
2370
+ config.mcpServers = {
2371
+ ...config.mcpServers,
2372
+ exa: { enabled: true, apiKey: process.env.EXA_API_KEY }
2373
+ };
2374
+ }
2375
+ if (process.env.OMC_PARALLEL_EXECUTION !== void 0) {
2376
+ config.features = {
2377
+ ...config.features,
2378
+ parallelExecution: process.env.OMC_PARALLEL_EXECUTION === "true"
2379
+ };
2380
+ }
2381
+ if (process.env.OMC_LSP_TOOLS !== void 0) {
2382
+ config.features = {
2383
+ ...config.features,
2384
+ lspTools: process.env.OMC_LSP_TOOLS === "true"
2385
+ };
2386
+ }
2387
+ if (process.env.OMC_MAX_BACKGROUND_TASKS) {
2388
+ const maxTasks = parseInt(process.env.OMC_MAX_BACKGROUND_TASKS, 10);
2389
+ if (!isNaN(maxTasks)) {
2390
+ config.permissions = {
2391
+ ...config.permissions,
2392
+ maxBackgroundTasks: maxTasks
2393
+ };
2394
+ }
2395
+ }
2396
+ if (process.env.OMC_ROUTING_ENABLED !== void 0) {
2397
+ config.routing = {
2398
+ ...config.routing,
2399
+ enabled: process.env.OMC_ROUTING_ENABLED === "true"
2400
+ };
2401
+ }
2402
+ if (process.env.OMC_ROUTING_FORCE_INHERIT !== void 0) {
2403
+ config.routing = {
2404
+ ...config.routing,
2405
+ forceInherit: process.env.OMC_ROUTING_FORCE_INHERIT === "true"
2406
+ };
2407
+ }
2408
+ if (process.env.OMC_ROUTING_DEFAULT_TIER) {
2409
+ const tier = process.env.OMC_ROUTING_DEFAULT_TIER.toUpperCase();
2410
+ if (tier === "LOW" || tier === "MEDIUM" || tier === "HIGH") {
2411
+ config.routing = {
2412
+ ...config.routing,
2413
+ defaultTier: tier
2414
+ };
2415
+ }
2416
+ }
2417
+ const aliasKeys = ["HAIKU", "SONNET", "OPUS"];
2418
+ const modelAliases = {};
2419
+ for (const key of aliasKeys) {
2420
+ const envVal = process.env[`OMC_MODEL_ALIAS_${key}`];
2421
+ if (envVal) {
2422
+ const lower = key.toLowerCase();
2423
+ modelAliases[lower] = envVal.toLowerCase();
2424
+ }
2425
+ }
2426
+ if (Object.keys(modelAliases).length > 0) {
2427
+ config.routing = {
2428
+ ...config.routing,
2429
+ modelAliases
2430
+ };
2431
+ }
2432
+ if (process.env.OMC_ESCALATION_ENABLED !== void 0) {
2433
+ config.routing = {
2434
+ ...config.routing,
2435
+ escalationEnabled: process.env.OMC_ESCALATION_ENABLED === "true"
2436
+ };
2437
+ }
2438
+ const externalModelsDefaults = {};
2439
+ if (process.env.OMC_EXTERNAL_MODELS_DEFAULT_PROVIDER) {
2440
+ const provider = process.env.OMC_EXTERNAL_MODELS_DEFAULT_PROVIDER;
2441
+ if (provider === "codex" || provider === "gemini") {
2442
+ externalModelsDefaults.provider = provider;
2443
+ }
2444
+ }
2445
+ if (process.env.OMC_EXTERNAL_MODELS_DEFAULT_CODEX_MODEL) {
2446
+ externalModelsDefaults.codexModel = process.env.OMC_EXTERNAL_MODELS_DEFAULT_CODEX_MODEL;
2447
+ } else if (process.env.OMC_CODEX_DEFAULT_MODEL) {
2448
+ externalModelsDefaults.codexModel = process.env.OMC_CODEX_DEFAULT_MODEL;
2449
+ }
2450
+ if (process.env.OMC_EXTERNAL_MODELS_DEFAULT_GEMINI_MODEL) {
2451
+ externalModelsDefaults.geminiModel = process.env.OMC_EXTERNAL_MODELS_DEFAULT_GEMINI_MODEL;
2452
+ } else if (process.env.OMC_GEMINI_DEFAULT_MODEL) {
2453
+ externalModelsDefaults.geminiModel = process.env.OMC_GEMINI_DEFAULT_MODEL;
2454
+ }
2455
+ const externalModelsFallback = {
2456
+ onModelFailure: "provider_chain"
2457
+ };
2458
+ if (process.env.OMC_EXTERNAL_MODELS_FALLBACK_POLICY) {
2459
+ const policy = process.env.OMC_EXTERNAL_MODELS_FALLBACK_POLICY;
2460
+ if (policy === "provider_chain" || policy === "cross_provider" || policy === "claude_only") {
2461
+ externalModelsFallback.onModelFailure = policy;
2462
+ }
2463
+ }
2464
+ if (Object.keys(externalModelsDefaults).length > 0 || externalModelsFallback.onModelFailure !== "provider_chain") {
2465
+ config.externalModels = {
2466
+ defaults: externalModelsDefaults,
2467
+ fallbackPolicy: externalModelsFallback
2468
+ };
2469
+ }
2470
+ if (process.env.OMC_DELEGATION_ROUTING_ENABLED !== void 0) {
2471
+ config.delegationRouting = {
2472
+ ...config.delegationRouting,
2473
+ enabled: process.env.OMC_DELEGATION_ROUTING_ENABLED === "true"
2474
+ };
2475
+ }
2476
+ if (process.env.OMC_DELEGATION_ROUTING_DEFAULT_PROVIDER) {
2477
+ const provider = process.env.OMC_DELEGATION_ROUTING_DEFAULT_PROVIDER;
2478
+ if (["claude", "codex", "gemini"].includes(provider)) {
2479
+ config.delegationRouting = {
2480
+ ...config.delegationRouting,
2481
+ defaultProvider: provider
2482
+ };
2483
+ }
2484
+ }
2485
+ return config;
2486
+ }
2487
+ function loadConfig() {
2488
+ const paths = getConfigPaths();
2489
+ let config = { ...DEFAULT_CONFIG };
2490
+ const userConfig = loadJsoncFile(paths.user);
2491
+ if (userConfig) {
2492
+ config = deepMerge(config, userConfig);
2493
+ }
2494
+ const projectConfig = loadJsoncFile(paths.project);
2495
+ if (projectConfig) {
2496
+ config = deepMerge(config, projectConfig);
2497
+ }
2498
+ const envConfig = loadEnvConfig();
2499
+ config = deepMerge(config, envConfig);
2500
+ if (config.routing?.forceInherit !== true && process.env.OMC_ROUTING_FORCE_INHERIT === void 0 && isNonClaudeProvider()) {
2501
+ config.routing = {
2502
+ ...config.routing,
2503
+ forceInherit: true
2504
+ };
2505
+ }
2506
+ return config;
2507
+ }
2508
+
2509
+ // src/hooks/factcheck/config.ts
2510
+ var DEFAULT_FACTCHECK_POLICY = {
2511
+ enabled: false,
2512
+ mode: "quick",
2513
+ strict_project_patterns: [],
2514
+ forbidden_path_prefixes: ["${HOME}/.claude/plugins/cache/omc/"],
2515
+ forbidden_path_substrings: ["/.omc/", ".omc-config.json"],
2516
+ readonly_command_prefixes: [
2517
+ "ls ",
2518
+ "cat ",
2519
+ "find ",
2520
+ "grep ",
2521
+ "head ",
2522
+ "tail ",
2523
+ "stat ",
2524
+ "echo ",
2525
+ "wc "
2526
+ ],
2527
+ warn_on_cwd_mismatch: true,
2528
+ enforce_cwd_parity_in_quick: false,
2529
+ warn_on_unverified_gates: true,
2530
+ warn_on_unverified_gates_when_no_source_files: false
2531
+ };
2532
+ var DEFAULT_SENTINEL_POLICY = {
2533
+ enabled: false,
2534
+ readiness: {
2535
+ min_pass_rate: 0.6,
2536
+ max_timeout_rate: 0.1,
2537
+ max_warn_plus_fail_rate: 0.4,
2538
+ min_reason_coverage_rate: 0.95
2539
+ }
2540
+ };
2541
+ var DEFAULT_GUARDS_CONFIG = {
2542
+ factcheck: { ...DEFAULT_FACTCHECK_POLICY },
2543
+ sentinel: { ...DEFAULT_SENTINEL_POLICY }
2544
+ };
2545
+ function expandTokens(value, workspace) {
2546
+ const home = (0, import_os2.homedir)();
2547
+ const ws = workspace ?? process.env.OMC_WORKSPACE ?? process.cwd();
2548
+ return value.replace(/\$\{HOME\}/g, home).replace(/\$\{WORKSPACE\}/g, ws);
2549
+ }
2550
+ function expandTokensDeep(obj, workspace) {
2551
+ if (typeof obj === "string") {
2552
+ return expandTokens(obj, workspace);
2553
+ }
2554
+ if (Array.isArray(obj)) {
2555
+ return obj.map((item) => expandTokensDeep(item, workspace));
2556
+ }
2557
+ if (typeof obj === "object" && obj !== null) {
2558
+ const result = {};
2559
+ for (const [key, value] of Object.entries(obj)) {
2560
+ result[key] = expandTokensDeep(value, workspace);
2561
+ }
2562
+ return result;
2563
+ }
2564
+ return obj;
2565
+ }
2566
+ function deepMergeGuards(target, source) {
2567
+ const result = { ...target };
2568
+ if (source.factcheck) {
2569
+ result.factcheck = { ...result.factcheck, ...source.factcheck };
2570
+ }
2571
+ if (source.sentinel) {
2572
+ result.sentinel = {
2573
+ ...result.sentinel,
2574
+ ...source.sentinel,
2575
+ readiness: {
2576
+ ...result.sentinel.readiness,
2577
+ ...source.sentinel.readiness ?? {}
2578
+ }
2579
+ };
2580
+ }
2581
+ return result;
2582
+ }
2583
+ function loadGuardsConfig(workspace) {
2584
+ try {
2585
+ const fullConfig = loadConfig();
2586
+ const guardsRaw = fullConfig.guards ?? {};
2587
+ const merged = deepMergeGuards(DEFAULT_GUARDS_CONFIG, guardsRaw);
2588
+ return expandTokensDeep(merged, workspace);
2589
+ } catch {
2590
+ return expandTokensDeep({ ...DEFAULT_GUARDS_CONFIG }, workspace);
2591
+ }
2592
+ }
2593
+
2594
+ // src/hooks/factcheck/index.ts
2595
+ function severityRank(value) {
2596
+ if (value === "FAIL") return 2;
2597
+ if (value === "WARN") return 1;
2598
+ return 0;
2599
+ }
2600
+ function runChecks(claims, mode, policy, runtimeCwd) {
2601
+ const mismatches = [];
2602
+ const notes = [];
2603
+ const missingFields = checkMissingFields(claims);
2604
+ if (missingFields.length > 0) {
2605
+ mismatches.push({
2606
+ check: "A",
2607
+ severity: "FAIL",
2608
+ detail: `Missing required fields: ${JSON.stringify(missingFields)}`
2609
+ });
2610
+ }
2611
+ const missingGates = checkMissingGates(claims);
2612
+ if (missingGates.length > 0) {
2613
+ mismatches.push({
2614
+ check: "A",
2615
+ severity: "FAIL",
2616
+ detail: `Missing required gates: ${JSON.stringify(missingGates)}`
2617
+ });
2618
+ }
2619
+ const falseGates = getFalseGates(claims);
2620
+ const srcFiles = sourceFileCount(claims);
2621
+ if (mode === "strict" && falseGates.length > 0) {
2622
+ mismatches.push({
2623
+ check: "B",
2624
+ severity: "FAIL",
2625
+ detail: `Strict mode requires all gates true, got false: ${JSON.stringify(falseGates)}`
2626
+ });
2627
+ } else if ((mode === "declared" || mode === "manual") && falseGates.length > 0 && policy.warn_on_unverified_gates) {
2628
+ if (srcFiles > 0 || policy.warn_on_unverified_gates_when_no_source_files) {
2629
+ mismatches.push({
2630
+ check: "B",
2631
+ severity: "WARN",
2632
+ detail: `Unverified gates in declared/manual mode: ${JSON.stringify(falseGates)}`
2633
+ });
2634
+ } else {
2635
+ notes.push("No source files declared; unverified gates are ignored by policy");
2636
+ }
2637
+ }
2638
+ mismatches.push(...checkPaths(claims, policy));
2639
+ mismatches.push(...checkCommands(claims, policy));
2640
+ const claimsCwd = String(claims.cwd ?? "").trim();
2641
+ const cwdMismatch = checkCwdParity(
2642
+ claimsCwd,
2643
+ runtimeCwd ?? process.cwd(),
2644
+ mode,
2645
+ policy
2646
+ );
2647
+ if (cwdMismatch) {
2648
+ mismatches.push(cwdMismatch);
2649
+ }
2650
+ const maxRank = mismatches.reduce(
2651
+ (max, m) => Math.max(max, severityRank(m.severity)),
2652
+ 0
2653
+ );
2654
+ let verdict = "PASS";
2655
+ if (maxRank === 2) verdict = "FAIL";
2656
+ else if (maxRank === 1) verdict = "WARN";
2657
+ return {
2658
+ verdict,
2659
+ mode,
2660
+ mismatches,
2661
+ notes,
2662
+ claims_evidence: {
2663
+ source_files: srcFiles,
2664
+ commands_count: (claims.commands_executed ?? []).length,
2665
+ models_count: (claims.models_used ?? []).length
2666
+ }
2667
+ };
2668
+ }
2669
+ function runFactcheck(claims, options) {
2670
+ const config = loadGuardsConfig(options?.workspace);
2671
+ const mode = options?.mode ?? config.factcheck.mode;
2672
+ return runChecks(claims, mode, config.factcheck, options?.runtimeCwd);
2673
+ }
2674
+
2675
+ // src/hooks/factcheck/sentinel.ts
2676
+ var import_fs9 = require("fs");
2677
+ function computeRate(numerator, denominator) {
2678
+ if (denominator === 0) return 0;
2679
+ return numerator / denominator;
2680
+ }
2681
+ function getPassRate(stats) {
2682
+ return computeRate(stats.pass_count, stats.total_runs);
2683
+ }
2684
+ function getTimeoutRate(stats) {
2685
+ return computeRate(stats.timeout_count, stats.total_runs);
2686
+ }
2687
+ function getWarnPlusFailRate(stats) {
2688
+ return computeRate(stats.warn_count + stats.fail_count, stats.total_runs);
2689
+ }
2690
+ function getReasonCoverageRate(stats) {
2691
+ return computeRate(stats.reason_coverage_count, stats.total_runs);
2692
+ }
2693
+ function extractVerdict(entry) {
2694
+ const raw = String(entry.verdict ?? "").toUpperCase().trim();
2695
+ if (raw === "PASS") return "PASS";
2696
+ if (raw === "WARN") return "WARN";
2697
+ return "FAIL";
2698
+ }
2699
+ function hasReason(entry) {
2700
+ return !!(entry.reason || entry.error || entry.message);
2701
+ }
2702
+ function isTimeout(entry) {
2703
+ if (entry.runtime?.timed_out === true) return true;
2704
+ if (entry.runtime?.global_timeout === true) return true;
2705
+ const reason = String(entry.reason ?? "").toLowerCase();
2706
+ return reason.includes("timeout");
2707
+ }
2708
+ function analyzeLog(logPath) {
2709
+ const stats = {
2710
+ total_runs: 0,
2711
+ pass_count: 0,
2712
+ warn_count: 0,
2713
+ fail_count: 0,
2714
+ timeout_count: 0,
2715
+ reason_coverage_count: 0
2716
+ };
2717
+ if (!(0, import_fs9.existsSync)(logPath)) {
2718
+ return stats;
2719
+ }
2720
+ let content;
2721
+ try {
2722
+ content = (0, import_fs9.readFileSync)(logPath, "utf-8");
2723
+ } catch {
2724
+ return stats;
2725
+ }
2726
+ const lines = content.split("\n").filter((line) => line.trim().length > 0);
2727
+ for (const line of lines) {
2728
+ let entry;
2729
+ try {
2730
+ entry = JSON.parse(line);
2731
+ } catch {
2732
+ continue;
2733
+ }
2734
+ stats.total_runs++;
2735
+ const verdict = extractVerdict(entry);
2736
+ if (verdict === "PASS") stats.pass_count++;
2737
+ else if (verdict === "WARN") stats.warn_count++;
2738
+ else stats.fail_count++;
2739
+ if (isTimeout(entry)) stats.timeout_count++;
2740
+ if (hasReason(entry)) stats.reason_coverage_count++;
2741
+ }
2742
+ return stats;
2743
+ }
2744
+ function isUpstreamReady(stats, policy) {
2745
+ const blockers = [];
2746
+ const passRate = getPassRate(stats);
2747
+ if (passRate < policy.min_pass_rate) {
2748
+ blockers.push(
2749
+ `pass_rate ${passRate.toFixed(3)} < min ${policy.min_pass_rate}`
2750
+ );
2751
+ }
2752
+ const timeoutRate = getTimeoutRate(stats);
2753
+ if (timeoutRate > policy.max_timeout_rate) {
2754
+ blockers.push(
2755
+ `timeout_rate ${timeoutRate.toFixed(3)} > max ${policy.max_timeout_rate}`
2756
+ );
2757
+ }
2758
+ const warnFailRate = getWarnPlusFailRate(stats);
2759
+ if (warnFailRate > policy.max_warn_plus_fail_rate) {
2760
+ blockers.push(
2761
+ `warn_plus_fail_rate ${warnFailRate.toFixed(3)} > max ${policy.max_warn_plus_fail_rate}`
2762
+ );
2763
+ }
2764
+ const reasonRate = getReasonCoverageRate(stats);
2765
+ if (reasonRate < policy.min_reason_coverage_rate) {
2766
+ blockers.push(
2767
+ `reason_coverage_rate ${reasonRate.toFixed(3)} < min ${policy.min_reason_coverage_rate}`
2768
+ );
2769
+ }
2770
+ return [blockers.length === 0, blockers];
2771
+ }
2772
+ function checkSentinelHealth(logPath, workspace) {
2773
+ const config = loadGuardsConfig(workspace);
2774
+ const stats = analyzeLog(logPath);
2775
+ const [ready, blockers] = isUpstreamReady(stats, config.sentinel.readiness);
2776
+ return { ready, blockers, stats };
2777
+ }
2778
+
2779
+ // src/team/sentinel-gate.ts
2780
+ function mapFactcheckToBlockers(result) {
2781
+ if (result.verdict === "PASS") {
2782
+ return [];
2783
+ }
2784
+ if (result.mismatches.length === 0) {
2785
+ return [`[factcheck] verdict ${result.verdict}`];
2786
+ }
2787
+ return result.mismatches.map(
2788
+ (mismatch) => `[factcheck] ${mismatch.severity} ${mismatch.check}: ${mismatch.detail}`
2789
+ );
2790
+ }
2791
+ function coerceArray(value) {
2792
+ if (Array.isArray(value)) return value;
2793
+ if (value == null) return [];
2794
+ if (typeof value === "object" && !Array.isArray(value)) return [];
2795
+ return [value];
2796
+ }
2797
+ function sanitizeClaims(raw) {
2798
+ const out = { ...raw };
2799
+ const arrayFields = [
2800
+ "files_modified",
2801
+ "files_created",
2802
+ "files_deleted",
2803
+ "artifacts_expected",
2804
+ "commands_executed",
2805
+ "models_used"
2806
+ ];
2807
+ for (const field of arrayFields) {
2808
+ if (field in out) {
2809
+ out[field] = coerceArray(out[field]);
2810
+ }
2811
+ }
2812
+ return out;
2813
+ }
2814
+ function checkSentinelReadiness(options = {}) {
2815
+ const {
2816
+ logPath,
2817
+ workspace,
2818
+ claims,
2819
+ enabled = loadGuardsConfig(workspace).sentinel.enabled
2820
+ } = options;
2821
+ if (!enabled) {
2822
+ return {
2823
+ ready: true,
2824
+ blockers: [],
2825
+ skipped: true
2826
+ };
2827
+ }
2828
+ const blockers = [];
2829
+ let ranCheck = false;
2830
+ if (logPath) {
2831
+ ranCheck = true;
2832
+ const health = checkSentinelHealth(logPath, workspace);
2833
+ blockers.push(...health.blockers);
2834
+ }
2835
+ if (claims) {
2836
+ ranCheck = true;
2837
+ try {
2838
+ const sanitized = sanitizeClaims(claims);
2839
+ const factcheck = runFactcheck(sanitized, { workspace });
2840
+ blockers.push(...mapFactcheckToBlockers(factcheck));
2841
+ } catch (err) {
2842
+ blockers.push(
2843
+ `[factcheck] execution error: ${err instanceof Error ? err.message : String(err)}`
2844
+ );
2845
+ }
2846
+ }
2847
+ if (!ranCheck) {
2848
+ return {
2849
+ ready: false,
2850
+ blockers: ["[sentinel] gate enabled but no logPath or claims provided \u2014 cannot verify readiness"],
2851
+ skipped: true
2852
+ };
2853
+ }
2854
+ const dedupedBlockers = [...new Set(blockers)];
2855
+ return {
2856
+ ready: dedupedBlockers.length === 0,
2857
+ blockers: dedupedBlockers,
2858
+ skipped: false
2859
+ };
2860
+ }
2861
+ async function waitForSentinelReadiness(options = {}) {
2862
+ const timeoutMs = Math.max(0, options.timeoutMs ?? 3e4);
2863
+ const pollIntervalMs = Math.max(50, options.pollIntervalMs ?? 250);
2864
+ const startedAt = Date.now();
2865
+ let attempts = 1;
2866
+ let latest = checkSentinelReadiness(options);
2867
+ if (latest.ready) {
2868
+ return {
2869
+ ...latest,
2870
+ timedOut: false,
2871
+ elapsedMs: Date.now() - startedAt,
2872
+ attempts
2873
+ };
2874
+ }
2875
+ const deadline = startedAt + timeoutMs;
2876
+ while (Date.now() < deadline) {
2877
+ await new Promise((resolve5) => setTimeout(resolve5, pollIntervalMs));
2878
+ attempts += 1;
2879
+ latest = checkSentinelReadiness(options);
2880
+ if (latest.ready) {
2881
+ return {
2882
+ ...latest,
2883
+ timedOut: false,
2884
+ elapsedMs: Date.now() - startedAt,
2885
+ attempts
2886
+ };
2887
+ }
2888
+ }
2889
+ const timeoutBlocker = `[sentinel] readiness check timed out after ${timeoutMs}ms`;
2890
+ const blockers = latest.blockers.includes(timeoutBlocker) ? latest.blockers : [...latest.blockers, timeoutBlocker];
2891
+ return {
2892
+ ...latest,
2893
+ blockers,
2894
+ timedOut: true,
2895
+ elapsedMs: Date.now() - startedAt,
2896
+ attempts
2897
+ };
2898
+ }
2899
+
2900
+ // src/team/runtime-v2.ts
2901
+ var import_path15 = require("path");
2902
+ var import_fs12 = require("fs");
2903
+ var import_promises6 = require("fs/promises");
2904
+ var import_perf_hooks = require("perf_hooks");
2905
+
2906
+ // src/team/monitor.ts
2907
+ var import_fs10 = require("fs");
2908
+ var import_promises4 = require("fs/promises");
2909
+ var import_path13 = require("path");
2910
+ async function readJsonSafe2(filePath) {
2911
+ try {
2912
+ if (!(0, import_fs10.existsSync)(filePath)) return null;
2913
+ const raw = await (0, import_promises4.readFile)(filePath, "utf-8");
2914
+ return JSON.parse(raw);
2915
+ } catch {
2916
+ return null;
2917
+ }
2918
+ }
2919
+ async function writeAtomic(filePath, data) {
2920
+ const { writeFile: writeFile5 } = await import("fs/promises");
2921
+ await (0, import_promises4.mkdir)((0, import_path13.dirname)(filePath), { recursive: true });
2922
+ const tmpPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
2923
+ await writeFile5(tmpPath, data, "utf-8");
2924
+ const { rename: rename3 } = await import("fs/promises");
2925
+ await rename3(tmpPath, filePath);
2926
+ }
2927
+ async function readTeamConfig(teamName, cwd) {
2928
+ return readJsonSafe2(absPath(cwd, TeamPaths.config(teamName)));
2929
+ }
2930
+ async function readWorkerStatus(teamName, workerName2, cwd) {
2931
+ const data = await readJsonSafe2(absPath(cwd, TeamPaths.workerStatus(teamName, workerName2)));
2932
+ return data ?? { state: "unknown", updated_at: "" };
2933
+ }
2934
+ async function readWorkerHeartbeat(teamName, workerName2, cwd) {
2935
+ return readJsonSafe2(absPath(cwd, TeamPaths.heartbeat(teamName, workerName2)));
2936
+ }
2937
+ async function readMonitorSnapshot(teamName, cwd) {
2938
+ const p = absPath(cwd, TeamPaths.monitorSnapshot(teamName));
2939
+ if (!(0, import_fs10.existsSync)(p)) return null;
2940
+ try {
2941
+ const raw = await (0, import_promises4.readFile)(p, "utf-8");
2942
+ const parsed = JSON.parse(raw);
2943
+ if (!parsed || typeof parsed !== "object") return null;
2944
+ const monitorTimings = (() => {
2945
+ const candidate = parsed.monitorTimings;
2946
+ if (!candidate || typeof candidate !== "object") return void 0;
2947
+ if (typeof candidate.list_tasks_ms !== "number" || typeof candidate.worker_scan_ms !== "number" || typeof candidate.mailbox_delivery_ms !== "number" || typeof candidate.total_ms !== "number" || typeof candidate.updated_at !== "string") {
2948
+ return void 0;
2949
+ }
2950
+ return candidate;
2951
+ })();
2952
+ return {
2953
+ taskStatusById: parsed.taskStatusById ?? {},
2954
+ workerAliveByName: parsed.workerAliveByName ?? {},
2955
+ workerStateByName: parsed.workerStateByName ?? {},
2956
+ workerTurnCountByName: parsed.workerTurnCountByName ?? {},
2957
+ workerTaskIdByName: parsed.workerTaskIdByName ?? {},
2958
+ mailboxNotifiedByMessageId: parsed.mailboxNotifiedByMessageId ?? {},
2959
+ completedEventTaskIds: parsed.completedEventTaskIds ?? {},
2960
+ monitorTimings
2961
+ };
2962
+ } catch {
2963
+ return null;
2964
+ }
2965
+ }
2966
+ async function writeMonitorSnapshot(teamName, snapshot, cwd) {
2967
+ await writeAtomic(absPath(cwd, TeamPaths.monitorSnapshot(teamName)), JSON.stringify(snapshot, null, 2));
2968
+ }
2969
+ async function writeShutdownRequest(teamName, workerName2, fromWorker, cwd) {
2970
+ const data = {
2971
+ from: fromWorker,
2972
+ requested_at: (/* @__PURE__ */ new Date()).toISOString()
2973
+ };
2974
+ await writeAtomic(absPath(cwd, TeamPaths.shutdownRequest(teamName, workerName2)), JSON.stringify(data, null, 2));
2975
+ }
2976
+ async function readShutdownAck(teamName, workerName2, cwd, requestedAfter) {
2977
+ const ack = await readJsonSafe2(
2978
+ absPath(cwd, TeamPaths.shutdownAck(teamName, workerName2))
2979
+ );
2980
+ if (!ack) return null;
2981
+ if (requestedAfter && ack.updated_at) {
2982
+ if (new Date(ack.updated_at).getTime() < new Date(requestedAfter).getTime()) {
2983
+ return null;
2984
+ }
2985
+ }
2986
+ return ack;
2987
+ }
2988
+ async function listTasksFromFiles(teamName, cwd) {
2989
+ const tasksDir = absPath(cwd, TeamPaths.tasks(teamName));
2990
+ if (!(0, import_fs10.existsSync)(tasksDir)) return [];
2991
+ const { readdir: readdir2 } = await import("fs/promises");
2992
+ const entries = await readdir2(tasksDir);
2993
+ const tasks = [];
2994
+ for (const entry of entries) {
2995
+ const match = /^(?:task-)?(\d+)\.json$/.exec(entry);
2996
+ if (!match) continue;
2997
+ const task = await readJsonSafe2(absPath(cwd, `${TeamPaths.tasks(teamName)}/${entry}`));
2998
+ if (task) tasks.push(task);
2999
+ }
3000
+ return tasks.sort((a, b) => Number(a.id) - Number(b.id));
3001
+ }
3002
+ async function writeWorkerInbox(teamName, workerName2, content, cwd) {
3003
+ await writeAtomic(absPath(cwd, TeamPaths.inbox(teamName, workerName2)), content);
3004
+ }
3005
+ async function saveTeamConfig(config, cwd) {
3006
+ await writeAtomic(absPath(cwd, TeamPaths.config(config.name)), JSON.stringify(config, null, 2));
3007
+ }
3008
+ async function cleanupTeamState(teamName, cwd) {
3009
+ const root = absPath(cwd, TeamPaths.root(teamName));
3010
+ const { rm: rm3 } = await import("fs/promises");
3011
+ try {
3012
+ await rm3(root, { recursive: true, force: true });
3013
+ } catch {
3014
+ }
3015
+ }
3016
+
3017
+ // src/team/events.ts
3018
+ var import_crypto = require("crypto");
3019
+ var import_path14 = require("path");
3020
+ var import_promises5 = require("fs/promises");
3021
+ var import_fs11 = require("fs");
3022
+ async function appendTeamEvent(teamName, event, cwd) {
3023
+ const full = {
3024
+ event_id: (0, import_crypto.randomUUID)(),
3025
+ team: teamName,
3026
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
3027
+ ...event
3028
+ };
3029
+ const p = absPath(cwd, TeamPaths.events(teamName));
3030
+ await (0, import_promises5.mkdir)((0, import_path14.dirname)(p), { recursive: true });
3031
+ await (0, import_promises5.appendFile)(p, `${JSON.stringify(full)}
3032
+ `, "utf8");
3033
+ return full;
3034
+ }
3035
+ async function emitMonitorDerivedEvents(teamName, tasks, workers, previousSnapshot, cwd) {
3036
+ if (!previousSnapshot) return;
3037
+ const completedEventTaskIds = { ...previousSnapshot.completedEventTaskIds ?? {} };
3038
+ for (const task of tasks) {
3039
+ const prevStatus = previousSnapshot.taskStatusById?.[task.id];
3040
+ if (!prevStatus || prevStatus === task.status) continue;
3041
+ if (task.status === "completed" && !completedEventTaskIds[task.id]) {
3042
+ await appendTeamEvent(teamName, {
3043
+ type: "task_completed",
3044
+ worker: "leader-fixed",
3045
+ task_id: task.id,
3046
+ reason: `status_transition:${prevStatus}->${task.status}`
3047
+ }, cwd).catch(() => {
3048
+ });
3049
+ completedEventTaskIds[task.id] = true;
3050
+ } else if (task.status === "failed") {
3051
+ await appendTeamEvent(teamName, {
3052
+ type: "task_failed",
3053
+ worker: "leader-fixed",
3054
+ task_id: task.id,
3055
+ reason: `status_transition:${prevStatus}->${task.status}`
3056
+ }, cwd).catch(() => {
3057
+ });
3058
+ }
3059
+ }
3060
+ for (const worker of workers) {
3061
+ const prevAlive = previousSnapshot.workerAliveByName?.[worker.name];
3062
+ const prevState = previousSnapshot.workerStateByName?.[worker.name];
3063
+ if (prevAlive === true && !worker.alive) {
3064
+ await appendTeamEvent(teamName, {
3065
+ type: "worker_stopped",
3066
+ worker: worker.name,
3067
+ reason: "pane_exited"
3068
+ }, cwd).catch(() => {
3069
+ });
3070
+ }
3071
+ if (prevState === "working" && worker.status.state === "idle") {
3072
+ await appendTeamEvent(teamName, {
3073
+ type: "worker_idle",
3074
+ worker: worker.name,
3075
+ reason: `state_transition:${prevState}->${worker.status.state}`
3076
+ }, cwd).catch(() => {
3077
+ });
3078
+ }
3079
+ }
3080
+ }
3081
+
3082
+ // src/team/phase-controller.ts
3083
+ function inferPhase(tasks) {
3084
+ if (tasks.length === 0) return "initializing";
3085
+ const inProgress = tasks.filter((t) => t.status === "in_progress");
3086
+ const pending = tasks.filter((t) => t.status === "pending");
3087
+ const permanentlyFailed = tasks.filter(
3088
+ (t) => t.status === "completed" && t.metadata?.permanentlyFailed === true
3089
+ );
3090
+ const genuinelyCompleted = tasks.filter(
3091
+ (t) => t.status === "completed" && !t.metadata?.permanentlyFailed
3092
+ );
3093
+ const explicitlyFailed = tasks.filter((t) => t.status === "failed");
3094
+ const allFailed = [...permanentlyFailed, ...explicitlyFailed];
3095
+ if (inProgress.length > 0) return "executing";
3096
+ if (pending.length === tasks.length && genuinelyCompleted.length === 0 && allFailed.length === 0) {
3097
+ return "planning";
3098
+ }
3099
+ if (pending.length > 0 && genuinelyCompleted.length > 0 && inProgress.length === 0) {
3100
+ return "executing";
3101
+ }
3102
+ if (allFailed.length > 0) {
3103
+ const hasRetriesRemaining = allFailed.some((t) => {
3104
+ const retryCount = t.metadata?.retryCount ?? 0;
3105
+ const maxRetries = t.metadata?.maxRetries ?? 3;
3106
+ return retryCount < maxRetries;
3107
+ });
3108
+ if (allFailed.length === tasks.length && !hasRetriesRemaining || pending.length === 0 && inProgress.length === 0 && genuinelyCompleted.length === 0 && !hasRetriesRemaining) {
3109
+ return "failed";
3110
+ }
3111
+ if (hasRetriesRemaining) return "fixing";
3112
+ }
3113
+ if (genuinelyCompleted.length === tasks.length && allFailed.length === 0) {
3114
+ return "completed";
3115
+ }
3116
+ return "executing";
3117
+ }
3118
+
3119
+ // src/team/runtime-v2.ts
3120
+ init_team_name();
3121
+ init_tmux_session();
3122
+ function isRuntimeV2Enabled(env = process.env) {
3123
+ const raw = env.OMC_RUNTIME_V2;
3124
+ if (!raw) return true;
3125
+ const normalized = raw.trim().toLowerCase();
3126
+ return !["0", "false", "no", "off"].includes(normalized);
3127
+ }
3128
+ function sanitizeTeamName(name) {
3129
+ return name.replace(/[^a-z0-9-]/g, "").slice(0, 30);
3130
+ }
3131
+ async function isWorkerPaneAlive(paneId) {
3132
+ if (!paneId) return false;
3133
+ try {
3134
+ const { isWorkerAlive: isWorkerAlive2 } = await Promise.resolve().then(() => (init_tmux_session(), tmux_session_exports));
3135
+ return await isWorkerAlive2(paneId);
3136
+ } catch {
3137
+ return false;
3138
+ }
3139
+ }
3140
+ function buildV2TaskInstruction(teamName, workerName2, task, taskId) {
3141
+ return [
3142
+ `## Initial Task Assignment`,
3143
+ `Task ID: ${taskId}`,
3144
+ `Worker: ${workerName2}`,
3145
+ `Subject: ${task.subject}`,
3146
+ ``,
3147
+ task.description,
3148
+ ``,
3149
+ `## Task Lifecycle (CLI API)`,
3150
+ `1. Claim your task:`,
3151
+ ` omc team api claim-task --input '{"team_name":"${teamName}","task_id":"${taskId}","worker":"${workerName2}"}' --json`,
3152
+ `2. Do the work described above`,
3153
+ `3. On completion (use the claim_token from step 1):`,
3154
+ ` omc team api transition-task-status --input '{"team_name":"${teamName}","task_id":"${taskId}","from":"in_progress","to":"completed","claim_token":"<claim_token>"}' --json`,
3155
+ `4. On failure (use the claim_token from step 1):`,
3156
+ ` omc team api transition-task-status --input '{"team_name":"${teamName}","task_id":"${taskId}","from":"in_progress","to":"failed","claim_token":"<claim_token>"}' --json`,
3157
+ ``,
3158
+ `IMPORTANT: Use the CLI API commands above for all task state transitions.`,
3159
+ `Do NOT write done.json or edit task files directly.`,
3160
+ `After completing or failing the task, exit immediately.`
3161
+ ].join("\n");
3162
+ }
3163
+ async function notifyPaneWithRetry2(sessionName2, paneId, message, maxAttempts = 6, retryDelayMs = 350) {
3164
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3165
+ if (await sendToWorker(sessionName2, paneId, message)) {
3166
+ return true;
3167
+ }
3168
+ if (attempt < maxAttempts) {
3169
+ await new Promise((r) => setTimeout(r, retryDelayMs));
3170
+ }
3171
+ }
3172
+ return false;
3173
+ }
3174
+ async function spawnV2Worker(opts) {
3175
+ const { execFile: execFile2 } = await import("child_process");
3176
+ const { promisify: promisify2 } = await import("util");
3177
+ const execFileAsync = promisify2(execFile2);
3178
+ const splitTarget = opts.existingWorkerPaneIds.length === 0 ? opts.leaderPaneId : opts.existingWorkerPaneIds[opts.existingWorkerPaneIds.length - 1];
3179
+ const splitType = opts.existingWorkerPaneIds.length === 0 ? "-h" : "-v";
3180
+ const splitResult = await execFileAsync("tmux", [
3181
+ "split-window",
3182
+ splitType,
3183
+ "-t",
3184
+ splitTarget,
3185
+ "-d",
3186
+ "-P",
3187
+ "-F",
3188
+ "#{pane_id}",
3189
+ "-c",
3190
+ opts.cwd
3191
+ ]);
3192
+ const paneId = splitResult.stdout.split("\n")[0]?.trim();
3193
+ if (!paneId) return null;
3194
+ const usePromptMode = isPromptModeAgent(opts.agentType);
3195
+ const instruction = buildV2TaskInstruction(
3196
+ opts.teamName,
3197
+ opts.workerName,
3198
+ opts.task,
3199
+ opts.taskId
3200
+ );
3201
+ await composeInitialInbox(opts.teamName, opts.workerName, instruction, opts.cwd);
3202
+ const relInboxPath = `.omc/state/team/${opts.teamName}/workers/${opts.workerName}/inbox.md`;
3203
+ const envVars = getWorkerEnv(opts.teamName, opts.workerName, opts.agentType);
3204
+ const resolvedBinaryPath = opts.resolvedBinaryPaths[opts.agentType] ?? resolveValidatedBinaryPath(opts.agentType);
3205
+ const modelForAgent = (() => {
3206
+ if (opts.agentType === "codex") {
3207
+ return process.env.OMC_EXTERNAL_MODELS_DEFAULT_CODEX_MODEL || process.env.OMC_CODEX_DEFAULT_MODEL || void 0;
3208
+ }
3209
+ if (opts.agentType === "gemini") {
3210
+ return process.env.OMC_EXTERNAL_MODELS_DEFAULT_GEMINI_MODEL || process.env.OMC_GEMINI_DEFAULT_MODEL || void 0;
3211
+ }
3212
+ return void 0;
3213
+ })();
3214
+ const [launchBinary, ...launchArgs] = buildWorkerArgv(opts.agentType, {
3215
+ teamName: opts.teamName,
3216
+ workerName: opts.workerName,
3217
+ cwd: opts.cwd,
3218
+ resolvedBinaryPath,
3219
+ model: modelForAgent
3220
+ });
3221
+ if (usePromptMode) {
3222
+ const promptArgs = getPromptModeArgs(
3223
+ opts.agentType,
3224
+ `Read and execute your task from: ${relInboxPath}`
3225
+ );
3226
+ launchArgs.push(...promptArgs);
3227
+ }
3228
+ const paneConfig = {
3229
+ teamName: opts.teamName,
3230
+ workerName: opts.workerName,
3231
+ envVars,
3232
+ launchBinary,
3233
+ launchArgs,
3234
+ cwd: opts.cwd
3235
+ };
3236
+ await spawnWorkerInPane(opts.sessionName, paneId, paneConfig);
3237
+ try {
3238
+ await execFileAsync("tmux", [
3239
+ "select-layout",
3240
+ "-t",
3241
+ opts.sessionName,
3242
+ "main-vertical"
3243
+ ]);
3244
+ } catch {
3245
+ }
3246
+ if (!usePromptMode) {
3247
+ const paneReady = await waitForPaneReady(paneId);
3248
+ if (!paneReady) {
3249
+ try {
3250
+ await execFileAsync("tmux", ["kill-pane", "-t", paneId]);
3251
+ } catch {
3252
+ }
3253
+ return null;
3254
+ }
3255
+ if (opts.agentType === "gemini") {
3256
+ const confirmed = await notifyPaneWithRetry2(opts.sessionName, paneId, "1");
3257
+ if (!confirmed) {
3258
+ try {
3259
+ await execFileAsync("tmux", ["kill-pane", "-t", paneId]);
3260
+ } catch {
3261
+ }
3262
+ return null;
3263
+ }
3264
+ await new Promise((r) => setTimeout(r, 800));
3265
+ }
3266
+ const notified = await notifyPaneWithRetry2(
3267
+ opts.sessionName,
3268
+ paneId,
3269
+ `Read and execute your task from: ${relInboxPath}`
3270
+ );
3271
+ if (!notified) {
3272
+ try {
3273
+ await execFileAsync("tmux", ["kill-pane", "-t", paneId]);
3274
+ } catch {
3275
+ }
3276
+ return null;
3277
+ }
3278
+ }
3279
+ return paneId;
3280
+ }
3281
+ async function startTeamV2(config) {
3282
+ const sanitized = sanitizeTeamName(config.teamName);
3283
+ const leaderCwd = (0, import_path15.resolve)(config.cwd);
3284
+ validateTeamName(sanitized);
3285
+ const agentTypes = config.agentTypes;
3286
+ const resolvedBinaryPaths = {};
3287
+ for (const agentType of [...new Set(agentTypes)]) {
3288
+ resolvedBinaryPaths[agentType] = resolveValidatedBinaryPath(agentType);
3289
+ }
3290
+ await (0, import_promises6.mkdir)(absPath(leaderCwd, TeamPaths.tasks(sanitized)), { recursive: true });
3291
+ await (0, import_promises6.mkdir)(absPath(leaderCwd, TeamPaths.workers(sanitized)), { recursive: true });
3292
+ await (0, import_promises6.mkdir)((0, import_path15.join)(leaderCwd, ".omc", "state", "team", sanitized, "mailbox"), { recursive: true });
3293
+ for (let i = 0; i < config.tasks.length; i++) {
3294
+ const taskId = String(i + 1);
3295
+ const taskFilePath = absPath(leaderCwd, TeamPaths.taskFile(sanitized, taskId));
3296
+ await (0, import_promises6.mkdir)((0, import_path15.join)(taskFilePath, ".."), { recursive: true });
3297
+ await (0, import_promises6.writeFile)(taskFilePath, JSON.stringify({
3298
+ id: taskId,
3299
+ subject: config.tasks[i].subject,
3300
+ description: config.tasks[i].description,
3301
+ status: "pending",
3302
+ owner: null,
3303
+ result: null,
3304
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
3305
+ }, null, 2), "utf-8");
3306
+ }
3307
+ const workerNames = [];
3308
+ for (let i = 0; i < config.tasks.length; i++) {
3309
+ const wName = `worker-${i + 1}`;
3310
+ workerNames.push(wName);
3311
+ const agentType = agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude";
3312
+ await ensureWorkerStateDir(sanitized, wName, leaderCwd);
3313
+ await writeWorkerOverlay({
3314
+ teamName: sanitized,
3315
+ workerName: wName,
3316
+ agentType,
3317
+ tasks: config.tasks.map((t, idx) => ({
3318
+ id: String(idx + 1),
3319
+ subject: t.subject,
3320
+ description: t.description
3321
+ })),
3322
+ cwd: leaderCwd
3323
+ });
3324
+ }
3325
+ const session = await createTeamSession(sanitized, 0, leaderCwd);
3326
+ const sessionName2 = session.sessionName;
3327
+ const leaderPaneId = session.leaderPaneId;
3328
+ const workerPaneIds = [];
3329
+ const workersInfo = workerNames.map((wName, i) => ({
3330
+ name: wName,
3331
+ index: i + 1,
3332
+ role: agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude",
3333
+ assigned_tasks: [],
3334
+ working_dir: leaderCwd
3335
+ }));
3336
+ const teamConfig = {
3337
+ name: sanitized,
3338
+ task: config.tasks.map((t) => t.subject).join("; "),
3339
+ agent_type: agentTypes[0] || "claude",
3340
+ worker_launch_mode: "interactive",
3341
+ worker_count: config.workerCount,
3342
+ max_workers: 20,
3343
+ workers: workersInfo,
3344
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
3345
+ tmux_session: sessionName2,
3346
+ next_task_id: config.tasks.length + 1,
3347
+ leader_cwd: leaderCwd,
3348
+ team_state_root: teamStateRoot(leaderCwd, sanitized),
3349
+ leader_pane_id: leaderPaneId,
3350
+ hud_pane_id: null,
3351
+ resize_hook_name: null,
3352
+ resize_hook_target: null
3353
+ };
3354
+ await saveTeamConfig(teamConfig, leaderCwd);
3355
+ const maxConcurrent = Math.min(agentTypes.length, config.tasks.length);
3356
+ for (let i = 0; i < maxConcurrent; i++) {
3357
+ const wName = workerNames[i];
3358
+ const taskId = String(i + 1);
3359
+ const task = config.tasks[i];
3360
+ if (!task) break;
3361
+ const paneId = await spawnV2Worker({
3362
+ sessionName: sessionName2,
3363
+ leaderPaneId,
3364
+ existingWorkerPaneIds: workerPaneIds,
3365
+ teamName: sanitized,
3366
+ workerName: wName,
3367
+ workerIndex: i,
3368
+ agentType: agentTypes[i % agentTypes.length] ?? agentTypes[0] ?? "claude",
3369
+ task,
3370
+ taskId,
3371
+ cwd: leaderCwd,
3372
+ resolvedBinaryPaths
3373
+ });
3374
+ if (paneId) {
3375
+ workerPaneIds.push(paneId);
3376
+ const workerInfo = workersInfo[i];
3377
+ if (workerInfo) {
3378
+ workerInfo.pane_id = paneId;
3379
+ workerInfo.assigned_tasks = [taskId];
3380
+ }
3381
+ }
3382
+ }
3383
+ teamConfig.workers = workersInfo;
3384
+ await saveTeamConfig(teamConfig, leaderCwd);
3385
+ await appendTeamEvent(sanitized, {
3386
+ type: "team_leader_nudge",
3387
+ worker: "leader-fixed",
3388
+ reason: `start_team_v2: workers=${config.workerCount} tasks=${config.tasks.length} panes=${workerPaneIds.length}`
3389
+ }, leaderCwd);
3390
+ return {
3391
+ teamName: sanitized,
3392
+ sanitizedName: sanitized,
3393
+ sessionName: sessionName2,
3394
+ config: teamConfig,
3395
+ cwd: leaderCwd
3396
+ };
3397
+ }
3398
+ async function monitorTeamV2(teamName, cwd) {
3399
+ const monitorStartMs = import_perf_hooks.performance.now();
3400
+ const sanitized = sanitizeTeamName(teamName);
3401
+ const config = await readTeamConfig(sanitized, cwd);
3402
+ if (!config) return null;
3403
+ const previousSnapshot = await readMonitorSnapshot(sanitized, cwd);
3404
+ const listTasksStartMs = import_perf_hooks.performance.now();
3405
+ const allTasks = await listTasksFromFiles(sanitized, cwd);
3406
+ const listTasksMs = import_perf_hooks.performance.now() - listTasksStartMs;
3407
+ const taskById = new Map(allTasks.map((task) => [task.id, task]));
3408
+ const inProgressByOwner = /* @__PURE__ */ new Map();
3409
+ for (const task of allTasks) {
3410
+ if (task.status !== "in_progress" || !task.owner) continue;
3411
+ const existing = inProgressByOwner.get(task.owner) || [];
3412
+ existing.push(task);
3413
+ inProgressByOwner.set(task.owner, existing);
3414
+ }
3415
+ const workers = [];
3416
+ const deadWorkers = [];
3417
+ const nonReportingWorkers = [];
3418
+ const recommendations = [];
3419
+ const workerScanStartMs = import_perf_hooks.performance.now();
3420
+ const workerSignals = await Promise.all(
3421
+ config.workers.map(async (worker) => {
3422
+ const alive = await isWorkerPaneAlive(worker.pane_id);
3423
+ const [status, heartbeat] = await Promise.all([
3424
+ readWorkerStatus(sanitized, worker.name, cwd),
3425
+ readWorkerHeartbeat(sanitized, worker.name, cwd)
3426
+ ]);
3427
+ return { worker, alive, status, heartbeat };
3428
+ })
3429
+ );
3430
+ const workerScanMs = import_perf_hooks.performance.now() - workerScanStartMs;
3431
+ for (const { worker: w, alive, status, heartbeat } of workerSignals) {
3432
+ const currentTask = status.current_task_id ? taskById.get(status.current_task_id) ?? null : null;
3433
+ const previousTurns = previousSnapshot ? previousSnapshot.workerTurnCountByName[w.name] ?? 0 : null;
3434
+ const previousTaskId = previousSnapshot?.workerTaskIdByName[w.name] ?? "";
3435
+ const currentTaskId = status.current_task_id ?? "";
3436
+ const turnsWithoutProgress = heartbeat && previousTurns !== null && status.state === "working" && currentTask && (currentTask.status === "pending" || currentTask.status === "in_progress") && currentTaskId !== "" && previousTaskId === currentTaskId ? Math.max(0, heartbeat.turn_count - previousTurns) : 0;
3437
+ workers.push({
3438
+ name: w.name,
3439
+ alive,
3440
+ status,
3441
+ heartbeat,
3442
+ assignedTasks: w.assigned_tasks,
3443
+ turnsWithoutProgress
3444
+ });
3445
+ if (!alive) {
3446
+ deadWorkers.push(w.name);
3447
+ const deadWorkerTasks = inProgressByOwner.get(w.name) || [];
3448
+ for (const t of deadWorkerTasks) {
3449
+ recommendations.push(`Reassign task-${t.id} from dead ${w.name}`);
3450
+ }
3451
+ }
3452
+ if (alive && turnsWithoutProgress > 5) {
3453
+ nonReportingWorkers.push(w.name);
3454
+ recommendations.push(`Send reminder to non-reporting ${w.name}`);
3455
+ }
3456
+ }
3457
+ const taskCounts = {
3458
+ total: allTasks.length,
3459
+ pending: allTasks.filter((t) => t.status === "pending").length,
3460
+ blocked: allTasks.filter((t) => t.status === "blocked").length,
3461
+ in_progress: allTasks.filter((t) => t.status === "in_progress").length,
3462
+ completed: allTasks.filter((t) => t.status === "completed").length,
3463
+ failed: allTasks.filter((t) => t.status === "failed").length
3464
+ };
3465
+ const allTasksTerminal2 = taskCounts.pending === 0 && taskCounts.blocked === 0 && taskCounts.in_progress === 0;
3466
+ const phase = inferPhase(allTasks.map((t) => ({
3467
+ status: t.status,
3468
+ metadata: void 0
3469
+ })));
3470
+ await emitMonitorDerivedEvents(
3471
+ sanitized,
3472
+ allTasks,
3473
+ workers.map((w) => ({ name: w.name, alive: w.alive, status: w.status })),
3474
+ previousSnapshot,
3475
+ cwd
3476
+ );
3477
+ const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
3478
+ const totalMs = import_perf_hooks.performance.now() - monitorStartMs;
3479
+ await writeMonitorSnapshot(sanitized, {
3480
+ taskStatusById: Object.fromEntries(allTasks.map((t) => [t.id, t.status])),
3481
+ workerAliveByName: Object.fromEntries(workers.map((w) => [w.name, w.alive])),
3482
+ workerStateByName: Object.fromEntries(workers.map((w) => [w.name, w.status.state])),
3483
+ workerTurnCountByName: Object.fromEntries(workers.map((w) => [w.name, w.heartbeat?.turn_count ?? 0])),
3484
+ workerTaskIdByName: Object.fromEntries(workers.map((w) => [w.name, w.status.current_task_id ?? ""])),
3485
+ mailboxNotifiedByMessageId: previousSnapshot?.mailboxNotifiedByMessageId ?? {},
3486
+ completedEventTaskIds: previousSnapshot?.completedEventTaskIds ?? {},
3487
+ monitorTimings: {
3488
+ list_tasks_ms: Number(listTasksMs.toFixed(2)),
3489
+ worker_scan_ms: Number(workerScanMs.toFixed(2)),
3490
+ mailbox_delivery_ms: 0,
3491
+ total_ms: Number(totalMs.toFixed(2)),
3492
+ updated_at: updatedAt
3493
+ }
3494
+ }, cwd);
3495
+ return {
3496
+ teamName: sanitized,
3497
+ phase,
3498
+ workers,
3499
+ tasks: {
3500
+ ...taskCounts,
3501
+ items: allTasks
3502
+ },
3503
+ allTasksTerminal: allTasksTerminal2,
3504
+ deadWorkers,
3505
+ nonReportingWorkers,
3506
+ recommendations,
3507
+ performance: {
3508
+ list_tasks_ms: Number(listTasksMs.toFixed(2)),
3509
+ worker_scan_ms: Number(workerScanMs.toFixed(2)),
3510
+ total_ms: Number(totalMs.toFixed(2)),
3511
+ updated_at: updatedAt
3512
+ }
3513
+ };
3514
+ }
3515
+ async function shutdownTeamV2(teamName, cwd, options = {}) {
3516
+ const force = options.force === true;
3517
+ const ralph = options.ralph === true;
3518
+ const timeoutMs = options.timeoutMs ?? 15e3;
3519
+ const sanitized = sanitizeTeamName(teamName);
3520
+ const config = await readTeamConfig(sanitized, cwd);
3521
+ if (!config) {
3522
+ await cleanupTeamState(sanitized, cwd);
3523
+ return;
3524
+ }
3525
+ if (!force) {
3526
+ const allTasks = await listTasksFromFiles(sanitized, cwd);
3527
+ const gate = {
3528
+ total: allTasks.length,
3529
+ pending: allTasks.filter((t) => t.status === "pending").length,
3530
+ blocked: allTasks.filter((t) => t.status === "blocked").length,
3531
+ in_progress: allTasks.filter((t) => t.status === "in_progress").length,
3532
+ completed: allTasks.filter((t) => t.status === "completed").length,
3533
+ failed: allTasks.filter((t) => t.status === "failed").length,
3534
+ allowed: false
3535
+ };
3536
+ gate.allowed = gate.pending === 0 && gate.blocked === 0 && gate.in_progress === 0 && gate.failed === 0;
3537
+ await appendTeamEvent(sanitized, {
3538
+ type: "shutdown_gate",
3539
+ worker: "leader-fixed",
3540
+ reason: `allowed=${gate.allowed} total=${gate.total} pending=${gate.pending} blocked=${gate.blocked} in_progress=${gate.in_progress} completed=${gate.completed} failed=${gate.failed}${ralph ? " policy=ralph" : ""}`
3541
+ }, cwd).catch(() => {
3542
+ });
3543
+ if (!gate.allowed) {
3544
+ const hasActiveWork = gate.pending > 0 || gate.blocked > 0 || gate.in_progress > 0;
3545
+ if (ralph && !hasActiveWork) {
3546
+ await appendTeamEvent(sanitized, {
3547
+ type: "team_leader_nudge",
3548
+ worker: "leader-fixed",
3549
+ reason: `gate_bypassed:pending=${gate.pending},blocked=${gate.blocked},in_progress=${gate.in_progress},failed=${gate.failed}`
3550
+ }, cwd).catch(() => {
3551
+ });
3552
+ } else {
3553
+ throw new Error(
3554
+ `shutdown_gate_blocked:pending=${gate.pending},blocked=${gate.blocked},in_progress=${gate.in_progress},failed=${gate.failed}`
3555
+ );
3556
+ }
3557
+ }
3558
+ }
3559
+ if (force) {
3560
+ await appendTeamEvent(sanitized, {
3561
+ type: "shutdown_gate_forced",
3562
+ worker: "leader-fixed",
3563
+ reason: "force_bypass"
3564
+ }, cwd).catch(() => {
3565
+ });
3566
+ }
3567
+ const shutdownRequestTimes = /* @__PURE__ */ new Map();
3568
+ for (const w of config.workers) {
3569
+ try {
3570
+ const requestedAt = (/* @__PURE__ */ new Date()).toISOString();
3571
+ await writeShutdownRequest(sanitized, w.name, "leader-fixed", cwd);
3572
+ shutdownRequestTimes.set(w.name, requestedAt);
3573
+ const shutdownInbox = `# Shutdown Request
3574
+
3575
+ All tasks are complete. Please wrap up and respond with a shutdown acknowledgement.
3576
+
3577
+ Write your ack to: ${TeamPaths.shutdownAck(sanitized, w.name)}
3578
+ Format: {"status":"accept","reason":"ok","updated_at":"<iso>"}
3579
+
3580
+ Then exit your session.
3581
+ `;
3582
+ await writeWorkerInbox(sanitized, w.name, shutdownInbox, cwd);
3583
+ } catch (err) {
3584
+ process.stderr.write(`[team/runtime-v2] shutdown request failed for ${w.name}: ${err}
3585
+ `);
3586
+ }
3587
+ }
3588
+ const deadline = Date.now() + timeoutMs;
3589
+ const rejected = [];
3590
+ const ackedWorkers = /* @__PURE__ */ new Set();
3591
+ while (Date.now() < deadline) {
3592
+ for (const w of config.workers) {
3593
+ if (ackedWorkers.has(w.name)) continue;
3594
+ const ack = await readShutdownAck(sanitized, w.name, cwd, shutdownRequestTimes.get(w.name));
3595
+ if (ack) {
3596
+ ackedWorkers.add(w.name);
3597
+ await appendTeamEvent(sanitized, {
3598
+ type: "shutdown_ack",
3599
+ worker: w.name,
3600
+ reason: ack.status === "reject" ? `reject:${ack.reason || "no_reason"}` : "accept"
3601
+ }, cwd).catch(() => {
3602
+ });
3603
+ if (ack.status === "reject") {
3604
+ rejected.push({ worker: w.name, reason: ack.reason || "no_reason" });
3605
+ }
3606
+ }
3607
+ }
3608
+ if (rejected.length > 0 && !force) {
3609
+ const detail = rejected.map((r) => `${r.worker}:${r.reason}`).join(",");
3610
+ throw new Error(`shutdown_rejected:${detail}`);
3611
+ }
3612
+ const allDone = config.workers.every((w) => ackedWorkers.has(w.name));
3613
+ if (allDone) break;
3614
+ await new Promise((r) => setTimeout(r, 2e3));
3615
+ }
3616
+ try {
3617
+ const { killWorkerPanes: killWorkerPanes2, killTeamSession: killTeamSession2 } = await Promise.resolve().then(() => (init_tmux_session(), tmux_session_exports));
3618
+ const workerPaneIds = config.workers.map((w) => w.pane_id).filter((p) => typeof p === "string" && p.trim().length > 0);
3619
+ await killWorkerPanes2({
3620
+ paneIds: workerPaneIds,
3621
+ leaderPaneId: config.leader_pane_id ?? void 0,
3622
+ teamName: sanitized,
3623
+ cwd
3624
+ });
3625
+ if (config.tmux_session && !config.tmux_session.includes(":")) {
3626
+ await killTeamSession2(config.tmux_session, [], void 0);
3627
+ }
3628
+ } catch (err) {
3629
+ process.stderr.write(`[team/runtime-v2] tmux cleanup: ${err}
3630
+ `);
3631
+ }
3632
+ if (ralph) {
3633
+ const finalTasks = await listTasksFromFiles(sanitized, cwd).catch(() => []);
3634
+ const completed = finalTasks.filter((t) => t.status === "completed").length;
3635
+ const failed = finalTasks.filter((t) => t.status === "failed").length;
3636
+ const pending = finalTasks.filter((t) => t.status === "pending").length;
3637
+ await appendTeamEvent(sanitized, {
3638
+ type: "team_leader_nudge",
3639
+ worker: "leader-fixed",
3640
+ reason: `ralph_cleanup_summary: total=${finalTasks.length} completed=${completed} failed=${failed} pending=${pending} force=${force}`
3641
+ }, cwd).catch(() => {
3642
+ });
3643
+ }
3644
+ await cleanupTeamState(sanitized, cwd);
3645
+ }
3646
+
3647
+ // src/team/runtime-cli.ts
3648
+ function getTerminalStatus(taskCounts, expectedTaskCount) {
3649
+ const active = taskCounts.pending + taskCounts.inProgress;
3650
+ const terminal = taskCounts.completed + taskCounts.failed;
3651
+ if (active !== 0 || terminal !== expectedTaskCount) return null;
3652
+ return taskCounts.failed > 0 ? "failed" : "completed";
3653
+ }
3654
+ function parseWatchdogFailedAt(marker) {
3655
+ if (typeof marker.failedAt === "number") return marker.failedAt;
3656
+ if (typeof marker.failedAt === "string") {
3657
+ const numeric = Number(marker.failedAt);
3658
+ if (Number.isFinite(numeric)) return numeric;
3659
+ const parsed = Date.parse(marker.failedAt);
3660
+ if (Number.isFinite(parsed)) return parsed;
3661
+ }
3662
+ throw new Error("watchdog marker missing valid failedAt");
3663
+ }
3664
+ async function checkWatchdogFailedMarker(stateRoot2, startTime) {
3665
+ const markerPath = (0, import_path16.join)(stateRoot2, "watchdog-failed.json");
3666
+ let raw;
3667
+ try {
3668
+ raw = await (0, import_promises7.readFile)(markerPath, "utf-8");
3669
+ } catch (err) {
3670
+ const code = err.code;
3671
+ if (code === "ENOENT") return { failed: false };
3672
+ return { failed: true, reason: `Failed to read watchdog marker: ${err}` };
3673
+ }
3674
+ let marker;
3675
+ try {
3676
+ marker = JSON.parse(raw);
3677
+ } catch (err) {
3678
+ return { failed: true, reason: `Failed to parse watchdog marker: ${err}` };
3679
+ }
3680
+ let failedAt;
3681
+ try {
3682
+ failedAt = parseWatchdogFailedAt(marker);
3683
+ } catch (err) {
3684
+ return { failed: true, reason: `Invalid watchdog marker: ${err}` };
3685
+ }
3686
+ if (failedAt >= startTime) {
3687
+ return { failed: true, reason: `Watchdog marked team failed at ${new Date(failedAt).toISOString()}` };
3688
+ }
3689
+ try {
3690
+ await (0, import_promises7.unlink)(markerPath);
3691
+ } catch {
3692
+ }
3693
+ return { failed: false };
3694
+ }
3695
+ async function writeResultArtifact(output, finishedAt, jobId = process.env.OMC_JOB_ID, omcJobsDir = process.env.OMC_JOBS_DIR) {
3696
+ if (!jobId || !omcJobsDir) return;
3697
+ const resultPath = (0, import_path16.join)(omcJobsDir, `${jobId}-result.json`);
3698
+ const tmpPath = `${resultPath}.tmp`;
3699
+ await (0, import_promises7.writeFile)(
3700
+ tmpPath,
3701
+ JSON.stringify({ ...output, finishedAt }),
3702
+ "utf-8"
3703
+ );
3704
+ await (0, import_promises7.rename)(tmpPath, resultPath);
3705
+ }
3706
+ async function writePanesFile(jobId, paneIds, leaderPaneId) {
3707
+ const omcJobsDir = process.env.OMC_JOBS_DIR;
3708
+ if (!jobId || !omcJobsDir) return;
3709
+ const panesPath = (0, import_path16.join)(omcJobsDir, `${jobId}-panes.json`);
3710
+ await (0, import_promises7.writeFile)(
3711
+ panesPath + ".tmp",
3712
+ JSON.stringify({ paneIds: [...paneIds], leaderPaneId })
3713
+ );
3714
+ await (0, import_promises7.rename)(panesPath + ".tmp", panesPath);
3715
+ }
3716
+ function collectTaskResults(stateRoot2) {
3717
+ const tasksDir = (0, import_path16.join)(stateRoot2, "tasks");
3718
+ try {
3719
+ const files = (0, import_fs13.readdirSync)(tasksDir).filter((f) => f.endsWith(".json"));
3720
+ return files.map((f) => {
3721
+ try {
3722
+ const raw = (0, import_fs13.readFileSync)((0, import_path16.join)(tasksDir, f), "utf-8");
1391
3723
  const task = JSON.parse(raw);
1392
3724
  return {
1393
3725
  taskId: task.id ?? f.replace(".json", ""),
@@ -1432,10 +3764,12 @@ async function main() {
1432
3764
  agentTypes,
1433
3765
  tasks,
1434
3766
  cwd,
1435
- pollIntervalMs = 5e3
3767
+ pollIntervalMs = 5e3,
3768
+ sentinelGateTimeoutMs = 3e4,
3769
+ sentinelGatePollIntervalMs = 250
1436
3770
  } = input;
1437
3771
  const workerCount = input.workerCount ?? agentTypes.length;
1438
- const stateRoot2 = (0, import_path10.join)(cwd, `.omc/state/team/${teamName}`);
3772
+ const stateRoot2 = (0, import_path16.join)(cwd, `.omc/state/team/${teamName}`);
1439
3773
  const config = {
1440
3774
  teamName,
1441
3775
  workerCount,
@@ -1443,6 +3777,7 @@ async function main() {
1443
3777
  tasks,
1444
3778
  cwd
1445
3779
  };
3780
+ const useV2 = isRuntimeV2Enabled();
1446
3781
  let runtime = null;
1447
3782
  let finalStatus = "failed";
1448
3783
  let pollActive = true;
@@ -1452,22 +3787,26 @@ async function main() {
1452
3787
  async function doShutdown(status) {
1453
3788
  pollActive = false;
1454
3789
  finalStatus = status;
1455
- if (runtime?.stopWatchdog) {
3790
+ if (!useV2 && runtime?.stopWatchdog) {
1456
3791
  runtime.stopWatchdog();
1457
3792
  }
1458
3793
  const taskResults = collectTaskResults(stateRoot2);
1459
3794
  if (runtime) {
1460
3795
  try {
1461
- await shutdownTeam(
1462
- runtime.teamName,
1463
- runtime.sessionName,
1464
- runtime.cwd,
1465
- 2e3,
1466
- runtime.workerPaneIds,
1467
- runtime.leaderPaneId
1468
- );
3796
+ if (useV2) {
3797
+ await shutdownTeamV2(runtime.teamName, runtime.cwd, { force: true });
3798
+ } else {
3799
+ await shutdownTeam(
3800
+ runtime.teamName,
3801
+ runtime.sessionName,
3802
+ runtime.cwd,
3803
+ 2e3,
3804
+ runtime.workerPaneIds,
3805
+ runtime.leaderPaneId
3806
+ );
3807
+ }
1469
3808
  } catch (err) {
1470
- process.stderr.write(`[runtime-cli] shutdownTeam error: ${err}
3809
+ process.stderr.write(`[runtime-cli] shutdown error: ${err}
1471
3810
  `);
1472
3811
  }
1473
3812
  }
@@ -1479,6 +3818,13 @@ async function main() {
1479
3818
  duration,
1480
3819
  workerCount
1481
3820
  };
3821
+ const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
3822
+ try {
3823
+ await writeResultArtifact(output, finishedAt);
3824
+ } catch (err) {
3825
+ process.stderr.write(`[runtime-cli] Failed to persist result artifact: ${err}
3826
+ `);
3827
+ }
1482
3828
  process.stdout.write(JSON.stringify(output) + "\n");
1483
3829
  process.exit(exitCodeFor(status));
1484
3830
  }
@@ -1491,22 +3837,128 @@ async function main() {
1491
3837
  doShutdown("failed").catch(() => process.exit(1));
1492
3838
  });
1493
3839
  try {
1494
- runtime = await startTeam(config);
3840
+ if (useV2) {
3841
+ const v2Runtime = await startTeamV2({
3842
+ teamName,
3843
+ workerCount,
3844
+ agentTypes,
3845
+ tasks,
3846
+ cwd
3847
+ });
3848
+ const v2PaneIds = v2Runtime.config.workers.map((w) => w.pane_id).filter((p) => typeof p === "string");
3849
+ runtime = {
3850
+ teamName: v2Runtime.teamName,
3851
+ sessionName: v2Runtime.sessionName,
3852
+ leaderPaneId: v2Runtime.config.leader_pane_id || "",
3853
+ config,
3854
+ workerNames: v2Runtime.config.workers.map((w) => w.name),
3855
+ workerPaneIds: v2PaneIds,
3856
+ activeWorkers: /* @__PURE__ */ new Map(),
3857
+ cwd
3858
+ };
3859
+ } else {
3860
+ runtime = await startTeam(config);
3861
+ }
1495
3862
  } catch (err) {
1496
3863
  process.stderr.write(`[runtime-cli] startTeam failed: ${err}
1497
3864
  `);
1498
3865
  process.exit(1);
1499
3866
  }
1500
3867
  const jobId = process.env.OMC_JOB_ID;
3868
+ const expectedTaskCount = tasks.length;
3869
+ let mismatchStreak = 0;
1501
3870
  try {
1502
3871
  await writePanesFile(jobId, runtime.workerPaneIds, runtime.leaderPaneId);
1503
3872
  } catch (err) {
1504
3873
  process.stderr.write(`[runtime-cli] Failed to persist pane IDs: ${err}
1505
3874
  `);
1506
3875
  }
3876
+ if (useV2) {
3877
+ process.stderr.write("[runtime-cli] Using runtime v2 (event-driven, no watchdog)\n");
3878
+ while (pollActive) {
3879
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
3880
+ if (!pollActive) break;
3881
+ let snap;
3882
+ try {
3883
+ snap = await monitorTeamV2(teamName, cwd);
3884
+ } catch (err) {
3885
+ process.stderr.write(`[runtime-cli/v2] monitorTeamV2 error: ${err}
3886
+ `);
3887
+ continue;
3888
+ }
3889
+ if (!snap) {
3890
+ process.stderr.write("[runtime-cli/v2] monitorTeamV2 returned null (team config missing?)\n");
3891
+ await doShutdown("failed");
3892
+ return;
3893
+ }
3894
+ try {
3895
+ await writePanesFile(jobId, runtime.workerPaneIds, runtime.leaderPaneId);
3896
+ } catch {
3897
+ }
3898
+ process.stderr.write(
3899
+ `[runtime-cli/v2] phase=${snap.phase} pending=${snap.tasks.pending} in_progress=${snap.tasks.in_progress} completed=${snap.tasks.completed} failed=${snap.tasks.failed} dead=${snap.deadWorkers.length} totalMs=${snap.performance.total_ms}
3900
+ `
3901
+ );
3902
+ const v2Observed = snap.tasks.pending + snap.tasks.in_progress + snap.tasks.completed + snap.tasks.failed;
3903
+ if (v2Observed !== expectedTaskCount) {
3904
+ mismatchStreak += 1;
3905
+ process.stderr.write(
3906
+ `[runtime-cli/v2] Task-count mismatch observed=${v2Observed} expected=${expectedTaskCount} streak=${mismatchStreak}
3907
+ `
3908
+ );
3909
+ if (mismatchStreak >= 2) {
3910
+ process.stderr.write("[runtime-cli/v2] Persistent task-count mismatch \u2014 failing fast\n");
3911
+ await doShutdown("failed");
3912
+ return;
3913
+ }
3914
+ continue;
3915
+ }
3916
+ mismatchStreak = 0;
3917
+ if (snap.allTasksTerminal) {
3918
+ const hasFailures = snap.tasks.failed > 0;
3919
+ if (!hasFailures) {
3920
+ const sentinelLogPath = (0, import_path16.join)(cwd, "sentinel_stop.jsonl");
3921
+ const gateResult = await waitForSentinelReadiness({
3922
+ workspace: cwd,
3923
+ logPath: sentinelLogPath,
3924
+ timeoutMs: sentinelGateTimeoutMs,
3925
+ pollIntervalMs: sentinelGatePollIntervalMs
3926
+ });
3927
+ if (!gateResult.ready) {
3928
+ process.stderr.write(
3929
+ `[runtime-cli/v2] Sentinel gate blocked: ${gateResult.blockers.join("; ")}
3930
+ `
3931
+ );
3932
+ await doShutdown("failed");
3933
+ return;
3934
+ }
3935
+ await doShutdown("completed");
3936
+ } else {
3937
+ process.stderr.write("[runtime-cli/v2] Terminal failure detected from task counts\n");
3938
+ await doShutdown("failed");
3939
+ }
3940
+ return;
3941
+ }
3942
+ const allDead = runtime.workerPaneIds.length > 0 && snap.deadWorkers.length === runtime.workerPaneIds.length;
3943
+ const hasOutstanding = snap.tasks.pending + snap.tasks.in_progress > 0;
3944
+ if (allDead && hasOutstanding) {
3945
+ process.stderr.write("[runtime-cli/v2] All workers dead with outstanding work \u2014 failing\n");
3946
+ await doShutdown("failed");
3947
+ return;
3948
+ }
3949
+ }
3950
+ return;
3951
+ }
1507
3952
  while (pollActive) {
1508
3953
  await new Promise((r) => setTimeout(r, pollIntervalMs));
1509
3954
  if (!pollActive) break;
3955
+ const watchdogCheck = await checkWatchdogFailedMarker(stateRoot2, startTime);
3956
+ if (watchdogCheck.failed) {
3957
+ process.stderr.write(`[runtime-cli] ${watchdogCheck.reason ?? "Watchdog failure marker detected"}
3958
+ `);
3959
+ await doShutdown("failed");
3960
+ return;
3961
+ }
1510
3962
  let snap;
1511
3963
  try {
1512
3964
  snap = await monitorTeam(teamName, cwd, runtime.workerPaneIds);
@@ -1525,10 +3977,46 @@ async function main() {
1525
3977
  `[runtime-cli] phase=${snap.phase} pending=${snap.taskCounts.pending} inProgress=${snap.taskCounts.inProgress} completed=${snap.taskCounts.completed} failed=${snap.taskCounts.failed} dead=${snap.deadWorkers.length} monitorMs=${snap.monitorPerformance.totalMs} tasksMs=${snap.monitorPerformance.listTasksMs} workerMs=${snap.monitorPerformance.workerScanMs}
1526
3978
  `
1527
3979
  );
1528
- if (snap.phase === "completed") {
3980
+ const observedTaskCount = snap.taskCounts.pending + snap.taskCounts.inProgress + snap.taskCounts.completed + snap.taskCounts.failed;
3981
+ if (observedTaskCount !== expectedTaskCount) {
3982
+ mismatchStreak += 1;
3983
+ process.stderr.write(
3984
+ `[runtime-cli] Task-count mismatch observed=${observedTaskCount} expected=${expectedTaskCount} streak=${mismatchStreak}
3985
+ `
3986
+ );
3987
+ if (mismatchStreak >= 2) {
3988
+ process.stderr.write("[runtime-cli] Persistent task-count mismatch detected \u2014 failing fast\n");
3989
+ await doShutdown("failed");
3990
+ return;
3991
+ }
3992
+ continue;
3993
+ }
3994
+ mismatchStreak = 0;
3995
+ const terminalStatus = getTerminalStatus(snap.taskCounts, expectedTaskCount);
3996
+ if (terminalStatus === "completed") {
3997
+ const sentinelLogPath = (0, import_path16.join)(cwd, "sentinel_stop.jsonl");
3998
+ const gateResult = await waitForSentinelReadiness({
3999
+ workspace: cwd,
4000
+ logPath: sentinelLogPath,
4001
+ timeoutMs: sentinelGateTimeoutMs,
4002
+ pollIntervalMs: sentinelGatePollIntervalMs
4003
+ });
4004
+ if (!gateResult.ready) {
4005
+ process.stderr.write(
4006
+ `[runtime-cli] Sentinel gate blocked completion (timedOut=${gateResult.timedOut}, attempts=${gateResult.attempts}, elapsedMs=${gateResult.elapsedMs}): ${gateResult.blockers.join("; ")}
4007
+ `
4008
+ );
4009
+ await doShutdown("failed");
4010
+ return;
4011
+ }
1529
4012
  await doShutdown("completed");
1530
4013
  return;
1531
4014
  }
4015
+ if (terminalStatus === "failed") {
4016
+ process.stderr.write("[runtime-cli] Terminal failure detected from task counts\n");
4017
+ await doShutdown("failed");
4018
+ return;
4019
+ }
1532
4020
  const allWorkersDead = runtime.workerPaneIds.length > 0 && snap.deadWorkers.length === runtime.workerPaneIds.length;
1533
4021
  const hasOutstandingWork = snap.taskCounts.pending + snap.taskCounts.inProgress > 0;
1534
4022
  const deadWorkerFailure = allWorkersDead && hasOutstandingWork;
@@ -1548,3 +4036,9 @@ if (require.main === module) {
1548
4036
  process.exit(1);
1549
4037
  });
1550
4038
  }
4039
+ // Annotate the CommonJS export names for ESM import in node:
4040
+ 0 && (module.exports = {
4041
+ checkWatchdogFailedMarker,
4042
+ getTerminalStatus,
4043
+ writeResultArtifact
4044
+ });