@pennixrv/trellis 0.7.0-beta.8 → 0.7.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (485) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/index.d.ts.map +1 -1
  3. package/dist/cli/index.js +14 -26
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/commands/ablate.js +1 -1
  6. package/dist/commands/ablate.js.map +1 -1
  7. package/dist/commands/init.d.ts.map +1 -1
  8. package/dist/commands/init.js +30 -56
  9. package/dist/commands/init.js.map +1 -1
  10. package/dist/commands/task-progress.d.ts +2 -0
  11. package/dist/commands/task-progress.d.ts.map +1 -1
  12. package/dist/commands/task-progress.js +37 -30
  13. package/dist/commands/task-progress.js.map +1 -1
  14. package/dist/commands/{channel → teamwork}/adapters/claude.d.ts +3 -3
  15. package/dist/commands/teamwork/adapters/claude.d.ts.map +1 -0
  16. package/dist/commands/{channel → teamwork}/adapters/claude.js +3 -3
  17. package/dist/commands/teamwork/adapters/claude.js.map +1 -0
  18. package/dist/commands/{channel → teamwork}/adapters/codex.d.ts +1 -15
  19. package/dist/commands/teamwork/adapters/codex.d.ts.map +1 -0
  20. package/dist/commands/{channel → teamwork}/adapters/codex.js +5 -42
  21. package/dist/commands/teamwork/adapters/codex.js.map +1 -0
  22. package/dist/commands/{channel → teamwork}/adapters/index.d.ts +6 -6
  23. package/dist/commands/teamwork/adapters/index.d.ts.map +1 -0
  24. package/dist/commands/{channel → teamwork}/adapters/index.js +16 -52
  25. package/dist/commands/teamwork/adapters/index.js.map +1 -0
  26. package/dist/commands/{channel → teamwork}/adapters/types.d.ts +2 -2
  27. package/dist/commands/teamwork/adapters/types.d.ts.map +1 -0
  28. package/dist/commands/teamwork/adapters/types.js.map +1 -0
  29. package/dist/commands/{channel → teamwork}/agent-loader.d.ts +2 -4
  30. package/dist/commands/teamwork/agent-loader.d.ts.map +1 -0
  31. package/dist/commands/{channel → teamwork}/agent-loader.js +4 -35
  32. package/dist/commands/teamwork/agent-loader.js.map +1 -0
  33. package/dist/commands/teamwork/artifact.d.ts +177 -0
  34. package/dist/commands/teamwork/artifact.d.ts.map +1 -0
  35. package/dist/commands/teamwork/artifact.js +908 -0
  36. package/dist/commands/teamwork/artifact.js.map +1 -0
  37. package/dist/commands/{channel → teamwork}/context-loader.d.ts +1 -1
  38. package/dist/commands/teamwork/context-loader.d.ts.map +1 -0
  39. package/dist/commands/{channel → teamwork}/context-loader.js +12 -12
  40. package/dist/commands/teamwork/context-loader.js.map +1 -0
  41. package/dist/commands/{channel → teamwork}/context-trust.d.ts +6 -6
  42. package/dist/commands/teamwork/context-trust.d.ts.map +1 -0
  43. package/dist/commands/{channel → teamwork}/context-trust.js +16 -16
  44. package/dist/commands/teamwork/context-trust.js.map +1 -0
  45. package/dist/commands/teamwork/context.d.ts +16 -0
  46. package/dist/commands/teamwork/context.d.ts.map +1 -0
  47. package/dist/commands/{channel → teamwork}/context.js +17 -17
  48. package/dist/commands/teamwork/context.js.map +1 -0
  49. package/dist/commands/teamwork/coordinator.d.ts +89 -0
  50. package/dist/commands/teamwork/coordinator.d.ts.map +1 -0
  51. package/dist/commands/teamwork/coordinator.js +1198 -0
  52. package/dist/commands/teamwork/coordinator.js.map +1 -0
  53. package/dist/commands/teamwork/create.d.ts +23 -0
  54. package/dist/commands/teamwork/create.d.ts.map +1 -0
  55. package/dist/commands/teamwork/create.js +39 -0
  56. package/dist/commands/teamwork/create.js.map +1 -0
  57. package/dist/commands/{channel → teamwork}/dev-parse-trace.d.ts +1 -1
  58. package/dist/commands/teamwork/dev-parse-trace.d.ts.map +1 -0
  59. package/dist/commands/{channel → teamwork}/dev-parse-trace.js +1 -1
  60. package/dist/commands/teamwork/dev-parse-trace.js.map +1 -0
  61. package/dist/commands/{channel → teamwork}/guard.d.ts +27 -46
  62. package/dist/commands/teamwork/guard.d.ts.map +1 -0
  63. package/dist/commands/{channel → teamwork}/guard.js +54 -156
  64. package/dist/commands/teamwork/guard.js.map +1 -0
  65. package/dist/commands/teamwork/index.d.ts +3 -0
  66. package/dist/commands/teamwork/index.d.ts.map +1 -0
  67. package/dist/commands/{channel → teamwork}/index.js +135 -165
  68. package/dist/commands/teamwork/index.js.map +1 -0
  69. package/dist/commands/{channel → teamwork}/interrupt.d.ts +1 -1
  70. package/dist/commands/teamwork/interrupt.d.ts.map +1 -0
  71. package/dist/commands/teamwork/interrupt.js +22 -0
  72. package/dist/commands/teamwork/interrupt.js.map +1 -0
  73. package/dist/commands/teamwork/kill.d.ts +7 -0
  74. package/dist/commands/teamwork/kill.d.ts.map +1 -0
  75. package/dist/commands/{channel → teamwork}/kill.js +21 -21
  76. package/dist/commands/teamwork/kill.js.map +1 -0
  77. package/dist/commands/teamwork/list.d.ts +17 -0
  78. package/dist/commands/teamwork/list.d.ts.map +1 -0
  79. package/dist/commands/{channel → teamwork}/list.js +18 -27
  80. package/dist/commands/teamwork/list.js.map +1 -0
  81. package/dist/commands/{channel → teamwork}/messages.d.ts +1 -1
  82. package/dist/commands/teamwork/messages.d.ts.map +1 -0
  83. package/dist/commands/{channel → teamwork}/messages.js +18 -18
  84. package/dist/commands/teamwork/messages.js.map +1 -0
  85. package/dist/commands/teamwork/profiles.d.ts +25 -0
  86. package/dist/commands/teamwork/profiles.d.ts.map +1 -0
  87. package/dist/commands/teamwork/profiles.js +125 -0
  88. package/dist/commands/teamwork/profiles.js.map +1 -0
  89. package/dist/commands/teamwork/rm.d.ts +27 -0
  90. package/dist/commands/teamwork/rm.d.ts.map +1 -0
  91. package/dist/commands/{channel → teamwork}/rm.js +21 -22
  92. package/dist/commands/teamwork/rm.js.map +1 -0
  93. package/dist/commands/teamwork/run.d.ts +29 -0
  94. package/dist/commands/{channel → teamwork}/run.d.ts.map +1 -1
  95. package/dist/commands/teamwork/run.js +129 -0
  96. package/dist/commands/teamwork/run.js.map +1 -0
  97. package/dist/commands/{channel → teamwork}/send.d.ts +1 -1
  98. package/dist/commands/teamwork/send.d.ts.map +1 -0
  99. package/dist/commands/{channel → teamwork}/send.js +7 -7
  100. package/dist/commands/teamwork/send.js.map +1 -0
  101. package/dist/commands/{channel → teamwork}/spawn.d.ts +8 -12
  102. package/dist/commands/teamwork/spawn.d.ts.map +1 -0
  103. package/dist/commands/{channel → teamwork}/spawn.js +51 -112
  104. package/dist/commands/teamwork/spawn.js.map +1 -0
  105. package/dist/commands/teamwork/store/events.d.ts +22 -0
  106. package/dist/commands/teamwork/store/events.d.ts.map +1 -0
  107. package/dist/commands/{channel → teamwork}/store/events.js +8 -8
  108. package/dist/commands/teamwork/store/events.js.map +1 -0
  109. package/dist/commands/teamwork/store/filter.d.ts +3 -0
  110. package/dist/commands/teamwork/store/filter.d.ts.map +1 -0
  111. package/dist/commands/teamwork/store/filter.js +2 -0
  112. package/dist/commands/teamwork/store/filter.js.map +1 -0
  113. package/dist/commands/{channel → teamwork}/store/lock.d.ts +1 -1
  114. package/dist/commands/teamwork/store/lock.d.ts.map +1 -0
  115. package/dist/commands/{channel → teamwork}/store/lock.js +2 -2
  116. package/dist/commands/teamwork/store/lock.js.map +1 -0
  117. package/dist/commands/{channel → teamwork}/store/paths.d.ts +18 -32
  118. package/dist/commands/teamwork/store/paths.d.ts.map +1 -0
  119. package/dist/commands/{channel → teamwork}/store/paths.js +42 -109
  120. package/dist/commands/teamwork/store/paths.js.map +1 -0
  121. package/dist/commands/teamwork/store/schema.d.ts +18 -0
  122. package/dist/commands/teamwork/store/schema.d.ts.map +1 -0
  123. package/dist/commands/teamwork/store/schema.js +23 -0
  124. package/dist/commands/teamwork/store/schema.js.map +1 -0
  125. package/dist/commands/{channel → teamwork}/store/thread-state.d.ts +3 -3
  126. package/dist/commands/teamwork/store/thread-state.d.ts.map +1 -0
  127. package/dist/commands/{channel → teamwork}/store/thread-state.js +1 -1
  128. package/dist/commands/teamwork/store/thread-state.js.map +1 -0
  129. package/dist/commands/teamwork/store/watch.d.ts +19 -0
  130. package/dist/commands/teamwork/store/watch.d.ts.map +1 -0
  131. package/dist/commands/{channel → teamwork}/store/watch.js +8 -8
  132. package/dist/commands/teamwork/store/watch.js.map +1 -0
  133. package/dist/commands/teamwork/supervisor/idle.d.ts.map +1 -0
  134. package/dist/commands/teamwork/supervisor/idle.js.map +1 -0
  135. package/dist/commands/{channel → teamwork}/supervisor/inbox.d.ts +2 -2
  136. package/dist/commands/teamwork/supervisor/inbox.d.ts.map +1 -0
  137. package/dist/commands/{channel → teamwork}/supervisor/inbox.js +14 -14
  138. package/dist/commands/teamwork/supervisor/inbox.js.map +1 -0
  139. package/dist/commands/{channel → teamwork}/supervisor/shutdown.d.ts +3 -6
  140. package/dist/commands/teamwork/supervisor/shutdown.d.ts.map +1 -0
  141. package/dist/commands/{channel → teamwork}/supervisor/shutdown.js +7 -17
  142. package/dist/commands/teamwork/supervisor/shutdown.js.map +1 -0
  143. package/dist/commands/{channel → teamwork}/supervisor/stdout.d.ts +3 -5
  144. package/dist/commands/teamwork/supervisor/stdout.d.ts.map +1 -0
  145. package/dist/commands/{channel → teamwork}/supervisor/stdout.js +12 -23
  146. package/dist/commands/teamwork/supervisor/stdout.js.map +1 -0
  147. package/dist/commands/teamwork/supervisor/turns.d.ts.map +1 -0
  148. package/dist/commands/teamwork/supervisor/turns.js.map +1 -0
  149. package/dist/commands/{channel → teamwork}/supervisor/warning.d.ts +5 -5
  150. package/dist/commands/teamwork/supervisor/warning.d.ts.map +1 -0
  151. package/dist/commands/{channel → teamwork}/supervisor/warning.js +6 -6
  152. package/dist/commands/teamwork/supervisor/warning.js.map +1 -0
  153. package/dist/commands/{channel → teamwork}/supervisor.d.ts +21 -21
  154. package/dist/commands/teamwork/supervisor.d.ts.map +1 -0
  155. package/dist/commands/{channel → teamwork}/supervisor.js +53 -63
  156. package/dist/commands/teamwork/supervisor.js.map +1 -0
  157. package/dist/commands/teamwork/teammate-adapters.d.ts +31 -0
  158. package/dist/commands/teamwork/teammate-adapters.d.ts.map +1 -0
  159. package/dist/commands/teamwork/teammate-adapters.js +96 -0
  160. package/dist/commands/teamwork/teammate-adapters.js.map +1 -0
  161. package/dist/commands/teamwork/teammate-config.d.ts +19 -0
  162. package/dist/commands/teamwork/teammate-config.d.ts.map +1 -0
  163. package/dist/commands/teamwork/teammate-config.js +97 -0
  164. package/dist/commands/teamwork/teammate-config.js.map +1 -0
  165. package/dist/commands/teamwork/teammate-launch.d.ts +58 -0
  166. package/dist/commands/teamwork/teammate-launch.d.ts.map +1 -0
  167. package/dist/commands/teamwork/teammate-launch.js +125 -0
  168. package/dist/commands/teamwork/teammate-launch.js.map +1 -0
  169. package/dist/commands/teamwork/text-body.d.ts +13 -0
  170. package/dist/commands/teamwork/text-body.d.ts.map +1 -0
  171. package/dist/commands/{channel → teamwork}/text-body.js +3 -3
  172. package/dist/commands/teamwork/text-body.js.map +1 -0
  173. package/dist/commands/teamwork/threads.d.ts +35 -0
  174. package/dist/commands/teamwork/threads.d.ts.map +1 -0
  175. package/dist/commands/{channel → teamwork}/threads.js +19 -19
  176. package/dist/commands/teamwork/threads.js.map +1 -0
  177. package/dist/commands/teamwork/title.d.ts +12 -0
  178. package/dist/commands/teamwork/title.d.ts.map +1 -0
  179. package/dist/commands/teamwork/title.js +24 -0
  180. package/dist/commands/teamwork/title.js.map +1 -0
  181. package/dist/commands/{channel → teamwork}/wait.d.ts +1 -5
  182. package/dist/commands/teamwork/wait.d.ts.map +1 -0
  183. package/dist/commands/{channel → teamwork}/wait.js +8 -21
  184. package/dist/commands/teamwork/wait.js.map +1 -0
  185. package/dist/commands/update.d.ts.map +1 -1
  186. package/dist/commands/update.js +48 -89
  187. package/dist/commands/update.js.map +1 -1
  188. package/dist/commands/workflow.d.ts +1 -1
  189. package/dist/commands/workflow.d.ts.map +1 -1
  190. package/dist/commands/workflow.js +9 -10
  191. package/dist/commands/workflow.js.map +1 -1
  192. package/dist/configurators/claude.d.ts +0 -17
  193. package/dist/configurators/claude.d.ts.map +1 -1
  194. package/dist/configurators/claude.js +2 -61
  195. package/dist/configurators/claude.js.map +1 -1
  196. package/dist/configurators/shared.d.ts.map +1 -1
  197. package/dist/configurators/shared.js +2 -2
  198. package/dist/configurators/shared.js.map +1 -1
  199. package/dist/configurators/snow.js +1 -1
  200. package/dist/configurators/snow.js.map +1 -1
  201. package/dist/configurators/workflow.d.ts +1 -1
  202. package/dist/configurators/workflow.js +5 -5
  203. package/dist/configurators/workflow.js.map +1 -1
  204. package/dist/constants/paths.d.ts +1 -1
  205. package/dist/constants/paths.d.ts.map +1 -1
  206. package/dist/constants/paths.js +1 -1
  207. package/dist/constants/paths.js.map +1 -1
  208. package/dist/migrations/manifests/0.7.0-beta.10.json +9 -0
  209. package/dist/migrations/manifests/0.7.0-beta.11.json +9 -0
  210. package/dist/migrations/manifests/0.7.0-beta.12.json +9 -0
  211. package/dist/migrations/manifests/0.7.0-beta.13.json +9 -0
  212. package/dist/migrations/manifests/0.7.0-beta.14.json +9 -0
  213. package/dist/migrations/manifests/0.7.0-beta.15.json +9 -0
  214. package/dist/migrations/manifests/0.7.0-beta.16.json +9 -0
  215. package/dist/migrations/manifests/0.7.0-beta.17.json +9 -0
  216. package/dist/migrations/manifests/0.7.0-beta.18.json +9 -0
  217. package/dist/migrations/manifests/0.7.0-beta.19.json +9 -0
  218. package/dist/migrations/manifests/0.7.0-beta.20.json +9 -0
  219. package/dist/migrations/manifests/0.7.0-beta.21.json +17 -0
  220. package/dist/migrations/manifests/0.7.0-beta.22.json +9 -0
  221. package/dist/migrations/manifests/0.7.0-beta.23.json +9 -0
  222. package/dist/migrations/manifests/0.7.0-beta.24.json +9 -0
  223. package/dist/migrations/manifests/0.7.0-beta.25.json +9 -0
  224. package/dist/migrations/manifests/0.7.0-beta.26.json +9 -0
  225. package/dist/migrations/manifests/0.7.0-beta.27.json +9 -0
  226. package/dist/migrations/manifests/0.7.0-beta.28.json +9 -0
  227. package/dist/migrations/manifests/0.7.0-beta.29.json +9 -0
  228. package/dist/migrations/manifests/0.7.0-beta.30.json +9 -0
  229. package/dist/migrations/manifests/0.7.0-beta.31.json +9 -0
  230. package/dist/migrations/manifests/0.7.0-beta.32.json +9 -0
  231. package/dist/migrations/manifests/0.7.0-beta.33.json +9 -0
  232. package/dist/migrations/manifests/0.7.0-beta.34.json +9 -0
  233. package/dist/migrations/manifests/0.7.0-beta.35.json +9 -0
  234. package/dist/migrations/manifests/0.7.0-beta.36.json +9 -0
  235. package/dist/migrations/manifests/0.7.0-beta.37.json +9 -0
  236. package/dist/migrations/manifests/0.7.0-beta.38.json +9 -0
  237. package/dist/migrations/manifests/0.7.0-beta.39.json +9 -0
  238. package/dist/migrations/manifests/0.7.0-beta.40.json +9 -0
  239. package/dist/migrations/manifests/0.7.0-beta.41.json +9 -0
  240. package/dist/migrations/manifests/0.7.0-beta.42.json +9 -0
  241. package/dist/migrations/manifests/0.7.0-beta.43.json +9 -0
  242. package/dist/migrations/manifests/0.7.0-beta.44.json +9 -0
  243. package/dist/migrations/manifests/0.7.0-beta.45.json +9 -0
  244. package/dist/migrations/manifests/0.7.0-beta.46.json +9 -0
  245. package/dist/migrations/manifests/0.7.0-beta.47.json +9 -0
  246. package/dist/migrations/manifests/0.7.0-beta.48.json +9 -0
  247. package/dist/migrations/manifests/0.7.0-beta.49.json +13 -0
  248. package/dist/migrations/manifests/0.7.0-beta.50.json +12 -0
  249. package/dist/migrations/manifests/0.7.0-beta.51.json +9 -0
  250. package/dist/migrations/manifests/0.7.0-beta.52.json +9 -0
  251. package/dist/migrations/manifests/0.7.0-beta.53.json +27 -0
  252. package/dist/migrations/manifests/0.7.0-beta.54.json +8 -0
  253. package/dist/migrations/manifests/0.7.0-beta.9.json +9 -0
  254. package/dist/migrations/manifests/0.7.1-beta.0.json +9 -0
  255. package/dist/migrations/manifests/0.7.1.json +9 -0
  256. package/dist/templates/claude/hooks/statusline.py +0 -7
  257. package/dist/templates/codex/hooks/session-start.py +31 -38
  258. package/dist/templates/common/bundled-skills/trellis-decision-space-construction-and-merging/SKILL.md +10 -0
  259. package/dist/templates/common/bundled-skills/trellis-decision-space-construction-and-merging/workflow.md +40 -0
  260. package/dist/templates/common/bundled-skills/trellis-delivery-review-and-closeout/SKILL.md +10 -0
  261. package/dist/templates/common/bundled-skills/trellis-delivery-review-and-closeout/workflow.md +55 -0
  262. package/dist/templates/common/bundled-skills/trellis-goal-exploration-and-requirements/SKILL.md +10 -0
  263. package/dist/templates/common/bundled-skills/trellis-goal-exploration-and-requirements/workflow.md +33 -0
  264. package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +25 -25
  265. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +1 -1
  266. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +13 -19
  267. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-spec-structure.md +1 -1
  268. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-task-lifecycle.md +27 -75
  269. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-workflow.md +17 -56
  270. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +1 -1
  271. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/bundled-skills.md +14 -11
  272. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +0 -33
  273. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/multi-agent-teamwork.md +32 -0
  274. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/spec-system.md +1 -1
  275. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +25 -111
  276. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/workflow.md +19 -60
  277. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +1 -1
  278. package/dist/templates/common/bundled-skills/trellis-session-insight/SKILL.md +1 -1
  279. package/dist/templates/common/bundled-skills/trellis-session-insight/references/cli-quick-reference.md +1 -1
  280. package/dist/templates/common/bundled-skills/trellis-solution-design-and-convergence/SKILL.md +10 -0
  281. package/dist/templates/common/bundled-skills/trellis-solution-design-and-convergence/workflow.md +36 -0
  282. package/dist/templates/common/bundled-skills/trellis-task-implementation/SKILL.md +10 -0
  283. package/dist/templates/common/bundled-skills/trellis-task-implementation/workflow.md +29 -0
  284. package/dist/templates/common/bundled-skills/trellis-teamwork/SKILL.md +73 -0
  285. package/dist/templates/common/bundled-skills/trellis-teamwork/references/coordination-modes.md +29 -0
  286. package/dist/templates/common/bundled-skills/trellis-teamwork/references/teammate-configuration-matrix.md +31 -0
  287. package/dist/templates/common/bundled-skills/trellis-teamwork/references/teammate-processes.md +37 -0
  288. package/dist/templates/common/bundled-skills/trellis-teamwork/references/teamwork-plan-construction.md +78 -0
  289. package/dist/templates/common/commands/continue.md +9 -49
  290. package/dist/templates/common/commands/finish-work.md +10 -58
  291. package/dist/templates/common/commands/start.md +19 -49
  292. package/dist/templates/common/skills/brainstorm.md +11 -191
  293. package/dist/templates/copilot/hooks/session-start.py +30 -26
  294. package/dist/templates/copilot/prompts/brainstorm.prompt.md +7 -150
  295. package/dist/templates/copilot/prompts/finish-work.prompt.md +11 -88
  296. package/dist/templates/copilot/prompts/record-session.prompt.md +4 -12
  297. package/dist/templates/copilot/prompts/start.prompt.md +12 -10
  298. package/dist/templates/dsh/DSH.md +2 -2
  299. package/dist/templates/kiro/agents/trellis.json +2 -2
  300. package/dist/templates/markdown/agents.md +14 -3
  301. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +9 -8
  302. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +1 -1
  303. package/dist/templates/markdown/workspace-index.md +0 -1
  304. package/dist/templates/omp/extensions/trellis/index.ts.txt +28 -17
  305. package/dist/templates/opencode/lib/session-utils.js +20 -25
  306. package/dist/templates/opencode/lib/trellis-context.js +4 -76
  307. package/dist/templates/opencode/plugins/inject-subagent-context.js +5 -4
  308. package/dist/templates/opencode/plugins/inject-workflow-state.js +14 -17
  309. package/dist/templates/shared-hooks/inject-shell-session-context.py +3 -3
  310. package/dist/templates/shared-hooks/inject-subagent-context.py +445 -67
  311. package/dist/templates/shared-hooks/inject-workflow-state.py +44 -36
  312. package/dist/templates/shared-hooks/session-start.py +21 -33
  313. package/dist/templates/trellis/agents/delegated-worktree-primary-agent.md +18 -0
  314. package/dist/templates/trellis/agents/teammate-profiles.json +8 -0
  315. package/dist/templates/trellis/agents/teammate.md +63 -0
  316. package/dist/templates/trellis/config.yaml +29 -38
  317. package/dist/templates/trellis/gitignore.txt +1 -0
  318. package/dist/templates/trellis/index.d.ts +8 -12
  319. package/dist/templates/trellis/index.d.ts.map +1 -1
  320. package/dist/templates/trellis/index.js +14 -25
  321. package/dist/templates/trellis/index.js.map +1 -1
  322. package/dist/templates/trellis/scripts/add_session.py +1 -1
  323. package/dist/templates/trellis/scripts/common/__init__.py +0 -1
  324. package/dist/templates/trellis/scripts/common/active_task.py +136 -100
  325. package/dist/templates/trellis/scripts/common/config.py +7 -9
  326. package/dist/templates/trellis/scripts/common/git_context.py +1 -1
  327. package/dist/templates/trellis/scripts/common/io.py +19 -0
  328. package/dist/templates/trellis/scripts/common/paths.py +0 -1
  329. package/dist/templates/trellis/scripts/common/safe_commit.py +11 -90
  330. package/dist/templates/trellis/scripts/common/session_context.py +1 -8
  331. package/dist/templates/trellis/scripts/common/spec_match.py +1 -1
  332. package/dist/templates/trellis/scripts/common/task_context.py +152 -59
  333. package/dist/templates/trellis/scripts/common/task_continuity.py +598 -0
  334. package/dist/templates/trellis/scripts/common/task_store.py +70 -548
  335. package/dist/templates/trellis/scripts/common/task_utils.py +4 -98
  336. package/dist/templates/trellis/scripts/common/task_workflow.py +1096 -0
  337. package/dist/templates/trellis/scripts/common/tasks.py +5 -8
  338. package/dist/templates/trellis/scripts/common/workflow_phase.py +8 -7
  339. package/dist/templates/trellis/scripts/hooks/linear_sync.py +3 -3
  340. package/dist/templates/trellis/scripts/task.py +119 -377
  341. package/dist/templates/trellis/workflow.md +111 -699
  342. package/dist/utils/agent-refs.d.ts +5 -5
  343. package/dist/utils/agent-refs.js +6 -6
  344. package/dist/utils/file-writer.d.ts +3 -2
  345. package/dist/utils/file-writer.d.ts.map +1 -1
  346. package/dist/utils/file-writer.js +3 -2
  347. package/dist/utils/file-writer.js.map +1 -1
  348. package/dist/utils/managed-paths.d.ts +0 -7
  349. package/dist/utils/managed-paths.d.ts.map +1 -1
  350. package/dist/utils/managed-paths.js +0 -40
  351. package/dist/utils/managed-paths.js.map +1 -1
  352. package/dist/utils/manifest-prune.d.ts.map +1 -1
  353. package/dist/utils/manifest-prune.js +2 -11
  354. package/dist/utils/manifest-prune.js.map +1 -1
  355. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  356. package/dist/utils/uninstall-scrubbers.js +3 -3
  357. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  358. package/dist/utils/workflow-resolver.d.ts +10 -16
  359. package/dist/utils/workflow-resolver.d.ts.map +1 -1
  360. package/dist/utils/workflow-resolver.js +25 -36
  361. package/dist/utils/workflow-resolver.js.map +1 -1
  362. package/package.json +2 -2
  363. package/dist/commands/channel/adapters/claude.d.ts.map +0 -1
  364. package/dist/commands/channel/adapters/claude.js.map +0 -1
  365. package/dist/commands/channel/adapters/codex.d.ts.map +0 -1
  366. package/dist/commands/channel/adapters/codex.js.map +0 -1
  367. package/dist/commands/channel/adapters/index.d.ts.map +0 -1
  368. package/dist/commands/channel/adapters/index.js.map +0 -1
  369. package/dist/commands/channel/adapters/types.d.ts.map +0 -1
  370. package/dist/commands/channel/adapters/types.js.map +0 -1
  371. package/dist/commands/channel/agent-loader.d.ts.map +0 -1
  372. package/dist/commands/channel/agent-loader.js.map +0 -1
  373. package/dist/commands/channel/context-loader.d.ts.map +0 -1
  374. package/dist/commands/channel/context-loader.js.map +0 -1
  375. package/dist/commands/channel/context-trust.d.ts.map +0 -1
  376. package/dist/commands/channel/context-trust.js.map +0 -1
  377. package/dist/commands/channel/context.d.ts +0 -16
  378. package/dist/commands/channel/context.d.ts.map +0 -1
  379. package/dist/commands/channel/context.js.map +0 -1
  380. package/dist/commands/channel/create.d.ts +0 -29
  381. package/dist/commands/channel/create.d.ts.map +0 -1
  382. package/dist/commands/channel/create.js +0 -47
  383. package/dist/commands/channel/create.js.map +0 -1
  384. package/dist/commands/channel/dev-parse-trace.d.ts.map +0 -1
  385. package/dist/commands/channel/dev-parse-trace.js.map +0 -1
  386. package/dist/commands/channel/guard.d.ts.map +0 -1
  387. package/dist/commands/channel/guard.js.map +0 -1
  388. package/dist/commands/channel/index.d.ts +0 -3
  389. package/dist/commands/channel/index.d.ts.map +0 -1
  390. package/dist/commands/channel/index.js.map +0 -1
  391. package/dist/commands/channel/interrupt.d.ts.map +0 -1
  392. package/dist/commands/channel/interrupt.js +0 -22
  393. package/dist/commands/channel/interrupt.js.map +0 -1
  394. package/dist/commands/channel/kill.d.ts +0 -7
  395. package/dist/commands/channel/kill.d.ts.map +0 -1
  396. package/dist/commands/channel/kill.js.map +0 -1
  397. package/dist/commands/channel/list.d.ts +0 -18
  398. package/dist/commands/channel/list.d.ts.map +0 -1
  399. package/dist/commands/channel/list.js.map +0 -1
  400. package/dist/commands/channel/messages.d.ts.map +0 -1
  401. package/dist/commands/channel/messages.js.map +0 -1
  402. package/dist/commands/channel/rm.d.ts +0 -27
  403. package/dist/commands/channel/rm.d.ts.map +0 -1
  404. package/dist/commands/channel/rm.js.map +0 -1
  405. package/dist/commands/channel/run.d.ts +0 -32
  406. package/dist/commands/channel/run.js +0 -141
  407. package/dist/commands/channel/run.js.map +0 -1
  408. package/dist/commands/channel/send.d.ts.map +0 -1
  409. package/dist/commands/channel/send.js.map +0 -1
  410. package/dist/commands/channel/spawn.d.ts.map +0 -1
  411. package/dist/commands/channel/spawn.js.map +0 -1
  412. package/dist/commands/channel/store/events.d.ts +0 -22
  413. package/dist/commands/channel/store/events.d.ts.map +0 -1
  414. package/dist/commands/channel/store/events.js.map +0 -1
  415. package/dist/commands/channel/store/filter.d.ts +0 -3
  416. package/dist/commands/channel/store/filter.d.ts.map +0 -1
  417. package/dist/commands/channel/store/filter.js +0 -2
  418. package/dist/commands/channel/store/filter.js.map +0 -1
  419. package/dist/commands/channel/store/lock.d.ts.map +0 -1
  420. package/dist/commands/channel/store/lock.js.map +0 -1
  421. package/dist/commands/channel/store/paths.d.ts.map +0 -1
  422. package/dist/commands/channel/store/paths.js.map +0 -1
  423. package/dist/commands/channel/store/schema.d.ts +0 -27
  424. package/dist/commands/channel/store/schema.d.ts.map +0 -1
  425. package/dist/commands/channel/store/schema.js +0 -34
  426. package/dist/commands/channel/store/schema.js.map +0 -1
  427. package/dist/commands/channel/store/thread-state.d.ts.map +0 -1
  428. package/dist/commands/channel/store/thread-state.js.map +0 -1
  429. package/dist/commands/channel/store/watch.d.ts +0 -19
  430. package/dist/commands/channel/store/watch.d.ts.map +0 -1
  431. package/dist/commands/channel/store/watch.js.map +0 -1
  432. package/dist/commands/channel/supervisor/idle.d.ts.map +0 -1
  433. package/dist/commands/channel/supervisor/idle.js.map +0 -1
  434. package/dist/commands/channel/supervisor/inbox.d.ts.map +0 -1
  435. package/dist/commands/channel/supervisor/inbox.js.map +0 -1
  436. package/dist/commands/channel/supervisor/shutdown.d.ts.map +0 -1
  437. package/dist/commands/channel/supervisor/shutdown.js.map +0 -1
  438. package/dist/commands/channel/supervisor/stdout.d.ts.map +0 -1
  439. package/dist/commands/channel/supervisor/stdout.js.map +0 -1
  440. package/dist/commands/channel/supervisor/turns.d.ts.map +0 -1
  441. package/dist/commands/channel/supervisor/turns.js.map +0 -1
  442. package/dist/commands/channel/supervisor/warning.d.ts.map +0 -1
  443. package/dist/commands/channel/supervisor/warning.js.map +0 -1
  444. package/dist/commands/channel/supervisor.d.ts.map +0 -1
  445. package/dist/commands/channel/supervisor.js.map +0 -1
  446. package/dist/commands/channel/text-body.d.ts +0 -13
  447. package/dist/commands/channel/text-body.d.ts.map +0 -1
  448. package/dist/commands/channel/text-body.js.map +0 -1
  449. package/dist/commands/channel/threads.d.ts +0 -39
  450. package/dist/commands/channel/threads.d.ts.map +0 -1
  451. package/dist/commands/channel/threads.js.map +0 -1
  452. package/dist/commands/channel/title.d.ts +0 -12
  453. package/dist/commands/channel/title.d.ts.map +0 -1
  454. package/dist/commands/channel/title.js +0 -24
  455. package/dist/commands/channel/title.js.map +0 -1
  456. package/dist/commands/channel/wait.d.ts.map +0 -1
  457. package/dist/commands/channel/wait.js.map +0 -1
  458. package/dist/commands/channel/workers.d.ts +0 -9
  459. package/dist/commands/channel/workers.d.ts.map +0 -1
  460. package/dist/commands/channel/workers.js +0 -31
  461. package/dist/commands/channel/workers.js.map +0 -1
  462. package/dist/templates/common/bundled-skills/trellis-channel/SKILL.md +0 -69
  463. package/dist/templates/common/bundled-skills/trellis-channel/references/command-reference.md +0 -549
  464. package/dist/templates/common/bundled-skills/trellis-channel/references/forum.md +0 -233
  465. package/dist/templates/common/bundled-skills/trellis-channel/references/progress-debugging.md +0 -237
  466. package/dist/templates/common/bundled-skills/trellis-channel/references/subnode-work.md +0 -193
  467. package/dist/templates/common/bundled-skills/trellis-channel/references/workers.md +0 -295
  468. package/dist/templates/common/bundled-skills/trellis-channel/references/workflows.md +0 -131
  469. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/multi-agent-channel.md +0 -70
  470. package/dist/templates/common/bundled-skills/trellis-research-record/SKILL.md +0 -14
  471. package/dist/templates/copilot/prompts/parallel.prompt.md +0 -204
  472. package/dist/templates/trellis/agents/check.md +0 -70
  473. package/dist/templates/trellis/agents/implement.md +0 -71
  474. package/dist/templates/trellis/agents/subnode.env +0 -4
  475. package/dist/templates/trellis/agents/subnode.md +0 -69
  476. package/dist/templates/trellis/scripts/common/context_projection.py +0 -508
  477. package/dist/templates/trellis/scripts/common/continuation_record.py +0 -450
  478. package/dist/templates/trellis/scripts/common/ownership_record.py +0 -439
  479. package/dist/templates/trellis/scripts/subnode_artifact.py +0 -597
  480. package/dist/templates/trellis/scripts/workspace_note.py +0 -126
  481. /package/dist/commands/{channel → teamwork}/adapters/types.js +0 -0
  482. /package/dist/commands/{channel → teamwork}/supervisor/idle.d.ts +0 -0
  483. /package/dist/commands/{channel → teamwork}/supervisor/idle.js +0 -0
  484. /package/dist/commands/{channel → teamwork}/supervisor/turns.d.ts +0 -0
  485. /package/dist/commands/{channel → teamwork}/supervisor/turns.js +0 -0
