@pennixrv/trellis 0.7.0-beta.9 → 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 (484) 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.1-beta.0.json +9 -0
  254. package/dist/migrations/manifests/0.7.1.json +9 -0
  255. package/dist/templates/claude/hooks/statusline.py +0 -7
  256. package/dist/templates/codex/hooks/session-start.py +31 -38
  257. package/dist/templates/common/bundled-skills/trellis-decision-space-construction-and-merging/SKILL.md +10 -0
  258. package/dist/templates/common/bundled-skills/trellis-decision-space-construction-and-merging/workflow.md +40 -0
  259. package/dist/templates/common/bundled-skills/trellis-delivery-review-and-closeout/SKILL.md +10 -0
  260. package/dist/templates/common/bundled-skills/trellis-delivery-review-and-closeout/workflow.md +55 -0
  261. package/dist/templates/common/bundled-skills/trellis-goal-exploration-and-requirements/SKILL.md +10 -0
  262. package/dist/templates/common/bundled-skills/trellis-goal-exploration-and-requirements/workflow.md +33 -0
  263. package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +25 -25
  264. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +1 -1
  265. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +13 -19
  266. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-spec-structure.md +1 -1
  267. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-task-lifecycle.md +27 -75
  268. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-workflow.md +17 -56
  269. package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +1 -1
  270. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/bundled-skills.md +14 -11
  271. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +0 -33
  272. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/multi-agent-teamwork.md +32 -0
  273. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/spec-system.md +1 -1
  274. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +25 -111
  275. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/workflow.md +19 -60
  276. package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +1 -1
  277. package/dist/templates/common/bundled-skills/trellis-session-insight/SKILL.md +1 -1
  278. package/dist/templates/common/bundled-skills/trellis-session-insight/references/cli-quick-reference.md +1 -1
  279. package/dist/templates/common/bundled-skills/trellis-solution-design-and-convergence/SKILL.md +10 -0
  280. package/dist/templates/common/bundled-skills/trellis-solution-design-and-convergence/workflow.md +36 -0
  281. package/dist/templates/common/bundled-skills/trellis-task-implementation/SKILL.md +10 -0
  282. package/dist/templates/common/bundled-skills/trellis-task-implementation/workflow.md +29 -0
  283. package/dist/templates/common/bundled-skills/trellis-teamwork/SKILL.md +73 -0
  284. package/dist/templates/common/bundled-skills/trellis-teamwork/references/coordination-modes.md +29 -0
  285. package/dist/templates/common/bundled-skills/trellis-teamwork/references/teammate-configuration-matrix.md +31 -0
  286. package/dist/templates/common/bundled-skills/trellis-teamwork/references/teammate-processes.md +37 -0
  287. package/dist/templates/common/bundled-skills/trellis-teamwork/references/teamwork-plan-construction.md +78 -0
  288. package/dist/templates/common/commands/continue.md +9 -49
  289. package/dist/templates/common/commands/finish-work.md +10 -58
  290. package/dist/templates/common/commands/start.md +19 -49
  291. package/dist/templates/common/skills/brainstorm.md +11 -199
  292. package/dist/templates/copilot/hooks/session-start.py +30 -26
  293. package/dist/templates/copilot/prompts/brainstorm.prompt.md +7 -160
  294. package/dist/templates/copilot/prompts/finish-work.prompt.md +11 -88
  295. package/dist/templates/copilot/prompts/record-session.prompt.md +4 -12
  296. package/dist/templates/copilot/prompts/start.prompt.md +12 -10
  297. package/dist/templates/dsh/DSH.md +2 -2
  298. package/dist/templates/kiro/agents/trellis.json +2 -2
  299. package/dist/templates/markdown/agents.md +14 -3
  300. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +9 -8
  301. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +1 -1
  302. package/dist/templates/markdown/workspace-index.md +0 -1
  303. package/dist/templates/omp/extensions/trellis/index.ts.txt +28 -17
  304. package/dist/templates/opencode/lib/session-utils.js +20 -25
  305. package/dist/templates/opencode/lib/trellis-context.js +4 -76
  306. package/dist/templates/opencode/plugins/inject-subagent-context.js +5 -4
  307. package/dist/templates/opencode/plugins/inject-workflow-state.js +14 -17
  308. package/dist/templates/shared-hooks/inject-shell-session-context.py +3 -3
  309. package/dist/templates/shared-hooks/inject-subagent-context.py +445 -67
  310. package/dist/templates/shared-hooks/inject-workflow-state.py +44 -36
  311. package/dist/templates/shared-hooks/session-start.py +21 -33
  312. package/dist/templates/trellis/agents/delegated-worktree-primary-agent.md +18 -0
  313. package/dist/templates/trellis/agents/teammate-profiles.json +8 -0
  314. package/dist/templates/trellis/agents/teammate.md +63 -0
  315. package/dist/templates/trellis/config.yaml +29 -38
  316. package/dist/templates/trellis/gitignore.txt +1 -0
  317. package/dist/templates/trellis/index.d.ts +8 -12
  318. package/dist/templates/trellis/index.d.ts.map +1 -1
  319. package/dist/templates/trellis/index.js +14 -25
  320. package/dist/templates/trellis/index.js.map +1 -1
  321. package/dist/templates/trellis/scripts/add_session.py +1 -1
  322. package/dist/templates/trellis/scripts/common/__init__.py +0 -1
  323. package/dist/templates/trellis/scripts/common/active_task.py +136 -100
  324. package/dist/templates/trellis/scripts/common/config.py +7 -9
  325. package/dist/templates/trellis/scripts/common/git_context.py +1 -1
  326. package/dist/templates/trellis/scripts/common/io.py +19 -0
  327. package/dist/templates/trellis/scripts/common/paths.py +0 -1
  328. package/dist/templates/trellis/scripts/common/safe_commit.py +11 -90
  329. package/dist/templates/trellis/scripts/common/session_context.py +1 -8
  330. package/dist/templates/trellis/scripts/common/spec_match.py +1 -1
  331. package/dist/templates/trellis/scripts/common/task_context.py +152 -59
  332. package/dist/templates/trellis/scripts/common/task_continuity.py +598 -0
  333. package/dist/templates/trellis/scripts/common/task_store.py +70 -548
  334. package/dist/templates/trellis/scripts/common/task_utils.py +4 -98
  335. package/dist/templates/trellis/scripts/common/task_workflow.py +1096 -0
  336. package/dist/templates/trellis/scripts/common/tasks.py +5 -8
  337. package/dist/templates/trellis/scripts/common/workflow_phase.py +8 -7
  338. package/dist/templates/trellis/scripts/hooks/linear_sync.py +3 -3
  339. package/dist/templates/trellis/scripts/task.py +119 -377
  340. package/dist/templates/trellis/workflow.md +111 -706
  341. package/dist/utils/agent-refs.d.ts +5 -5
  342. package/dist/utils/agent-refs.js +6 -6
  343. package/dist/utils/file-writer.d.ts +3 -2
  344. package/dist/utils/file-writer.d.ts.map +1 -1
  345. package/dist/utils/file-writer.js +3 -2
  346. package/dist/utils/file-writer.js.map +1 -1
  347. package/dist/utils/managed-paths.d.ts +0 -7
  348. package/dist/utils/managed-paths.d.ts.map +1 -1
  349. package/dist/utils/managed-paths.js +0 -40
  350. package/dist/utils/managed-paths.js.map +1 -1
  351. package/dist/utils/manifest-prune.d.ts.map +1 -1
  352. package/dist/utils/manifest-prune.js +2 -11
  353. package/dist/utils/manifest-prune.js.map +1 -1
  354. package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
  355. package/dist/utils/uninstall-scrubbers.js +3 -3
  356. package/dist/utils/uninstall-scrubbers.js.map +1 -1
  357. package/dist/utils/workflow-resolver.d.ts +10 -16
  358. package/dist/utils/workflow-resolver.d.ts.map +1 -1
  359. package/dist/utils/workflow-resolver.js +25 -36
  360. package/dist/utils/workflow-resolver.js.map +1 -1
  361. package/package.json +2 -2
  362. package/dist/commands/channel/adapters/claude.d.ts.map +0 -1
  363. package/dist/commands/channel/adapters/claude.js.map +0 -1
  364. package/dist/commands/channel/adapters/codex.d.ts.map +0 -1
  365. package/dist/commands/channel/adapters/codex.js.map +0 -1
  366. package/dist/commands/channel/adapters/index.d.ts.map +0 -1
  367. package/dist/commands/channel/adapters/index.js.map +0 -1
  368. package/dist/commands/channel/adapters/types.d.ts.map +0 -1
  369. package/dist/commands/channel/adapters/types.js.map +0 -1
  370. package/dist/commands/channel/agent-loader.d.ts.map +0 -1
  371. package/dist/commands/channel/agent-loader.js.map +0 -1
  372. package/dist/commands/channel/context-loader.d.ts.map +0 -1
  373. package/dist/commands/channel/context-loader.js.map +0 -1
  374. package/dist/commands/channel/context-trust.d.ts.map +0 -1
  375. package/dist/commands/channel/context-trust.js.map +0 -1
  376. package/dist/commands/channel/context.d.ts +0 -16
  377. package/dist/commands/channel/context.d.ts.map +0 -1
  378. package/dist/commands/channel/context.js.map +0 -1
  379. package/dist/commands/channel/create.d.ts +0 -29
  380. package/dist/commands/channel/create.d.ts.map +0 -1
  381. package/dist/commands/channel/create.js +0 -47
  382. package/dist/commands/channel/create.js.map +0 -1
  383. package/dist/commands/channel/dev-parse-trace.d.ts.map +0 -1
  384. package/dist/commands/channel/dev-parse-trace.js.map +0 -1
  385. package/dist/commands/channel/guard.d.ts.map +0 -1
  386. package/dist/commands/channel/guard.js.map +0 -1
  387. package/dist/commands/channel/index.d.ts +0 -3
  388. package/dist/commands/channel/index.d.ts.map +0 -1
  389. package/dist/commands/channel/index.js.map +0 -1
  390. package/dist/commands/channel/interrupt.d.ts.map +0 -1
  391. package/dist/commands/channel/interrupt.js +0 -22
  392. package/dist/commands/channel/interrupt.js.map +0 -1
  393. package/dist/commands/channel/kill.d.ts +0 -7
  394. package/dist/commands/channel/kill.d.ts.map +0 -1
  395. package/dist/commands/channel/kill.js.map +0 -1
  396. package/dist/commands/channel/list.d.ts +0 -18
  397. package/dist/commands/channel/list.d.ts.map +0 -1
  398. package/dist/commands/channel/list.js.map +0 -1
  399. package/dist/commands/channel/messages.d.ts.map +0 -1
  400. package/dist/commands/channel/messages.js.map +0 -1
  401. package/dist/commands/channel/rm.d.ts +0 -27
  402. package/dist/commands/channel/rm.d.ts.map +0 -1
  403. package/dist/commands/channel/rm.js.map +0 -1
  404. package/dist/commands/channel/run.d.ts +0 -32
  405. package/dist/commands/channel/run.js +0 -141
  406. package/dist/commands/channel/run.js.map +0 -1
  407. package/dist/commands/channel/send.d.ts.map +0 -1
  408. package/dist/commands/channel/send.js.map +0 -1
  409. package/dist/commands/channel/spawn.d.ts.map +0 -1
  410. package/dist/commands/channel/spawn.js.map +0 -1
  411. package/dist/commands/channel/store/events.d.ts +0 -22
  412. package/dist/commands/channel/store/events.d.ts.map +0 -1
  413. package/dist/commands/channel/store/events.js.map +0 -1
  414. package/dist/commands/channel/store/filter.d.ts +0 -3
  415. package/dist/commands/channel/store/filter.d.ts.map +0 -1
  416. package/dist/commands/channel/store/filter.js +0 -2
  417. package/dist/commands/channel/store/filter.js.map +0 -1
  418. package/dist/commands/channel/store/lock.d.ts.map +0 -1
  419. package/dist/commands/channel/store/lock.js.map +0 -1
  420. package/dist/commands/channel/store/paths.d.ts.map +0 -1
  421. package/dist/commands/channel/store/paths.js.map +0 -1
  422. package/dist/commands/channel/store/schema.d.ts +0 -27
  423. package/dist/commands/channel/store/schema.d.ts.map +0 -1
  424. package/dist/commands/channel/store/schema.js +0 -34
  425. package/dist/commands/channel/store/schema.js.map +0 -1
  426. package/dist/commands/channel/store/thread-state.d.ts.map +0 -1
  427. package/dist/commands/channel/store/thread-state.js.map +0 -1
  428. package/dist/commands/channel/store/watch.d.ts +0 -19
  429. package/dist/commands/channel/store/watch.d.ts.map +0 -1
  430. package/dist/commands/channel/store/watch.js.map +0 -1
  431. package/dist/commands/channel/supervisor/idle.d.ts.map +0 -1
  432. package/dist/commands/channel/supervisor/idle.js.map +0 -1
  433. package/dist/commands/channel/supervisor/inbox.d.ts.map +0 -1
  434. package/dist/commands/channel/supervisor/inbox.js.map +0 -1
  435. package/dist/commands/channel/supervisor/shutdown.d.ts.map +0 -1
  436. package/dist/commands/channel/supervisor/shutdown.js.map +0 -1
  437. package/dist/commands/channel/supervisor/stdout.d.ts.map +0 -1
  438. package/dist/commands/channel/supervisor/stdout.js.map +0 -1
  439. package/dist/commands/channel/supervisor/turns.d.ts.map +0 -1
  440. package/dist/commands/channel/supervisor/turns.js.map +0 -1
  441. package/dist/commands/channel/supervisor/warning.d.ts.map +0 -1
  442. package/dist/commands/channel/supervisor/warning.js.map +0 -1
  443. package/dist/commands/channel/supervisor.d.ts.map +0 -1
  444. package/dist/commands/channel/supervisor.js.map +0 -1
  445. package/dist/commands/channel/text-body.d.ts +0 -13
  446. package/dist/commands/channel/text-body.d.ts.map +0 -1
  447. package/dist/commands/channel/text-body.js.map +0 -1
  448. package/dist/commands/channel/threads.d.ts +0 -39
  449. package/dist/commands/channel/threads.d.ts.map +0 -1
  450. package/dist/commands/channel/threads.js.map +0 -1
  451. package/dist/commands/channel/title.d.ts +0 -12
  452. package/dist/commands/channel/title.d.ts.map +0 -1
  453. package/dist/commands/channel/title.js +0 -24
  454. package/dist/commands/channel/title.js.map +0 -1
  455. package/dist/commands/channel/wait.d.ts.map +0 -1
  456. package/dist/commands/channel/wait.js.map +0 -1
  457. package/dist/commands/channel/workers.d.ts +0 -9
  458. package/dist/commands/channel/workers.d.ts.map +0 -1
  459. package/dist/commands/channel/workers.js +0 -31
  460. package/dist/commands/channel/workers.js.map +0 -1
  461. package/dist/templates/common/bundled-skills/trellis-channel/SKILL.md +0 -69
  462. package/dist/templates/common/bundled-skills/trellis-channel/references/command-reference.md +0 -549
  463. package/dist/templates/common/bundled-skills/trellis-channel/references/forum.md +0 -233
  464. package/dist/templates/common/bundled-skills/trellis-channel/references/progress-debugging.md +0 -237
  465. package/dist/templates/common/bundled-skills/trellis-channel/references/subnode-work.md +0 -222
  466. package/dist/templates/common/bundled-skills/trellis-channel/references/workers.md +0 -295
  467. package/dist/templates/common/bundled-skills/trellis-channel/references/workflows.md +0 -131
  468. package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/multi-agent-channel.md +0 -70
  469. package/dist/templates/common/bundled-skills/trellis-research-record/SKILL.md +0 -14
  470. package/dist/templates/copilot/prompts/parallel.prompt.md +0 -204
  471. package/dist/templates/trellis/agents/check.md +0 -70
  472. package/dist/templates/trellis/agents/implement.md +0 -71
  473. package/dist/templates/trellis/agents/subnode.env +0 -4
  474. package/dist/templates/trellis/agents/subnode.md +0 -76
  475. package/dist/templates/trellis/scripts/common/context_projection.py +0 -508
  476. package/dist/templates/trellis/scripts/common/continuation_record.py +0 -450
  477. package/dist/templates/trellis/scripts/common/ownership_record.py +0 -439
  478. package/dist/templates/trellis/scripts/subnode_artifact.py +0 -735
  479. package/dist/templates/trellis/scripts/workspace_note.py +0 -126
  480. /package/dist/commands/{channel → teamwork}/adapters/types.js +0 -0
  481. /package/dist/commands/{channel → teamwork}/supervisor/idle.d.ts +0 -0
  482. /package/dist/commands/{channel → teamwork}/supervisor/idle.js +0 -0
  483. /package/dist/commands/{channel → teamwork}/supervisor/turns.d.ts +0 -0
  484. /package/dist/commands/{channel → teamwork}/supervisor/turns.js +0 -0