@@ -0,0 +1,1198 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { isTaskPhaseId, parseTaskWorkflowState, } from "@pennixrv/trellis-core/task";
4
+ import { assertCoordinationTransition, readTeamworkEvents, readCoordinationState, recordCoordinationEvent, } from "@pennixrv/trellis-core/teamwork";
5
+ import { cleanupSettledTeamworkArtifacts, readTeammateReport, writeTeammateQueueFact, writeTeammateClaim, writeTeammateDisposition, validateTeamworkPlan, } from "./artifact.js";
6
+ import { assertTeammateAdapterContract, } from "./teammate-adapters.js";
7
+ import { effectiveTeammateCapacity, resolveTeammateRuntimeConfig, } from "./teammate-config.js";
8
+ import { resolveTeammateProfile } from "./profiles.js";
9
+ import { buildTeammateLaunchSpec, } from "./teammate-launch.js";
10
+ export function assertTeamworkPlanCurrent(plan, taskRoot) {
11
+ const taskFile = path.join(taskRoot, "task.json");
12
+ const stat = fs.lstatSync(taskFile);
13
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 2 * 1024 * 1024) {
14
+ throw new Error("task.json must be a regular file under 2097152 bytes");
15
+ }
16
+ const task = JSON.parse(fs.readFileSync(taskFile, "utf8"));
17
+ if (!task || typeof task !== "object" || Array.isArray(task)) {
18
+ throw new Error("task.json must be an object");
19
+ }
20
+ const record = task;
21
+ if (record.id !== plan.taskId ||
22
+ !record.meta ||
23
+ typeof record.meta !== "object" ||
24
+ Array.isArray(record.meta)) {
25
+ throw new Error("Teamwork plan task_id does not match task.json");
26
+ }
27
+ const meta = record.meta;
28
+ const workflow = parseTaskWorkflowState(meta.task_workflow);
29
+ if (!isTaskPhaseId(plan.phaseId)) {
30
+ throw new Error("Teamwork plan phase_id is not a declared task phase");
31
+ }
32
+ const phase = workflow.phases[plan.phaseId];
33
+ if (workflow.current_phase_id !== plan.phaseId ||
34
+ workflow.task_route_revision !== plan.taskRouteRevision ||
35
+ phase?.status !== "active" ||
36
+ phase.input_revision !== plan.inputRevision) {
37
+ throw new Error("Teamwork plan does not match the current active task phase and revisions");
38
+ }
39
+ }
40
+ async function recoverExistingBatch(input) {
41
+ const projection = await readCoordinationState({
42
+ sessionId: input.plan.sessionId,
43
+ cwd: input.cwd,
44
+ });
45
+ const existing = projection.batches.find((batch) => batch.batchId === input.plan.batchId);
46
+ if (!existing)
47
+ return undefined;
48
+ if (existing.planHash !== input.plan.planHash) {
49
+ throw new Error("batch id already exists with a different plan hash");
50
+ }
51
+ const events = await readTeamworkEvents({
52
+ sessionId: input.plan.sessionId,
53
+ cwd: input.cwd,
54
+ });
55
+ const saved = events.find((event) => event.kind === "coordination" &&
56
+ event.batchId === input.plan.batchId &&
57
+ event.action === "receipt_recorded" &&
58
+ event.payload &&
59
+ (event.payload.status === "ALL_ACCEPTED" ||
60
+ event.payload.status === "SETTLED_WITH_FAILURE"));
61
+ if (saved?.kind === "coordination" && saved.payload) {
62
+ return saved.payload;
63
+ }
64
+ const states = new Map([
65
+ [input.plan.batchId, existing.state],
66
+ ]);
67
+ if (existing.state !== "RECONCILIATION_REQUIRED") {
68
+ await appendTransition({
69
+ sessionId: input.plan.sessionId,
70
+ by: input.by,
71
+ batchId: input.plan.batchId,
72
+ entity: "batch",
73
+ id: input.plan.batchId,
74
+ state: "RECONCILIATION_REQUIRED",
75
+ states,
76
+ planHash: input.plan.planHash,
77
+ payload: { recoveredAfterRestart: true },
78
+ });
79
+ }
80
+ const assignments = input.plan.assignments.map((item) => {
81
+ const current = projection.assignments.find((entry) => entry.batchId === input.plan.batchId &&
82
+ entry.assignmentId === item.assignmentId);
83
+ return {
84
+ assignmentId: item.assignmentId,
85
+ status: current?.state === "ACCEPTED" || current?.state === "FINAL_FAILED"
86
+ ? current.state
87
+ : "UNKNOWN",
88
+ };
89
+ });
90
+ const retryCounts = Object.fromEntries(projection.assignments
91
+ .filter((entry) => entry.batchId === input.plan.batchId)
92
+ .map((entry) => [entry.assignmentId, entry.retryCount]));
93
+ const receipt = {
94
+ schemaVersion: 1,
95
+ batchId: input.plan.batchId,
96
+ status: "RECONCILIATION_REQUIRED",
97
+ assignments,
98
+ capacity: existing.effectiveCapacity ?? input.capacity,
99
+ retryCounts,
100
+ };
101
+ await recordCoordinationEvent({
102
+ sessionId: input.plan.sessionId,
103
+ cwd: input.cwd,
104
+ by: input.by,
105
+ batchId: input.plan.batchId,
106
+ entity: "batch",
107
+ action: "receipt_recorded",
108
+ receiptId: `${input.plan.batchId}:RECONCILIATION_REQUIRED`,
109
+ payload: { ...receipt, reason: "recovered batch requires reconciliation" },
110
+ idempotencyKey: `${input.plan.batchId}:RECONCILIATION_REQUIRED:receipt`,
111
+ });
112
+ return receipt;
113
+ }
114
+ function transitionState(states, key, next, entity) {
115
+ assertCoordinationTransition(entity, states.get(key), next);
116
+ states.set(key, next);
117
+ }
118
+ async function appendTransition(input) {
119
+ transitionState(input.states, input.id, input.state, input.entity);
120
+ await recordCoordinationEvent({
121
+ sessionId: input.sessionId,
122
+ by: input.by,
123
+ batchId: input.batchId,
124
+ entity: input.entity,
125
+ action: "state_transition",
126
+ state: input.state,
127
+ ...(input.assignmentId ? { assignmentId: input.assignmentId } : {}),
128
+ ...(input.attemptId ? { attemptId: input.attemptId } : {}),
129
+ ...(input.teammateId ? { teammateId: input.teammateId } : {}),
130
+ ...(input.slot !== undefined ? { slot: input.slot } : {}),
131
+ ...(input.retryCount !== undefined ? { retryCount: input.retryCount } : {}),
132
+ ...(input.providerSessionId
133
+ ? { providerSessionId: input.providerSessionId }
134
+ : {}),
135
+ ...(input.terminal !== undefined ? { terminal: input.terminal } : {}),
136
+ ...(input.planHash ? { planHash: input.planHash } : {}),
137
+ ...(input.payload ? { payload: input.payload } : {}),
138
+ idempotencyKey: `${input.batchId}:${input.entity}:${input.id}:${input.state}:${input.transitionKey ?? "initial"}`,
139
+ });
140
+ }
141
+ async function appendAction(input) {
142
+ await recordCoordinationEvent({
143
+ sessionId: input.sessionId,
144
+ by: input.by,
145
+ batchId: input.batchId,
146
+ entity: input.entity,
147
+ action: input.action,
148
+ ...(input.id && input.action === "claim_created"
149
+ ? { claimId: input.id }
150
+ : {}),
151
+ ...(input.id && input.action === "command_issued"
152
+ ? { commandId: input.id }
153
+ : {}),
154
+ ...(input.id && input.action === "receipt_recorded"
155
+ ? { receiptId: input.id }
156
+ : {}),
157
+ ...(input.assignmentId ? { assignmentId: input.assignmentId } : {}),
158
+ ...(input.attemptId ? { attemptId: input.attemptId } : {}),
159
+ ...(input.teammateId ? { teammateId: input.teammateId } : {}),
160
+ ...(input.leaseId ? { leaseId: input.leaseId } : {}),
161
+ ...(input.protected !== undefined ? { protected: input.protected } : {}),
162
+ ...(input.reason ? { reason: input.reason } : {}),
163
+ ...(input.payload ? { payload: input.payload } : {}),
164
+ idempotencyKey: `${input.batchId}:${input.action}:${input.id ?? input.leaseId ?? input.attemptId ?? "event"}`,
165
+ });
166
+ }
167
+ function readPlanFile(planPath) {
168
+ const raw = fs.readFileSync(planPath, "utf8");
169
+ return JSON.parse(raw);
170
+ }
171
+ export function loadTeamworkPlan(planPath, taskRoot) {
172
+ const plan = validateTeamworkPlan(readPlanFile(planPath), taskRoot);
173
+ assertTeamworkPlanCurrent(plan, taskRoot);
174
+ return plan;
175
+ }
176
+ export async function runTeamworkCoordinator(input) {
177
+ const plan = validateTeamworkPlan(input.plan, input.taskRoot);
178
+ assertTeamworkPlanCurrent(plan, input.taskRoot);
179
+ const cwd = input.cwd ?? input.taskRoot;
180
+ const frozenLaunches = new Map();
181
+ for (const assignment of plan.assignments) {
182
+ assertTeammateAdapterContract(assignment.provider);
183
+ const profile = resolveTeammateProfile({
184
+ cwd,
185
+ profile: assignment.profile,
186
+ provider: assignment.provider,
187
+ model: assignment.model,
188
+ });
189
+ frozenLaunches.set(assignment.assignmentId, {
190
+ profile,
191
+ launch: buildTeammateLaunchSpec({
192
+ cwd,
193
+ profile,
194
+ host: input.host,
195
+ contextFiles: assignment.contextFiles,
196
+ contextManifests: assignment.contextManifests,
197
+ protectedTargets: plan.protectedTargets,
198
+ }),
199
+ });
200
+ }
201
+ const config = input.config ?? resolveTeammateRuntimeConfig(cwd);
202
+ const capacity = effectiveTeammateCapacity({
203
+ requested: plan.requestedCapacity,
204
+ config,
205
+ verifiedHostCap: input.host.verifiedHostCap,
206
+ });
207
+ const by = input.by ?? "main";
208
+ const batchStates = new Map();
209
+ const assignmentStates = new Map();
210
+ const attemptStates = new Map();
211
+ const teammateStates = new Map();
212
+ await input.guard.acquire({
213
+ batchId: plan.batchId,
214
+ planHash: plan.planHash,
215
+ capacity,
216
+ });
217
+ let guardHeld = true;
218
+ let recovered;
219
+ try {
220
+ recovered = await recoverExistingBatch({ plan, cwd, by, capacity });
221
+ }
222
+ catch (error) {
223
+ await input.guard.release({
224
+ batchId: plan.batchId,
225
+ planHash: plan.planHash,
226
+ capacity,
227
+ });
228
+ guardHeld = false;
229
+ throw error;
230
+ }
231
+ if (recovered) {
232
+ if (recovered.status !== "RECONCILIATION_REQUIRED") {
233
+ await input.guard.release({
234
+ batchId: plan.batchId,
235
+ planHash: plan.planHash,
236
+ capacity,
237
+ });
238
+ guardHeld = false;
239
+ }
240
+ return recovered;
241
+ }
242
+ try {
243
+ for (const [queueIndex, assignment] of plan.assignments.entries()) {
244
+ writeTeammateQueueFact({
245
+ taskRoot: input.taskRoot,
246
+ briefPath: assignment.briefPath,
247
+ taskId: plan.taskId,
248
+ batchId: plan.batchId,
249
+ assignmentId: assignment.assignmentId,
250
+ planHash: plan.planHash,
251
+ briefDigest: assignment.briefDigest,
252
+ sourceDigest: assignment.sourceDigest,
253
+ queueIndex,
254
+ });
255
+ }
256
+ }
257
+ catch (error) {
258
+ await input.guard.release({
259
+ batchId: plan.batchId,
260
+ planHash: plan.planHash,
261
+ capacity,
262
+ });
263
+ guardHeld = false;
264
+ throw error;
265
+ }
266
+ await appendTransition({
267
+ sessionId: plan.sessionId,
268
+ by,
269
+ batchId: plan.batchId,
270
+ entity: "batch",
271
+ id: plan.batchId,
272
+ state: "PREPARED",
273
+ states: batchStates,
274
+ planHash: plan.planHash,
275
+ payload: {
276
+ requestedCapacity: plan.requestedCapacity,
277
+ effectiveCapacity: capacity,
278
+ teammateMaxConcurrency: config.teammate.maxConcurrency,
279
+ maxLiveTeammates: config.guard.maxLiveTeammates,
280
+ nonBatchReserved: config.guard.nonBatchReserved,
281
+ verifiedHostCap: input.host.verifiedHostCap,
282
+ ...(config.sourceDigest ? { configDigest: config.sourceDigest } : {}),
283
+ },
284
+ });
285
+ await appendTransition({
286
+ sessionId: plan.sessionId,
287
+ by,
288
+ batchId: plan.batchId,
289
+ entity: "batch",
290
+ id: plan.batchId,
291
+ state: "VALIDATING_PLAN",
292
+ states: batchStates,
293
+ planHash: plan.planHash,
294
+ });
295
+ for (const assignment of plan.assignments) {
296
+ await appendTransition({
297
+ sessionId: plan.sessionId,
298
+ by,
299
+ batchId: plan.batchId,
300
+ entity: "assignment",
301
+ id: assignment.assignmentId,
302
+ state: "QUEUED",
303
+ states: assignmentStates,
304
+ assignmentId: assignment.assignmentId,
305
+ retryCount: 0,
306
+ });
307
+ await appendAction({
308
+ sessionId: plan.sessionId,
309
+ by,
310
+ batchId: plan.batchId,
311
+ entity: "assignment",
312
+ action: "claim_created",
313
+ id: `${plan.batchId}:assignment:${assignment.assignmentId}`,
314
+ assignmentId: assignment.assignmentId,
315
+ });
316
+ }
317
+ await appendTransition({
318
+ sessionId: plan.sessionId,
319
+ by,
320
+ batchId: plan.batchId,
321
+ entity: "batch",
322
+ id: plan.batchId,
323
+ state: "RUNNING",
324
+ states: batchStates,
325
+ planHash: plan.planHash,
326
+ });
327
+ const pending = [...plan.assignments];
328
+ const active = new Map();
329
+ const waits = new Map();
330
+ const final = new Map();
331
+ const acceptedAttempts = new Map();
332
+ const retryCounts = {};
333
+ async function reconcile(reason) {
334
+ await appendAction({
335
+ sessionId: plan.sessionId,
336
+ by,
337
+ batchId: plan.batchId,
338
+ entity: "batch",
339
+ action: "reconciliation_required",
340
+ reason,
341
+ });
342
+ if (batchStates.get(plan.batchId) !== "RECONCILIATION_REQUIRED") {
343
+ await appendTransition({
344
+ sessionId: plan.sessionId,
345
+ by,
346
+ batchId: plan.batchId,
347
+ entity: "batch",
348
+ id: plan.batchId,
349
+ state: "RECONCILIATION_REQUIRED",
350
+ states: batchStates,
351
+ });
352
+ }
353
+ const receipt = {
354
+ schemaVersion: 1,
355
+ batchId: plan.batchId,
356
+ status: "RECONCILIATION_REQUIRED",
357
+ assignments: plan.assignments.map((item) => ({
358
+ assignmentId: item.assignmentId,
359
+ status: final.get(item.assignmentId) ?? "UNKNOWN",
360
+ })),
361
+ capacity,
362
+ retryCounts,
363
+ };
364
+ await appendAction({
365
+ sessionId: plan.sessionId,
366
+ by,
367
+ batchId: plan.batchId,
368
+ entity: "batch",
369
+ action: "receipt_recorded",
370
+ id: `${plan.batchId}:RECONCILIATION_REQUIRED`,
371
+ payload: { ...receipt, reason },
372
+ });
373
+ return receipt;
374
+ }
375
+ async function dispatch(slot, assignment, retryCount) {
376
+ const attemptId = `${assignment.assignmentId}.attempt.${retryCount}`;
377
+ const teammateId = `${assignment.assignmentId}.teammate.${retryCount}`;
378
+ const frozen = frozenLaunches.get(assignment.assignmentId);
379
+ if (!frozen)
380
+ throw new Error(`missing frozen launch for '${assignment.assignmentId}'`);
381
+ const { profile, launch } = frozen;
382
+ const context = {
383
+ plan,
384
+ assignment,
385
+ attemptId,
386
+ teammateId,
387
+ retryCount,
388
+ profile,
389
+ launch,
390
+ };
391
+ await appendTransition({
392
+ sessionId: plan.sessionId,
393
+ by,
394
+ batchId: plan.batchId,
395
+ entity: "assignment",
396
+ id: assignment.assignmentId,
397
+ state: "ASSIGNED",
398
+ states: assignmentStates,
399
+ assignmentId: assignment.assignmentId,
400
+ attemptId,
401
+ teammateId,
402
+ slot,
403
+ retryCount,
404
+ transitionKey: `assignment:${retryCount}`,
405
+ });
406
+ await appendTransition({
407
+ sessionId: plan.sessionId,
408
+ by,
409
+ batchId: plan.batchId,
410
+ entity: "attempt",
411
+ id: attemptId,
412
+ state: "ASSIGNED",
413
+ states: attemptStates,
414
+ assignmentId: assignment.assignmentId,
415
+ attemptId,
416
+ teammateId,
417
+ retryCount,
418
+ });
419
+ await appendTransition({
420
+ sessionId: plan.sessionId,
421
+ by,
422
+ batchId: plan.batchId,
423
+ entity: "teammate",
424
+ id: teammateId,
425
+ state: "ASSIGNED",
426
+ states: teammateStates,
427
+ attemptId,
428
+ teammateId,
429
+ });
430
+ writeTeammateClaim({
431
+ taskRoot: input.taskRoot,
432
+ briefPath: assignment.briefPath,
433
+ identity: {
434
+ taskId: plan.taskId,
435
+ batchId: plan.batchId,
436
+ assignmentId: assignment.assignmentId,
437
+ attemptId,
438
+ teammateId,
439
+ },
440
+ planHash: plan.planHash,
441
+ briefDigest: assignment.briefDigest,
442
+ sourceDigest: assignment.sourceDigest,
443
+ slot,
444
+ launch,
445
+ });
446
+ await appendAction({
447
+ sessionId: plan.sessionId,
448
+ by,
449
+ batchId: plan.batchId,
450
+ entity: "attempt",
451
+ action: "lease_acquired",
452
+ attemptId,
453
+ leaseId: `${plan.batchId}:${attemptId}`,
454
+ protected: true,
455
+ payload: { slot },
456
+ });
457
+ await appendAction({
458
+ sessionId: plan.sessionId,
459
+ by,
460
+ batchId: plan.batchId,
461
+ entity: "attempt",
462
+ action: "command_issued",
463
+ id: `${plan.batchId}:dispatch:${attemptId}`,
464
+ attemptId,
465
+ teammateId,
466
+ });
467
+ const launchReceipt = await input.runtime.dispatch(context);
468
+ if (launchReceipt?.providerSessionId)
469
+ context.providerSessionId = launchReceipt.providerSessionId;
470
+ await appendTransition({
471
+ sessionId: plan.sessionId,
472
+ by,
473
+ batchId: plan.batchId,
474
+ entity: "attempt",
475
+ id: attemptId,
476
+ state: "RUNNING",
477
+ states: attemptStates,
478
+ assignmentId: assignment.assignmentId,
479
+ attemptId,
480
+ teammateId,
481
+ retryCount,
482
+ ...(context.providerSessionId
483
+ ? { providerSessionId: context.providerSessionId }
484
+ : {}),
485
+ });
486
+ await appendTransition({
487
+ sessionId: plan.sessionId,
488
+ by,
489
+ batchId: plan.batchId,
490
+ entity: "teammate",
491
+ id: teammateId,
492
+ state: "RUNNING",
493
+ states: teammateStates,
494
+ attemptId,
495
+ teammateId,
496
+ ...(context.providerSessionId
497
+ ? { providerSessionId: context.providerSessionId }
498
+ : {}),
499
+ });
500
+ await appendTransition({
501
+ sessionId: plan.sessionId,
502
+ by,
503
+ batchId: plan.batchId,
504
+ entity: "assignment",
505
+ id: assignment.assignmentId,
506
+ state: "EXECUTING",
507
+ states: assignmentStates,
508
+ assignmentId: assignment.assignmentId,
509
+ attemptId,
510
+ teammateId,
511
+ slot,
512
+ retryCount,
513
+ ...(context.providerSessionId
514
+ ? { providerSessionId: context.providerSessionId }
515
+ : {}),
516
+ });
517
+ const activeWork = {
518
+ slot,
519
+ assignment,
520
+ retryCount,
521
+ continuations: 0,
522
+ ...(context.providerSessionId
523
+ ? { providerSessionId: context.providerSessionId }
524
+ : {}),
525
+ context,
526
+ };
527
+ active.set(slot, activeWork);
528
+ waits.set(slot, Promise.resolve()
529
+ .then(() => input.runtime.wait(context))
530
+ .then((result) => ({ slot, result }))
531
+ .catch((error) => ({
532
+ slot,
533
+ result: {
534
+ kind: "reconciliation",
535
+ reason: error instanceof Error ? error.message : String(error),
536
+ },
537
+ })));
538
+ retryCounts[assignment.assignmentId] = retryCount;
539
+ }
540
+ async function release(activeWork) {
541
+ if (activeWork.leaseReleased)
542
+ return;
543
+ await appendAction({
544
+ sessionId: plan.sessionId,
545
+ by,
546
+ batchId: plan.batchId,
547
+ entity: "attempt",
548
+ action: "lease_released",
549
+ attemptId: activeWork.context.attemptId,
550
+ leaseId: `${plan.batchId}:${activeWork.context.attemptId}`,
551
+ protected: false,
552
+ });
553
+ activeWork.leaseReleased = true;
554
+ }
555
+ async function releaseGuard() {
556
+ if (!guardHeld)
557
+ return;
558
+ await input.guard.release({
559
+ batchId: plan.batchId,
560
+ planHash: plan.planHash,
561
+ capacity,
562
+ });
563
+ guardHeld = false;
564
+ }
565
+ async function cancelAndDrain(reason, terminal) {
566
+ if (batchStates.get(plan.batchId) === "RUNNING") {
567
+ await appendTransition({
568
+ sessionId: plan.sessionId,
569
+ by,
570
+ batchId: plan.batchId,
571
+ entity: "batch",
572
+ id: plan.batchId,
573
+ state: "CANCEL_PENDING",
574
+ states: batchStates,
575
+ payload: { reason },
576
+ });
577
+ }
578
+ if (!input.runtime.cancel && active.size > 0 && !terminal) {
579
+ return reconcile(`host cannot confirm cancellation: ${reason}`);
580
+ }
581
+ for (const current of [...active.values()]) {
582
+ let result;
583
+ if (terminal?.current === current) {
584
+ result = terminal.result;
585
+ }
586
+ else {
587
+ try {
588
+ if (!input.runtime.cancel)
589
+ return reconcile(`host cannot cancel active attempt: ${reason}`);
590
+ result = await input.runtime.cancel(current.context);
591
+ }
592
+ catch (error) {
593
+ return reconcile(error instanceof Error ? error.message : String(error));
594
+ }
595
+ }
596
+ if (result.kind === "reconciliation" ||
597
+ result.kind === "timeout" ||
598
+ result.terminal !== true) {
599
+ return reconcile(`attempt cancellation is not terminal: ${reason}`);
600
+ }
601
+ if (result.providerSessionId &&
602
+ current.providerSessionId &&
603
+ result.providerSessionId !== current.providerSessionId) {
604
+ return reconcile("cancellation returned a different host session");
605
+ }
606
+ if (result.providerSessionId) {
607
+ current.providerSessionId = result.providerSessionId;
608
+ current.context.providerSessionId = result.providerSessionId;
609
+ }
610
+ try {
611
+ if (result.kind === "report")
612
+ await complete(current, false);
613
+ else
614
+ await fail(current, result.reason ?? "cancelled by coordinator", false);
615
+ }
616
+ catch (error) {
617
+ return reconcile(error instanceof Error ? error.message : String(error));
618
+ }
619
+ active.delete(current.slot);
620
+ waits.delete(current.slot);
621
+ }
622
+ if (pending.length > 0)
623
+ return reconcile(`queued assignment remains after cancellation: ${reason}`);
624
+ return settle();
625
+ }
626
+ async function fail(activeWork, reason, allowRetry = true) {
627
+ const { assignment, context, retryCount } = activeWork;
628
+ await appendTransition({
629
+ sessionId: plan.sessionId,
630
+ by,
631
+ batchId: plan.batchId,
632
+ entity: "attempt",
633
+ id: context.attemptId,
634
+ state: "FAILED",
635
+ states: attemptStates,
636
+ assignmentId: assignment.assignmentId,
637
+ attemptId: context.attemptId,
638
+ teammateId: context.teammateId,
639
+ retryCount,
640
+ ...(activeWork.providerSessionId
641
+ ? { providerSessionId: activeWork.providerSessionId }
642
+ : {}),
643
+ terminal: true,
644
+ });
645
+ await appendTransition({
646
+ sessionId: plan.sessionId,
647
+ by,
648
+ batchId: plan.batchId,
649
+ entity: "teammate",
650
+ id: context.teammateId,
651
+ state: "FAILED",
652
+ states: teammateStates,
653
+ attemptId: context.attemptId,
654
+ teammateId: context.teammateId,
655
+ ...(activeWork.providerSessionId
656
+ ? { providerSessionId: activeWork.providerSessionId }
657
+ : {}),
658
+ terminal: true,
659
+ });
660
+ if (allowRetry && retryCount < assignment.maxRetries) {
661
+ await release(activeWork);
662
+ retryCounts[assignment.assignmentId] = retryCount + 1;
663
+ pending.unshift(assignment);
664
+ return;
665
+ }
666
+ writeTeammateDisposition({
667
+ taskRoot: input.taskRoot,
668
+ briefPath: assignment.briefPath,
669
+ identity: {
670
+ taskId: plan.taskId,
671
+ batchId: plan.batchId,
672
+ assignmentId: assignment.assignmentId,
673
+ attemptId: context.attemptId,
674
+ teammateId: context.teammateId,
675
+ },
676
+ sourceDigest: assignment.sourceDigest,
677
+ status: "final_failed",
678
+ reason,
679
+ });
680
+ await appendTransition({
681
+ sessionId: plan.sessionId,
682
+ by,
683
+ batchId: plan.batchId,
684
+ entity: "attempt",
685
+ id: context.attemptId,
686
+ state: "FINAL_FAILED",
687
+ states: attemptStates,
688
+ assignmentId: assignment.assignmentId,
689
+ attemptId: context.attemptId,
690
+ teammateId: context.teammateId,
691
+ retryCount,
692
+ payload: { reason },
693
+ });
694
+ await appendTransition({
695
+ sessionId: plan.sessionId,
696
+ by,
697
+ batchId: plan.batchId,
698
+ entity: "assignment",
699
+ id: assignment.assignmentId,
700
+ state: "FINAL_FAILED",
701
+ states: assignmentStates,
702
+ assignmentId: assignment.assignmentId,
703
+ retryCount,
704
+ payload: { reason },
705
+ });
706
+ await release(activeWork);
707
+ final.set(assignment.assignmentId, "FINAL_FAILED");
708
+ }
709
+ async function accept(activeWork) {
710
+ const { assignment, context, retryCount } = activeWork;
711
+ try {
712
+ assertTeamworkPlanCurrent(plan, input.taskRoot);
713
+ }
714
+ catch (error) {
715
+ await fail(activeWork, `task phase changed before report acceptance: ${error instanceof Error ? error.message : String(error)}`, false);
716
+ return;
717
+ }
718
+ writeTeammateDisposition({
719
+ taskRoot: input.taskRoot,
720
+ briefPath: assignment.briefPath,
721
+ identity: {
722
+ taskId: plan.taskId,
723
+ batchId: plan.batchId,
724
+ assignmentId: assignment.assignmentId,
725
+ attemptId: context.attemptId,
726
+ teammateId: context.teammateId,
727
+ },
728
+ sourceDigest: assignment.sourceDigest,
729
+ status: "accepted",
730
+ });
731
+ await appendTransition({
732
+ sessionId: plan.sessionId,
733
+ by,
734
+ batchId: plan.batchId,
735
+ entity: "assignment",
736
+ id: assignment.assignmentId,
737
+ state: "ACCEPTED",
738
+ states: assignmentStates,
739
+ assignmentId: assignment.assignmentId,
740
+ attemptId: context.attemptId,
741
+ teammateId: context.teammateId,
742
+ retryCount,
743
+ });
744
+ await release(activeWork);
745
+ final.set(assignment.assignmentId, "ACCEPTED");
746
+ acceptedAttempts.set(assignment.assignmentId, context.attemptId);
747
+ }
748
+ async function complete(activeWork, allowRetry = true) {
749
+ const { assignment, context, retryCount } = activeWork;
750
+ await recordCoordinationEvent({
751
+ sessionId: plan.sessionId,
752
+ by,
753
+ batchId: plan.batchId,
754
+ entity: "attempt",
755
+ action: "terminal_observed",
756
+ assignmentId: assignment.assignmentId,
757
+ attemptId: context.attemptId,
758
+ teammateId: context.teammateId,
759
+ ...(activeWork.providerSessionId
760
+ ? { providerSessionId: activeWork.providerSessionId }
761
+ : {}),
762
+ terminal: true,
763
+ idempotencyKey: `${plan.batchId}:terminal:${context.attemptId}`,
764
+ });
765
+ let report;
766
+ try {
767
+ report = readTeammateReport({
768
+ taskRoot: input.taskRoot,
769
+ briefPath: assignment.briefPath,
770
+ attemptId: context.attemptId,
771
+ identity: {
772
+ taskId: plan.taskId,
773
+ batchId: plan.batchId,
774
+ assignmentId: assignment.assignmentId,
775
+ teammateId: context.teammateId,
776
+ planHash: plan.planHash,
777
+ phaseId: plan.phaseId,
778
+ taskRouteRevision: plan.taskRouteRevision,
779
+ inputRevision: plan.inputRevision,
780
+ },
781
+ sourceDigest: assignment.sourceDigest,
782
+ });
783
+ }
784
+ catch (error) {
785
+ await fail(activeWork, error instanceof Error ? error.message : String(error), allowRetry);
786
+ return;
787
+ }
788
+ if (input.runtime.validateReport &&
789
+ !(await input.runtime.validateReport(context, report))) {
790
+ await fail(activeWork, "report rejected by acceptance contract", allowRetry);
791
+ return;
792
+ }
793
+ try {
794
+ assertTeamworkPlanCurrent(plan, input.taskRoot);
795
+ }
796
+ catch (error) {
797
+ await fail(activeWork, `task phase changed before report acceptance: ${error instanceof Error ? error.message : String(error)}`, false);
798
+ return;
799
+ }
800
+ await appendTransition({
801
+ sessionId: plan.sessionId,
802
+ by,
803
+ batchId: plan.batchId,
804
+ entity: "teammate",
805
+ id: context.teammateId,
806
+ state: "REPORT_SUBMITTED",
807
+ states: teammateStates,
808
+ attemptId: context.attemptId,
809
+ teammateId: context.teammateId,
810
+ ...(activeWork.providerSessionId
811
+ ? { providerSessionId: activeWork.providerSessionId }
812
+ : {}),
813
+ terminal: true,
814
+ });
815
+ await appendTransition({
816
+ sessionId: plan.sessionId,
817
+ by,
818
+ batchId: plan.batchId,
819
+ entity: "attempt",
820
+ id: context.attemptId,
821
+ state: "REPORT_SUBMITTED",
822
+ states: attemptStates,
823
+ assignmentId: assignment.assignmentId,
824
+ attemptId: context.attemptId,
825
+ teammateId: context.teammateId,
826
+ retryCount,
827
+ ...(activeWork.providerSessionId
828
+ ? { providerSessionId: activeWork.providerSessionId }
829
+ : {}),
830
+ terminal: true,
831
+ });
832
+ await appendTransition({
833
+ sessionId: plan.sessionId,
834
+ by,
835
+ batchId: plan.batchId,
836
+ entity: "assignment",
837
+ id: assignment.assignmentId,
838
+ state: "REPORT_PENDING",
839
+ states: assignmentStates,
840
+ assignmentId: assignment.assignmentId,
841
+ attemptId: context.attemptId,
842
+ teammateId: context.teammateId,
843
+ retryCount,
844
+ });
845
+ await appendTransition({
846
+ sessionId: plan.sessionId,
847
+ by,
848
+ batchId: plan.batchId,
849
+ entity: "assignment",
850
+ id: assignment.assignmentId,
851
+ state: "VALIDATING",
852
+ states: assignmentStates,
853
+ assignmentId: assignment.assignmentId,
854
+ attemptId: context.attemptId,
855
+ teammateId: context.teammateId,
856
+ retryCount,
857
+ });
858
+ await accept(activeWork);
859
+ }
860
+ async function settle() {
861
+ await appendTransition({
862
+ sessionId: plan.sessionId,
863
+ by,
864
+ batchId: plan.batchId,
865
+ entity: "batch",
866
+ id: plan.batchId,
867
+ state: "SETTLING",
868
+ states: batchStates,
869
+ });
870
+ const cleanupFailures = cleanupSettledTeamworkArtifacts({
871
+ taskRoot: input.taskRoot,
872
+ assignments: plan.assignments,
873
+ acceptedAttempts,
874
+ });
875
+ if (cleanupFailures.length > 0) {
876
+ return reconcile(`Teamwork batch cleanup failed: ${cleanupFailures.join("; ")}`);
877
+ }
878
+ const accepted = plan.assignments.every((assignment) => final.get(assignment.assignmentId) === "ACCEPTED");
879
+ const status = accepted ? "ALL_ACCEPTED" : "SETTLED_WITH_FAILURE";
880
+ await appendTransition({
881
+ sessionId: plan.sessionId,
882
+ by,
883
+ batchId: plan.batchId,
884
+ entity: "batch",
885
+ id: plan.batchId,
886
+ state: status,
887
+ states: batchStates,
888
+ });
889
+ const receipt = {
890
+ schemaVersion: 1,
891
+ batchId: plan.batchId,
892
+ status,
893
+ assignments: plan.assignments.map((assignment) => ({
894
+ assignmentId: assignment.assignmentId,
895
+ status: final.get(assignment.assignmentId) ?? "FINAL_FAILED",
896
+ })),
897
+ capacity,
898
+ retryCounts,
899
+ evaluationGroups: [
900
+ ...new Set(plan.assignments
901
+ .map((assignment) => assignment.evaluationGroup?.id)
902
+ .filter((id) => id !== undefined)),
903
+ ].map((id) => ({
904
+ id,
905
+ status: plan.assignments
906
+ .filter((assignment) => assignment.evaluationGroup?.id === id)
907
+ .every((assignment) => final.get(assignment.assignmentId) === "ACCEPTED")
908
+ ? "COMPLETE"
909
+ : "INCOMPLETE",
910
+ })),
911
+ };
912
+ await appendAction({
913
+ sessionId: plan.sessionId,
914
+ by,
915
+ batchId: plan.batchId,
916
+ entity: "batch",
917
+ action: "receipt_recorded",
918
+ id: `${plan.batchId}:${status}`,
919
+ payload: { ...receipt },
920
+ });
921
+ await assertTeamworkReceiptDurable(plan.sessionId, plan.batchId, plan.planHash, cwd);
922
+ await releaseGuard();
923
+ return receipt;
924
+ }
925
+ async function fill() {
926
+ while (active.size < capacity && pending.length > 0) {
927
+ const assignment = pending.shift();
928
+ if (!assignment)
929
+ return;
930
+ const retryCount = retryCounts[assignment.assignmentId] ?? 0;
931
+ let slot = 0;
932
+ while (active.has(slot))
933
+ slot += 1;
934
+ await dispatch(slot, assignment, retryCount);
935
+ }
936
+ }
937
+ try {
938
+ await fill();
939
+ }
940
+ catch (error) {
941
+ return reconcile(error instanceof Error ? error.message : String(error));
942
+ }
943
+ while (active.size > 0) {
944
+ let next;
945
+ let timer;
946
+ try {
947
+ const remaining = Math.max(0, Date.parse(plan.deadline) - Date.now());
948
+ next = await Promise.race([
949
+ ...waits.values(),
950
+ new Promise((resolve) => {
951
+ timer = setTimeout(() => resolve({ deadlineExpired: true }), Math.min(remaining, 2_147_483_647));
952
+ }),
953
+ ]);
954
+ }
955
+ catch (error) {
956
+ return reconcile(error instanceof Error ? error.message : String(error));
957
+ }
958
+ finally {
959
+ if (timer)
960
+ clearTimeout(timer);
961
+ }
962
+ if ("deadlineExpired" in next) {
963
+ if (Date.now() >= Date.parse(plan.deadline))
964
+ return cancelAndDrain("batch deadline elapsed");
965
+ continue;
966
+ }
967
+ const current = active.get(next.slot);
968
+ if (!current)
969
+ continue;
970
+ waits.delete(next.slot);
971
+ if ((next.result.kind === "report" ||
972
+ next.result.kind === "failed" ||
973
+ next.result.kind === "cancelled") &&
974
+ next.result.terminal !== true) {
975
+ return reconcile("host outcome lacks terminal confirmation");
976
+ }
977
+ if (next.result.providerSessionId) {
978
+ if (current.providerSessionId &&
979
+ current.providerSessionId !== next.result.providerSessionId) {
980
+ return reconcile("host session identity changed during one attempt");
981
+ }
982
+ current.providerSessionId = next.result.providerSessionId;
983
+ current.context.providerSessionId = next.result.providerSessionId;
984
+ }
985
+ if (next.result.kind === "reconciliation") {
986
+ return reconcile(next.result.reason);
987
+ }
988
+ if (next.result.kind === "cancelled") {
989
+ return cancelAndDrain(next.result.reason ?? "runtime cancellation", {
990
+ current,
991
+ result: next.result,
992
+ });
993
+ }
994
+ let releaseSlot = true;
995
+ if (next.result.kind === "timeout") {
996
+ current.continuations += 1;
997
+ if (current.continuations > 8) {
998
+ return reconcile("continuation limit exceeded");
999
+ }
1000
+ else {
1001
+ await appendTransition({
1002
+ sessionId: plan.sessionId,
1003
+ by,
1004
+ batchId: plan.batchId,
1005
+ entity: "attempt",
1006
+ id: current.context.attemptId,
1007
+ state: "TIMEOUT_YIELDED",
1008
+ states: attemptStates,
1009
+ assignmentId: current.assignment.assignmentId,
1010
+ attemptId: current.context.attemptId,
1011
+ teammateId: current.context.teammateId,
1012
+ retryCount: current.retryCount,
1013
+ ...(current.providerSessionId
1014
+ ? { providerSessionId: current.providerSessionId }
1015
+ : {}),
1016
+ transitionKey: `continuation:${current.continuations}`,
1017
+ });
1018
+ await appendTransition({
1019
+ sessionId: plan.sessionId,
1020
+ by,
1021
+ batchId: plan.batchId,
1022
+ entity: "teammate",
1023
+ id: current.context.teammateId,
1024
+ state: "TIMEOUT_YIELDED",
1025
+ states: teammateStates,
1026
+ attemptId: current.context.attemptId,
1027
+ teammateId: current.context.teammateId,
1028
+ ...(current.providerSessionId
1029
+ ? { providerSessionId: current.providerSessionId }
1030
+ : {}),
1031
+ transitionKey: `continuation:${current.continuations}`,
1032
+ });
1033
+ await appendTransition({
1034
+ sessionId: plan.sessionId,
1035
+ by,
1036
+ batchId: plan.batchId,
1037
+ entity: "assignment",
1038
+ id: current.assignment.assignmentId,
1039
+ state: "WAITING_FOR_MAIN_COMMAND",
1040
+ states: assignmentStates,
1041
+ assignmentId: current.assignment.assignmentId,
1042
+ attemptId: current.context.attemptId,
1043
+ teammateId: current.context.teammateId,
1044
+ retryCount: current.retryCount,
1045
+ ...(current.providerSessionId
1046
+ ? { providerSessionId: current.providerSessionId }
1047
+ : {}),
1048
+ transitionKey: `continuation:${current.continuations}`,
1049
+ });
1050
+ await appendTransition({
1051
+ sessionId: plan.sessionId,
1052
+ by,
1053
+ batchId: plan.batchId,
1054
+ entity: "attempt",
1055
+ id: current.context.attemptId,
1056
+ state: "WAITING_FOR_MAIN_COMMAND",
1057
+ states: attemptStates,
1058
+ assignmentId: current.assignment.assignmentId,
1059
+ attemptId: current.context.attemptId,
1060
+ teammateId: current.context.teammateId,
1061
+ retryCount: current.retryCount,
1062
+ ...(current.providerSessionId
1063
+ ? { providerSessionId: current.providerSessionId }
1064
+ : {}),
1065
+ transitionKey: `continuation:${current.continuations}`,
1066
+ });
1067
+ await appendTransition({
1068
+ sessionId: plan.sessionId,
1069
+ by,
1070
+ batchId: plan.batchId,
1071
+ entity: "teammate",
1072
+ id: current.context.teammateId,
1073
+ state: "WAITING_FOR_MAIN_COMMAND",
1074
+ states: teammateStates,
1075
+ attemptId: current.context.attemptId,
1076
+ teammateId: current.context.teammateId,
1077
+ ...(current.providerSessionId
1078
+ ? { providerSessionId: current.providerSessionId }
1079
+ : {}),
1080
+ transitionKey: `continuation:${current.continuations}`,
1081
+ });
1082
+ let continued;
1083
+ try {
1084
+ continued = await input.runtime.continue(current.context);
1085
+ }
1086
+ catch (error) {
1087
+ return reconcile(error instanceof Error ? error.message : String(error));
1088
+ }
1089
+ if (continued.providerSessionId &&
1090
+ current.providerSessionId &&
1091
+ continued.providerSessionId !== current.providerSessionId) {
1092
+ return reconcile("continuation returned a different host session");
1093
+ }
1094
+ if (continued.providerSessionId) {
1095
+ current.providerSessionId = continued.providerSessionId;
1096
+ current.context.providerSessionId = continued.providerSessionId;
1097
+ }
1098
+ await appendTransition({
1099
+ sessionId: plan.sessionId,
1100
+ by,
1101
+ batchId: plan.batchId,
1102
+ entity: "attempt",
1103
+ id: current.context.attemptId,
1104
+ state: "RUNNING",
1105
+ states: attemptStates,
1106
+ assignmentId: current.assignment.assignmentId,
1107
+ attemptId: current.context.attemptId,
1108
+ teammateId: current.context.teammateId,
1109
+ retryCount: current.retryCount,
1110
+ ...(current.providerSessionId
1111
+ ? { providerSessionId: current.providerSessionId }
1112
+ : {}),
1113
+ transitionKey: `continuation:${current.continuations}`,
1114
+ });
1115
+ await appendTransition({
1116
+ sessionId: plan.sessionId,
1117
+ by,
1118
+ batchId: plan.batchId,
1119
+ entity: "teammate",
1120
+ id: current.context.teammateId,
1121
+ state: "RUNNING",
1122
+ states: teammateStates,
1123
+ attemptId: current.context.attemptId,
1124
+ teammateId: current.context.teammateId,
1125
+ ...(current.providerSessionId
1126
+ ? { providerSessionId: current.providerSessionId }
1127
+ : {}),
1128
+ transitionKey: `continuation:${current.continuations}`,
1129
+ });
1130
+ await appendTransition({
1131
+ sessionId: plan.sessionId,
1132
+ by,
1133
+ batchId: plan.batchId,
1134
+ entity: "assignment",
1135
+ id: current.assignment.assignmentId,
1136
+ state: "EXECUTING",
1137
+ states: assignmentStates,
1138
+ assignmentId: current.assignment.assignmentId,
1139
+ attemptId: current.context.attemptId,
1140
+ teammateId: current.context.teammateId,
1141
+ retryCount: current.retryCount,
1142
+ ...(current.providerSessionId
1143
+ ? { providerSessionId: current.providerSessionId }
1144
+ : {}),
1145
+ transitionKey: `continuation:${current.continuations}`,
1146
+ });
1147
+ waits.set(next.slot, Promise.resolve({ slot: next.slot, result: continued }));
1148
+ releaseSlot = false;
1149
+ }
1150
+ }
1151
+ else if (next.result.kind === "report") {
1152
+ try {
1153
+ await complete(current);
1154
+ }
1155
+ catch (error) {
1156
+ return reconcile(error instanceof Error ? error.message : String(error));
1157
+ }
1158
+ }
1159
+ else {
1160
+ try {
1161
+ await fail(current, next.result.reason);
1162
+ }
1163
+ catch (error) {
1164
+ return reconcile(error instanceof Error ? error.message : String(error));
1165
+ }
1166
+ }
1167
+ if (releaseSlot) {
1168
+ active.delete(next.slot);
1169
+ waits.delete(next.slot);
1170
+ try {
1171
+ await fill();
1172
+ }
1173
+ catch (error) {
1174
+ return reconcile(error instanceof Error ? error.message : String(error));
1175
+ }
1176
+ }
1177
+ }
1178
+ return settle();
1179
+ }
1180
+ export async function assertTeamworkReceiptDurable(sessionId, batchId, planHash, cwd) {
1181
+ const [state, events] = await Promise.all([
1182
+ readCoordinationState({ sessionId, ...(cwd ? { cwd } : {}) }),
1183
+ readTeamworkEvents({ sessionId, ...(cwd ? { cwd } : {}) }),
1184
+ ]);
1185
+ const batch = state.batches.find((entry) => entry.batchId === batchId);
1186
+ if (batch?.planHash !== planHash ||
1187
+ (batch.state !== "ALL_ACCEPTED" && batch.state !== "SETTLED_WITH_FAILURE")) {
1188
+ throw new Error(`batch '${batchId}' has no durable terminal receipt`);
1189
+ }
1190
+ const receiptRecorded = events.some((event) => event.kind === "coordination" &&
1191
+ event.batchId === batchId &&
1192
+ event.action === "receipt_recorded" &&
1193
+ event.payload?.status === batch.state);
1194
+ if (!receiptRecorded) {
1195
+ throw new Error(`batch '${batchId}' has no matching durable receipt event`);
1196
+ }
1197
+ }
1198
+ //# sourceMappingURL=coordinator.js.map