@@ -8,20 +8,19 @@ Usage:
8
8
  python3 task.py add-context <dir> <file> <path> [reason] # Add jsonl entry
9
9
  python3 task.py validate <dir> # Validate jsonl files
10
10
  python3 task.py list-context <dir> # List jsonl entries
11
- python3 task.py start <dir> # Set active task, record current branch
12
- python3 task.py replan <dir> "<reason>" # Return an in-progress task to planning
11
+ python3 task.py start <dir> # Set active task; enter implementation only after phase authorization
13
12
  python3 task.py current [--source] [--json] # Show active task
14
- python3 task.py ownership <operation> ... # Manage formal handoff task ownership
15
13
  python3 task.py finish # Clear active task
16
14
  python3 task.py workflow <id>|--clear # Set/clear per-task workflow selection
15
+ python3 task.py phase <action> <task-dir> # Read/update task phase workflow state
16
+ python3 task.py cancel <task-dir> --reason <text> --evidence-ref <ref> # Cancel task lifecycle
17
17
  python3 task.py set-branch <dir> <branch> # Set git branch
18
18
  python3 task.py set-base-branch <dir> <branch> # Set PR target branch
19
19
  python3 task.py set-scope <dir> <scope> # Set scope for PR title
20
20
  python3 task.py set-meta <dir> <key> <value> # Set a task metadata key
21
21
  python3 task.py rename <dir> <new-slug> [--dry-run] # Rename task + references
22
- python3 task.py archive <task-dir> [--skip-branch-validation] # Archive completed task
22
+ python3 task.py complete <task-dir> # Complete after Delivery Review and On-Site Closeout Phase acceptance
23
23
  python3 task.py list # List active tasks
24
- python3 task.py list-archive [month] # List archived tasks
25
24
  python3 task.py add-subtask <parent-dir> <child-dir> # Link child to parent
26
25
  python3 task.py remove-subtask <parent-dir> <child-dir> # Unlink child from parent
27
26
  """
@@ -30,9 +29,7 @@ from __future__ import annotations
30
29
 
31
30
  import argparse
32
31
  import json
33
- import os
34
32
  import sys
35
- from datetime import datetime, timezone
36
33
  from pathlib import Path
37
34
 
38
35
  from common.log import Colors, colored
@@ -67,7 +64,6 @@ from common.workflow_selection import WORKFLOW_ID_RE, workflow_md_for_task
67
64
  from common.task_store import (
68
65
  cmd_create,
69
66
  cmd_rename,
70
- cmd_archive,
71
67
  cmd_set_branch,
72
68
  cmd_set_base_branch,
73
69
  cmd_set_scope,
@@ -79,26 +75,21 @@ from common.task_context import (
79
75
  cmd_add_context,
80
76
  cmd_validate,
81
77
  cmd_list_context,
82
- curated_entry_count,
83
78
  )
84
- from common.continuation_record import (
85
- STATUS_WITHHELD,
86
- ContinuationError,
87
- clear as clear_continuity,
88
- seal as seal_continuity,
89
- status as continuity_status,
79
+ from common.task_workflow import (
80
+ TaskWorkflowError,
81
+ cmd_cancel_task,
82
+ cmd_complete_task,
83
+ cmd_delegate_start,
84
+ cmd_phase,
85
+ implementation_start_ready,
90
86
  )
91
- from common.ownership_record import (
92
- OwnershipError,
93
- archive as archive_ownership,
87
+ from common.task_continuity import (
88
+ add_continuity_commands,
94
89
  assert_task_mutation_allowed,
95
- claim as claim_ownership,
96
- consume as consume_ownership,
97
- quiesce as quiesce_ownership,
98
- retire as retire_ownership,
99
- retire_handoff as retire_handoff_ownership,
100
- seal as seal_ownership,
101
- status as ownership_status,
90
+ continuity_capture,
91
+ continuity_show,
92
+ transfer_task_ownership,
102
93
  )
103
94
 
104
95
 
@@ -111,12 +102,11 @@ def _record_start_state(
111
102
  repo_root: Path,
112
103
  label: str = "",
113
104
  ) -> None:
114
- """Move a freshly started task to in_progress and record its branch.
105
+ """Enter implementation and record its branch after current authorization.
115
106
 
116
- Both updates share one read/write: the status flip from planning, and the
117
- checked-out branch when `branch` is still empty. Recording at start is what
118
- keeps `branch` trustworthy at archive time — a task whose branch is only
119
- ever set by hand tends to reach archive with `branch: null`.
107
+ Planning and analysis tasks keep their lifecycle status while the active
108
+ session pointer supports workflow context. Only the start of an authorized
109
+ Task Implementation and Test Verification Phase changes `planning` to `in_progress`.
120
110
 
121
111
  Tolerant on purpose — a broken task.json does not fail `start`, because the
122
112
  session pointer is the point of the command. But the read overwrites the
@@ -135,14 +125,22 @@ def _record_start_state(
135
125
 
136
126
  applied: list[str] = []
137
127
 
138
- if data.get("status") == "planning":
128
+ try:
129
+ implementation_ready = implementation_start_ready(data, task_json_path.parent)
130
+ except TaskWorkflowError as error:
131
+ print(
132
+ colored(f"Warning: Implementation start withheld; task.json not updated: {error.code}: {error}", Colors.YELLOW),
133
+ file=sys.stderr,
134
+ )
135
+ return
136
+ if data.get("status") == "planning" and implementation_ready:
139
137
  data["status"] = "in_progress"
140
138
  applied.append(f"✓ Status: planning → in_progress{label}")
141
139
 
142
140
  # Only fill an empty field: an explicit `set-branch` must survive a later
143
141
  # `start` (re-starting a task after a checkout is a normal thing to do).
144
142
  base_branch_conflict: str | None = None
145
- if not data.get("branch"):
143
+ if implementation_ready and data.get("status") == "in_progress" and not data.get("branch"):
146
144
  branch = current_branch_name(repo_root)
147
145
  if branch:
148
146
  data["branch"] = branch
@@ -162,6 +160,12 @@ def _record_start_state(
162
160
  if not applied:
163
161
  return
164
162
 
163
+ try:
164
+ assert_task_mutation_allowed(repo_root, task_json_path.parent, data)
165
+ except TaskWorkflowError as error:
166
+ print(colored(f"{error.code}: task metadata update withheld: {error}", Colors.YELLOW), file=sys.stderr)
167
+ return
168
+
165
169
  if not write_json(task_json_path, data):
166
170
  print(
167
171
  colored(
@@ -178,11 +182,10 @@ def _record_start_state(
178
182
 
179
183
  if base_branch_conflict:
180
184
  # Recorded anyway — the value is true, it just cannot describe a PR.
181
- # Archive refuses this shape, so say so now rather than at the gate.
182
185
  print(
183
186
  colored(
184
187
  f"Warning: '{base_branch_conflict}' is also this task's base_branch; "
185
- "a PR cannot target its own branch, and archive will refuse it.",
188
+ "a PR cannot target its own branch.",
186
189
  Colors.YELLOW,
187
190
  ),
188
191
  file=sys.stderr,
@@ -217,35 +220,6 @@ def cmd_start(args: argparse.Namespace) -> int:
217
220
  print("Hint: Use task name (e.g., 'my-task') or full path (e.g., '.trellis/tasks/01-31-my-task')")
218
221
  return 1
219
222
 
220
- try:
221
- assert_task_mutation_allowed(repo_root, full_path)
222
- except (OwnershipError, OSError) as exc:
223
- print(colored(f"Error: {exc}", Colors.RED), file=sys.stderr)
224
- return 2
225
-
226
- # Context-manifest gate (#573): a seeded-but-uncurated implement/check
227
- # manifest means every sub-agent dispatched for this task runs with zero
228
- # spec context, and nothing downstream surfaces that to the main session.
229
- # An absent manifest is not gated — create seeds the files only on
230
- # sub-agent-capable platforms, so absence means no sub-agent reads them.
231
- if not getattr(args, "allow_empty_context", False):
232
- empty_manifests = [
233
- name
234
- for name in ("implement.jsonl", "check.jsonl")
235
- if curated_entry_count(full_path / name) == 0
236
- ]
237
- if empty_manifests:
238
- print(colored(
239
- f"Error: {' and '.join(empty_manifests)} "
240
- f"{'has' if len(empty_manifests) == 1 else 'have'} no curated entries",
241
- Colors.RED,
242
- ))
243
- print("Sub-agents (implement/check) would run with zero spec context.")
244
- print(f" Curate: python3 .trellis/scripts/task.py add-context {task_input} implement <path> \"<why>\"")
245
- print(f" Verify: python3 .trellis/scripts/task.py validate {task_input}")
246
- print(" Intentionally empty? Re-run start with --allow-empty-context")
247
- return 1
248
-
249
223
  # Convert to relative path for storage. repo_root is resolved because
250
224
  # full_path already is (resolve_task_dir only returns paths inside the
251
225
  # resolved root), so an unresolved repo_root would mismatch under a
@@ -280,7 +254,7 @@ def cmd_start(args: argparse.Namespace) -> int:
280
254
  Colors.YELLOW,
281
255
  ))
282
256
 
283
- # Still flip task.json status: planning → in_progress so downstream phases proceed.
257
+ # Enter implementation only when the accepted phase contract authorizes it.
284
258
  if task_json_path.is_file():
285
259
  _record_start_state(task_json_path, repo_root, " (degraded)")
286
260
  run_task_hooks("after_start", task_json_path, repo_root)
@@ -304,103 +278,23 @@ def cmd_start(args: argparse.Namespace) -> int:
304
278
  return 1
305
279
 
306
280
 
307
- def cmd_replan(args: argparse.Namespace) -> int:
308
- """Return an in-progress task to planning without losing its binding."""
309
- repo_root = get_repo_root()
310
- full_path = resolve_task_dir(args.dir, repo_root)
311
- if full_path is None or not full_path.is_dir():
312
- print(colored(f"Error: Task not found: {args.dir}", Colors.RED), file=sys.stderr)
313
- return 1
314
-
315
- try:
316
- assert_task_mutation_allowed(repo_root, full_path)
317
- except (OwnershipError, OSError) as exc:
318
- print(colored(f"Error: {exc}", Colors.RED), file=sys.stderr)
319
- return 2
320
-
321
- reason = " ".join(args.reason).strip()
322
- if not reason:
323
- print(colored("Error: replan reason must not be empty", Colors.RED), file=sys.stderr)
324
- return 1
325
-
326
- task_json_path = full_path / FILE_TASK_JSON
327
- data, read_reason = read_json_checked(task_json_path)
328
- if data is None:
329
- problem, hint = describe_json_read_failure(task_json_path, read_reason)
330
- print(colored(f"Error: {problem}", Colors.RED), file=sys.stderr)
331
- print(hint, file=sys.stderr)
332
- return 1
333
- if data.get("status") != "in_progress":
334
- print(
335
- colored(
336
- f"Error: replan requires status=in_progress (found {data.get('status')!r})",
337
- Colors.RED,
338
- ),
339
- file=sys.stderr,
340
- )
341
- return 1
342
-
343
- event = {
344
- "timestamp": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
345
- "task": full_path.relative_to(repo_root).as_posix(),
346
- "from_status": "in_progress",
347
- "reason": reason,
348
- "branch": data.get("branch"),
349
- }
350
- context_key = resolve_context_key()
351
- if context_key:
352
- event["session"] = context_key
353
-
354
- replans_path = full_path / "replans.jsonl"
355
- try:
356
- with replans_path.open("a", encoding="utf-8") as handle:
357
- handle.write(json.dumps(event, ensure_ascii=False) + "\n")
358
- handle.flush()
359
- os.fsync(handle.fileno())
360
- except OSError as exc:
361
- print(colored(f"Error: could not record replan: {exc}", Colors.RED), file=sys.stderr)
362
- return 1
363
-
364
- data["status"] = "planning"
365
- if not write_json(task_json_path, data):
366
- print(colored("Error: replan event recorded but task status was not changed", Colors.RED), file=sys.stderr)
367
- return 1
368
-
369
- print(colored(f"✓ Task returned to planning: {full_path.relative_to(repo_root)}", Colors.GREEN))
370
- print("Reason:", reason)
371
- run_task_hooks("after_replan", task_json_path, repo_root)
372
- return 0
373
-
374
-
375
281
  def cmd_finish(args: argparse.Namespace) -> int:
376
282
  """Clear active task."""
377
283
  repo_root = get_repo_root()
378
- active = resolve_active_task(repo_root)
284
+ active = clear_active_task(repo_root)
379
285
  current = active.task_path
380
286
 
381
287
  if not current:
382
288
  print(colored("No current task set", Colors.YELLOW))
383
289
  return 0
384
290
 
385
- if active.source_type == "unbound":
386
- print(colored("Task exists but no direct session is bound; run task.py start first", Colors.YELLOW))
387
- print(f"Task: {current}")
388
- return 0
389
- if active.source_type == "unbound_ambiguous":
390
- print(colored("Multiple tasks exist but no direct session is bound; choose one before finishing", Colors.YELLOW))
391
- for candidate in active.candidate_paths:
392
- print(f"Candidate: {candidate}")
393
- return 0
394
-
395
- try:
396
- assert_task_mutation_allowed(repo_root, repo_root / current)
397
- except (OwnershipError, OSError) as exc:
398
- print(colored(f"Error: {exc}", Colors.RED), file=sys.stderr)
399
- return 2
291
+ remaining = resolve_active_task(repo_root)
292
+ if remaining.context_key == active.context_key and remaining.task_path == current:
293
+ print(colored("Error: task ownership is fenced; this session cannot clear the active task", Colors.RED))
294
+ return 1
400
295
 
401
296
  # Resolve task.json path before clearing
402
297
  task_json_path = repo_root / current / FILE_TASK_JSON
403
- clear_active_task(repo_root)
404
298
 
405
299
  print(colored(f"✓ Cleared current task (was: {current})", Colors.GREEN))
406
300
  print(f"Source: {active.source}")
@@ -441,13 +335,26 @@ def cmd_current(args: argparse.Namespace) -> int:
441
335
  "branch": data.get("branch"),
442
336
  "base_branch": data.get("base_branch"),
443
337
  }
338
+ meta = data.get("meta")
339
+ phase_workflow = meta.get("task_workflow") if isinstance(meta, dict) else None
340
+ if isinstance(phase_workflow, dict):
341
+ current_phase_id = phase_workflow.get("current_phase_id")
342
+ phase_map = phase_workflow.get("phases")
343
+ phase_record = phase_map.get(current_phase_id) if isinstance(phase_map, dict) and isinstance(current_phase_id, str) else None
344
+ task_obj["current_phase_id"] = current_phase_id
345
+ task_obj["task_route_revision"] = phase_workflow.get("task_route_revision")
346
+ task_obj["input_revision"] = phase_workflow.get("input_revision")
347
+ task_obj["phase_status"] = phase_record.get("status") if isinstance(phase_record, dict) else None
444
348
  payload = {
445
349
  "current_task": task_obj,
446
350
  "source": active.source,
351
+ "session_source": (
352
+ f"session:{active.context_key}"
353
+ if active.context_key
354
+ else None
355
+ ),
447
356
  "stale": active.stale,
448
357
  }
449
- if active.candidate_paths:
450
- payload["candidates"] = list(active.candidate_paths)
451
358
  # Only present when the read failed, so the healthy shape is unchanged.
452
359
  if read_error:
453
360
  payload["error"] = read_error
@@ -455,12 +362,6 @@ def cmd_current(args: argparse.Namespace) -> int:
455
362
  return 0 if active.task_path else 1
456
363
 
457
364
  if args.source:
458
- if active.source_type == "unbound_ambiguous":
459
- print("Current task: (ambiguous)")
460
- print("Source: unbound_ambiguous")
461
- for candidate in active.candidate_paths:
462
- print(f"Candidate: {candidate}")
463
- return 1
464
365
  print(f"Current task: {active.task_path or '(none)'}")
465
366
  print(f"Source: {active.source}")
466
367
  if active.stale:
@@ -471,92 +372,9 @@ def cmd_current(args: argparse.Namespace) -> int:
471
372
  print(active.task_path)
472
373
  return 0
473
374
 
474
- if active.source_type == "unbound_ambiguous":
475
- print("Multiple active tasks require explicit binding:")
476
- for candidate in active.candidate_paths:
477
- print(candidate)
478
-
479
375
  return 1
480
376
 
481
377
 
482
- def cmd_continuity(args: argparse.Namespace) -> int:
483
- """Read or explicitly mutate the current task's Continuation Record."""
484
- repo_root = get_repo_root()
485
- try:
486
- if args.continuity_command == "status":
487
- result = continuity_status(repo_root)
488
- print(json.dumps(result, ensure_ascii=False, sort_keys=True))
489
- return 0
490
- if not getattr(args, "explicit_user_request", False):
491
- print(colored("Error: continuity writes require --explicit-user-request", Colors.RED), file=sys.stderr)
492
- return 2
493
- if args.continuity_command == "seal":
494
- request = Path(args.request)
495
- if request.is_absolute() or ".." in request.parts:
496
- print(colored("Error: continuity request must be project-relative", Colors.RED), file=sys.stderr)
497
- return 2
498
- result = seal_continuity(repo_root, repo_root / request, args.expected)
499
- else:
500
- result = clear_continuity(repo_root, args.expected)
501
- print(json.dumps(result, ensure_ascii=False, sort_keys=True))
502
- return 0
503
- except (ContinuationError, OSError) as exc:
504
- print(json.dumps({"status": STATUS_WITHHELD, "reason": str(exc)}, ensure_ascii=False, sort_keys=True))
505
- return 2
506
-
507
-
508
- def cmd_ownership(args: argparse.Namespace) -> int:
509
- """Manage the task-bound formal handoff ownership record."""
510
- repo_root = get_repo_root()
511
- if args.ownership_command == "status":
512
- try:
513
- result = ownership_status(repo_root, args.task_id, args.handoff_id, args.core_digest)
514
- except (OwnershipError, OSError) as exc:
515
- print(json.dumps({"status": "withheld", "reason": str(exc)}, ensure_ascii=False, sort_keys=True))
516
- return 2
517
- print(json.dumps(result, ensure_ascii=False, sort_keys=True))
518
- return 0
519
- if not getattr(args, "explicit_user_request", False):
520
- print(colored("Error: ownership writes require --explicit-user-request", Colors.RED), file=sys.stderr)
521
- return 2
522
- try:
523
- command = args.ownership_command
524
- if command == "quiesce":
525
- result = quiesce_ownership(
526
- repo_root, args.task, args.handoff_id, args.core_digest, args.source_session_id
527
- )
528
- elif command == "seal":
529
- result = seal_ownership(
530
- repo_root, args.task_id, args.handoff_id, args.core_digest, args.expected_generation
531
- )
532
- elif command == "retire":
533
- result = retire_ownership(
534
- repo_root, args.task_id, args.handoff_id, args.core_digest,
535
- args.expected_generation, args.archive_observation,
536
- )
537
- elif command == "retire-handoff":
538
- result = retire_handoff_ownership(
539
- repo_root, args.task_id, args.handoff_id, args.core_digest,
540
- )
541
- elif command == "claim":
542
- result = claim_ownership(
543
- repo_root, args.task_id, args.task, args.handoff_id, args.core_digest, args.expected_generation
544
- )
545
- elif command == "consume":
546
- result = consume_ownership(
547
- repo_root, args.task_id, args.handoff_id, args.core_digest, args.expected_generation
548
- )
549
- else:
550
- result = archive_ownership(
551
- repo_root, args.task_id, args.handoff_id, args.core_digest, args.expected_generation
552
- )
553
- print(json.dumps(result, ensure_ascii=False, sort_keys=True))
554
- return 0
555
- except (OwnershipError, OSError) as exc:
556
- print(json.dumps({"status": "withheld", "reason": str(exc)}, ensure_ascii=False, sort_keys=True))
557
- return 2
558
-
559
-
560
378
  # =============================================================================
561
379
  # Command: workflow
562
380
  # =============================================================================
@@ -590,6 +408,12 @@ def cmd_workflow(args: argparse.Namespace) -> int:
590
408
  print(colored(f"Error: failed to read {task_json_path}", Colors.RED))
591
409
  return 1
592
410
 
411
+ try:
412
+ assert_task_mutation_allowed(repo_root, task_dir, data)
413
+ except TaskWorkflowError as error:
414
+ print(f"{error.code}: {error}", file=sys.stderr)
415
+ return 1
416
+
593
417
  if args.clear:
594
418
  if data.pop("workflow", None) is None:
595
419
  print(colored("No workflow selection set on this task", Colors.YELLOW))
@@ -758,40 +582,6 @@ def cmd_list(args: argparse.Namespace) -> int:
758
582
  return 0
759
583
 
760
584
 
761
- # =============================================================================
762
- # Command: list-archive
763
- # =============================================================================
764
-
765
- def cmd_list_archive(args: argparse.Namespace) -> int:
766
- """List archived tasks."""
767
- repo_root = get_repo_root()
768
- tasks_dir = get_tasks_dir(repo_root)
769
- archive_dir = tasks_dir / "archive"
770
- month = args.month
771
-
772
- print(colored("Archived tasks:", Colors.BLUE))
773
- print()
774
-
775
- if month:
776
- month_dir = archive_dir / month
777
- if month_dir.is_dir():
778
- print(f"[{month}]")
779
- for d in sorted(month_dir.iterdir()):
780
- if d.is_dir():
781
- print(f" - {d.name}/")
782
- else:
783
- print(f" No archives for {month}")
784
- else:
785
- if archive_dir.is_dir():
786
- for month_dir in sorted(archive_dir.iterdir()):
787
- if month_dir.is_dir():
788
- month_name = month_dir.name
789
- count = sum(1 for d in month_dir.iterdir() if d.is_dir())
790
- print(f"[{month_name}] - {count} task(s)")
791
-
792
- return 0
793
-
794
-
795
585
  # =============================================================================
796
586
  # Help
797
587
  # =============================================================================
@@ -809,7 +599,7 @@ Usage:
809
599
  python3 task.py add-context <dir> <jsonl> <path> [reason] Add entry to jsonl
810
600
  python3 task.py validate <dir> Validate jsonl files
811
601
  python3 task.py list-context <dir> List jsonl entries
812
- python3 task.py start <dir> Set active task; records the checked-out branch when unset
602
+ python3 task.py start <dir> Set active task; enter implementation only after phase authorization
813
603
  python3 task.py current [--source] Show active task
814
604
  python3 task.py finish Clear active task
815
605
  python3 task.py workflow <id> Select workflow variant for active task
@@ -819,11 +609,10 @@ Usage:
819
609
  python3 task.py set-scope <dir> <scope> Set scope for PR title
820
610
  python3 task.py set-meta <dir> <key> <value> Set/overwrite a task metadata key
821
611
  python3 task.py rename <dir> <new-slug> Rename task, identity fields and references
822
- python3 task.py archive <task-dir> Archive completed task
612
+ python3 task.py complete <task-dir> Complete after Delivery Review and On-Site Closeout Phase acceptance
823
613
  python3 task.py add-subtask <parent> <child> Link child task to parent
824
614
  python3 task.py remove-subtask <parent> <child> Unlink child from parent
825
615
  python3 task.py list [--mine] [--status <status>] [--json] List tasks
826
- python3 task.py list-archive [YYYY-MM] List archived tasks
827
616
 
828
617
  Monorepo options:
829
618
  --package <pkg> Package name (validated against config.yaml packages)
@@ -831,16 +620,6 @@ Monorepo options:
831
620
  Rename options:
832
621
  --dry-run Print the change set without writing anything
833
622
 
834
- Archive options:
835
- --no-commit Skip the auto git commit after archiving
836
- --skip-branch-validation Archive despite missing or self-referential branch metadata.
837
- Archive normally refuses a task with no `branch` when it has a
838
- `base_branch` and the repo has a remote, or with
839
- `branch == base_branch`; repair those with `set-branch` /
840
- `set-base-branch` instead. Use this flag only for tasks that
841
- were never PR-backed. A recorded branch that was merged and
842
- deleted is only a warning and needs no flag.
843
-
844
623
  List options:
845
624
  --mine, -m Show only tasks assigned to current developer
846
625
  --status, -s <s> Filter by status (planning, in_progress, review, completed)
@@ -858,8 +637,7 @@ Examples:
858
637
  python3 task.py finish
859
638
  python3 task.py rename add-login add-sso --dry-run # Preview the change set
860
639
  python3 task.py rename add-login add-sso
861
- python3 task.py archive add-login
862
- python3 task.py archive add-login --skip-branch-validation # Task never had a branch of its own
640
+ python3 task.py complete add-login
863
641
  python3 task.py add-subtask parent-task child-task # Link existing tasks
864
642
  python3 task.py remove-subtask parent-task child-task
865
643
  python3 task.py list # List all active tasks
@@ -919,7 +697,7 @@ def main() -> int:
919
697
  p_create.add_argument(
920
698
  "--description",
921
699
  "-d",
922
- help="Task description (required, non-empty — an empty one is refused at archive)",
700
+ help="Task description (required, non-empty — an empty one cannot be completed)",
923
701
  )
924
702
  p_create.add_argument("--parent", help="Parent task directory (establishes subtask link)")
925
703
  p_create.add_argument("--package", help="Package name for monorepo projects")
@@ -965,17 +743,6 @@ def main() -> int:
965
743
  # start
966
744
  p_start = subparsers.add_parser("start", help="Set active task")
967
745
  p_start.add_argument("dir", help="Task directory")
968
- p_start.add_argument(
969
- "--allow-empty-context",
970
- action="store_true",
971
- help="Start even when implement.jsonl / check.jsonl have no curated entries",
972
- )
973
-
974
- # replan
975
- p_replan = subparsers.add_parser("replan", help="Return an in-progress task to planning")
976
- p_replan.add_argument("dir", help="Task directory")
977
- p_replan.add_argument("reason", nargs="+", help="Material reason for returning to planning")
978
-
979
746
  # current
980
747
  p_current = subparsers.add_parser("current", help="Show active task")
981
748
  p_current.add_argument("--source", action="store_true",
@@ -983,61 +750,6 @@ def main() -> int:
983
750
  p_current.add_argument("--json", action="store_true",
984
751
  help="Output machine-readable JSON")
985
752
 
986
- # continuity
987
- p_continuity = subparsers.add_parser("continuity", help="Read or explicitly update the current task Continuation Record")
988
- continuity_sub = p_continuity.add_subparsers(dest="continuity_command", required=True)
989
- continuity_status_parser = continuity_sub.add_parser("status", help="Show read-only Continuation Record status")
990
- continuity_status_parser.add_argument("--json", action="store_true", help="Output machine-readable JSON")
991
- continuity_seal = continuity_sub.add_parser("seal", help="Write a Continuation Record from an explicit request")
992
- continuity_seal.add_argument("--request", required=True, type=Path, help="Project-relative bounded request JSON")
993
- continuity_seal.add_argument("--expected", required=True, help="absent or the current record digest")
994
- continuity_seal.add_argument("--explicit-user-request", action="store_true", help="Required write confirmation")
995
- continuity_clear = continuity_sub.add_parser("clear", help="Clear the current Continuation Record")
996
- continuity_clear.add_argument("--expected", required=True, help="The current record digest or absent")
997
- continuity_clear.add_argument("--explicit-user-request", action="store_true", help="Required write confirmation")
998
-
999
- # ownership
1000
- p_ownership = subparsers.add_parser("ownership", help="Manage formal handoff task ownership")
1001
- ownership_sub = p_ownership.add_subparsers(dest="ownership_command", required=True)
1002
-
1003
- def add_ownership_common(parser, *, expected=False):
1004
- parser.add_argument("--task-id", required=True, help="Task id bound to the handoff")
1005
- parser.add_argument("--handoff-id", required=True, help="Immutable handoff id")
1006
- parser.add_argument("--core-digest", required=True, help="Immutable handoff core digest")
1007
- if expected:
1008
- parser.add_argument("--expected-generation", required=True, type=int)
1009
- parser.add_argument("--explicit-user-request", action="store_true", help="Required write confirmation")
1010
-
1011
- ownership_quiesce = ownership_sub.add_parser("quiesce", help="Begin source handoff quiescence")
1012
- ownership_quiesce.add_argument("--task", required=True, help="Current task path")
1013
- ownership_quiesce.add_argument("--source-session-id", required=True)
1014
- add_ownership_common(ownership_quiesce)
1015
-
1016
- ownership_seal = ownership_sub.add_parser("seal", help="Seal the source ownership boundary")
1017
- add_ownership_common(ownership_seal, expected=True)
1018
-
1019
- ownership_retire = ownership_sub.add_parser("retire", help="Retire source and expose handoff")
1020
- ownership_retire.add_argument("--archive-observation", required=True, choices=("not_required", "observed"))
1021
- add_ownership_common(ownership_retire, expected=True)
1022
-
1023
- ownership_retire_handoff = ownership_sub.add_parser("retire-handoff", help="Release one sealed handoff by exact id")
1024
- add_ownership_common(ownership_retire_handoff)
1025
-
1026
- ownership_claim = ownership_sub.add_parser("claim", help="Claim a ready handoff as this session")
1027
- ownership_claim.add_argument("--task", required=True, help="Task path to bind to this session")
1028
- add_ownership_common(ownership_claim, expected=True)
1029
-
1030
- ownership_consume = ownership_sub.add_parser("consume", help="Record target consumption")
1031
- add_ownership_common(ownership_consume, expected=True)
1032
-
1033
- ownership_archive = ownership_sub.add_parser("archive", help="Record post-consume retention archive")
1034
- add_ownership_common(ownership_archive, expected=True)
1035
-
1036
- ownership_status_parser = ownership_sub.add_parser("status", help="Show ownership status")
1037
- add_ownership_common(ownership_status_parser)
1038
- ownership_status_parser.add_argument("--json", action="store_true", help="Output machine-readable JSON")
1039
- ownership_status_parser.set_defaults(explicit_user_request=True)
1040
-
1041
753
  # finish
1042
754
  subparsers.add_parser("finish", help="Clear active task")
1043
755
 
@@ -1047,6 +759,45 @@ def main() -> int:
1047
759
  p_workflow.add_argument("--clear", action="store_true",
1048
760
  help="Remove the workflow selection (use default resolution)")
1049
761
 
762
+ # Business-phase task workflow state.
763
+ p_phase = subparsers.add_parser("phase", help="Read or update task phase state")
764
+ p_phase.add_argument(
765
+ "phase_action",
766
+ choices=("init", "show", "artifact", "accept", "skip", "wait", "block", "resume", "return", "route", "authorize", "admission"),
767
+ )
768
+ p_phase.add_argument("task_dir", help="Task directory or task name")
769
+ p_phase.add_argument("--expected-route-revision", help="Current task_route_revision required for mutation")
770
+ p_phase.add_argument("--task-kind", help="analysis | implementation | combined (init / route)")
771
+ p_phase.add_argument("--complexity", help="simple | standard | complex (init / route)")
772
+ p_phase.add_argument("--project-context", help="new | existing (init / route)")
773
+ p_phase.add_argument("--phase-ids", help="Comma-separated phase route (init / route)")
774
+ p_phase.add_argument("--route-reason", help="Reason when initialization omits one or more phases")
775
+ p_phase.add_argument("--route-evidence-ref", action="append", help="Evidence supporting an abbreviated initial route")
776
+ p_phase.add_argument("--target-phase", help="Earlier phase to revisit, or first affected phase for route change")
777
+ p_phase.add_argument("--artifact-ref", action="append", help="Task-relative file in the current phase output")
778
+ p_phase.add_argument("--artifact-revision", help="Current artifact_revision required for acceptance")
779
+ p_phase.add_argument("--result-ref", help="Task result artifact reference")
780
+ p_phase.add_argument("--outcome-kind", help="Phase result kind; pending phase outcomes may accompany wait/block")
781
+ p_phase.add_argument("--evidence-ref", action="append", help="Evidence reference (repeatable)")
782
+ p_phase.add_argument("--reason", help="Reason for skip, block, return, route change, or cancellation")
783
+ p_phase.add_argument("--contract-ref", help="Accepted implementation contract reference")
784
+ p_phase.add_argument("--approval-ref", help="Explicit implementation approval reference")
785
+ p_phase.add_argument("--closeout-disposition", help="delivery_ready | no_go | cancelled (Delivery Review and On-Site Closeout Phase)")
786
+ p_phase.add_argument("--child-disposition", action="append", help="Child task disposition as <task-id>=integrated|continue|independent|cancelled (repeatable at closeout)")
787
+ p_phase.add_argument("--dependency", action="append", help="Route dependency identifier (admission)")
788
+ p_phase.add_argument("--admission-state", choices=("ready", "missing", "stale", "incompatible", "blocked"), help="Dependency admission result")
789
+
790
+ p_delegate = subparsers.add_parser("delegate-start", help="Start an authorized child task in a Paseo worktree")
791
+ p_delegate.add_argument("child_task", help="Linked child task directory or name")
792
+
793
+ add_continuity_commands(subparsers)
794
+
795
+ # cancel task lifecycle independently of phase transitions
796
+ p_cancel = subparsers.add_parser("cancel", help="Cancel task lifecycle")
797
+ p_cancel.add_argument("task_dir", help="Task directory or task name")
798
+ p_cancel.add_argument("--reason", required=True, help="Why the task is cancelled")
799
+ p_cancel.add_argument("--evidence-ref", action="append", required=True, help="Task-relative cancellation evidence")
800
+
1050
801
  # set-branch
1051
802
  p_branch = subparsers.add_parser("set-branch", help="Set git branch")
1052
803
  p_branch.add_argument("dir", help="Task directory")
@@ -1078,19 +829,6 @@ def main() -> int:
1078
829
  help="Print the change set without writing anything",
1079
830
  )
1080
831
 
1081
- # archive
1082
- p_archive = subparsers.add_parser("archive", help="Archive task")
1083
- p_archive.add_argument("name", help="Task directory or name")
1084
- p_archive.add_argument("--no-commit", action="store_true", help="Skip auto git commit after archive")
1085
- p_archive.add_argument(
1086
- "--skip-branch-validation",
1087
- action="store_true",
1088
- help=(
1089
- "Archive even when branch metadata is missing or self-referential "
1090
- "(for tasks that were never PR-backed)"
1091
- ),
1092
- )
1093
-
1094
832
  # list
1095
833
  p_list = subparsers.add_parser("list", help="List tasks")
1096
834
  p_list.add_argument("--mine", "-m", action="store_true", help="My tasks only")
@@ -1107,9 +845,9 @@ def main() -> int:
1107
845
  p_rmsub.add_argument("parent_dir", help="Parent task directory")
1108
846
  p_rmsub.add_argument("child_dir", help="Child task directory")
1109
847
 
1110
- # list-archive
1111
- p_listarch = subparsers.add_parser("list-archive", help="List archived tasks")
1112
- p_listarch.add_argument("month", nargs="?", help="Month (YYYY-MM)")
848
+ # complete task lifecycle
849
+ p_complete = subparsers.add_parser("complete", help="Complete after Delivery Review and On-Site Closeout Phase acceptance")
850
+ p_complete.add_argument("task_dir", help="Task directory or task name")
1113
851
 
1114
852
  args = parser.parse_args()
1115
853
 
@@ -1117,28 +855,32 @@ def main() -> int:
1117
855
  show_usage()
1118
856
  return 1
1119
857
 
858
+ if args.command == "continuity":
859
+ return continuity_show(args) if args.continuity_action == "show" else continuity_capture(args)
860
+ if args.command == "transfer":
861
+ return transfer_task_ownership(args)
862
+
1120
863
  commands = {
1121
864
  "create": cmd_create,
1122
865
  "add-context": cmd_add_context,
1123
866
  "validate": cmd_validate,
1124
867
  "list-context": cmd_list_context,
1125
868
  "start": cmd_start,
1126
- "replan": cmd_replan,
1127
869
  "current": cmd_current,
1128
- "continuity": cmd_continuity,
1129
- "ownership": cmd_ownership,
1130
870
  "finish": cmd_finish,
1131
871
  "workflow": cmd_workflow,
872
+ "phase": cmd_phase,
873
+ "delegate-start": cmd_delegate_start,
874
+ "complete": cmd_complete_task,
875
+ "cancel": cmd_cancel_task,
1132
876
  "set-branch": cmd_set_branch,
1133
877
  "set-base-branch": cmd_set_base_branch,
1134
878
  "set-scope": cmd_set_scope,
1135
879
  "set-meta": cmd_set_meta,
1136
880
  "rename": cmd_rename,
1137
- "archive": cmd_archive,
1138
881
  "add-subtask": cmd_add_subtask,
1139
882
  "remove-subtask": cmd_remove_subtask,
1140
883
  "list": cmd_list,
1141
- "list-archive": cmd_list_archive,
1142
884
  }
1143
885
 
1144
886
  if args.command in commands: