@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
@@ -4,7 +4,7 @@ Safe git-add helpers for Trellis-owned paths.
4
4
  Why this module exists
5
5
  ----------------------
6
6
  A real user incident: a project's `.gitignore` listed `.trellis/` (company-wide
7
- template / personal habit). When `add_session.py` and `task.py archive` ran
7
+ template / personal habit). When `add_session.py` ran
8
8
  their auto-commit and `git add` failed with `ignored by .gitignore`, the AI
9
9
  agent driving the workflow "fixed" it by retrying with
10
10
  `git add -f .trellis/` — which fan-out-included every ignored subtree
@@ -13,8 +13,8 @@ agent driving the workflow "fixed" it by retrying with
13
13
 
14
14
  Design
15
15
  ------
16
- - Scripts only stage SPECIFIC product paths (journal files, index.md, the
17
- current task dir, the archive dir). Never the whole `.trellis/` tree.
16
+ - Scripts only stage SPECIFIC product paths (journal files, index.md, and the
17
+ current task dir). Never the whole `.trellis/` tree.
18
18
  - If plain `git add <specific>` fails with "ignored by", DO NOT retry with
19
19
  ``-f``. The presence of `.trellis/` in `.gitignore` is treated as user
20
20
  intent ("keep .trellis/ local-only"). The script warns and skips the
@@ -37,7 +37,6 @@ from pathlib import Path
37
37
 
38
38
  from .git import run_git, run_git_retry_index_lock
39
39
  from .paths import (
40
- DIR_ARCHIVE,
41
40
  DIR_TASKS,
42
41
  DIR_WORKFLOW,
43
42
  DIR_WORKSPACE,
@@ -72,8 +71,7 @@ def safe_trellis_paths_to_add(
72
71
  - .trellis/workspace/<developer>/journal-*.md
73
72
  - .trellis/workspace/<developer>/index.md
74
73
  - .trellis/tasks/<task_name>/ (ONLY the current task dir when
75
- ``task_name`` is passed; plus its archive location if the task
76
- already lives under archive/)
74
+ ``task_name`` is passed)
77
75
 
78
76
  Excluded (intentionally — these must not be staged):
79
77
  - .trellis/.backup-*, .trellis/worktrees/,
@@ -82,12 +80,11 @@ def safe_trellis_paths_to_add(
82
80
  Scope contract (see #303 / break-loop analysis): when ``task_name`` is
83
81
  passed, the task segment stages ONLY that task directory — it never walks
84
82
  ``tasks_dir.iterdir()`` over all active tasks. This mirrors
85
- :func:`safe_archive_paths_to_add` and prevents dirty changes in OTHER
86
- parallel-window task dirs from being bundled into the session auto-commit.
83
+ and prevents dirty changes in OTHER parallel-window task dirs from being
84
+ bundled into the session auto-commit.
87
85
 
88
- Backwards-compat: with no ``task_name``, the function walks every active
89
- task directory (+ the archive subtree) the old wide way. New callers
90
- should always pass ``task_name``.
86
+ With no ``task_name``, the function walks every direct task directory.
87
+ New callers should always pass ``task_name``.
91
88
  """
92
89
  paths: list[str] = []
93
90
 
@@ -112,90 +109,20 @@ def safe_trellis_paths_to_add(
112
109
  return paths
113
110
 
114
111
  if task_name is not None:
115
- # Narrow scope — ONLY the current task directory (active or archived).
112
+ # Narrow scope — ONLY the current task directory.
116
113
  # Never iterdir() all tasks: parallel-window dirty task dirs must not
117
114
  # leak into the session auto-commit.
118
115
  active_task = tasks_dir / task_name
119
116
  if active_task.is_dir():
120
117
  paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{task_name}")
121
- archived_task = tasks_dir / DIR_ARCHIVE / task_name
122
- if archived_task.is_dir():
123
- paths.append(
124
- f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}/{task_name}"
125
- )
126
118
  return paths
127
119
 
128
- # Legacy wide scope (no task_name): each direct child of tasks/ that is a
129
- # directory and not the archive root, plus the whole archive subtree.
120
+ # Wide scope (no task_name): each direct task directory.
130
121
  for child in sorted(tasks_dir.iterdir()):
131
122
  if not child.is_dir():
132
123
  continue
133
- if child.name == DIR_ARCHIVE:
134
- continue
135
124
  paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{child.name}")
136
125
 
137
- archive_dir = tasks_dir / DIR_ARCHIVE
138
- if archive_dir.is_dir():
139
- paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}")
140
-
141
- return paths
142
-
143
-
144
- def safe_archive_paths_to_add(
145
- repo_root: Path,
146
- task_name: str | None = None,
147
- modified_children: list[str] | None = None,
148
- ) -> list[str]:
149
- """Return paths to stage after `task.py archive`.
150
-
151
- Scoped to ONLY the paths the archive operation actually touched:
152
-
153
- - the archive subtree (where the freshly-moved task lives)
154
- - the source task directory (for source-side deletes; caller pairs
155
- this with `git rm --cached` since `git add` won't stage deletes
156
- for a path that no longer exists in the working tree)
157
- - any child task directories whose `task.json` was edited to drop
158
- the archived parent (parent-children relationship update)
159
-
160
- This narrow scope avoids "scope creep" — dirty changes in OTHER
161
- active task dirs (parallel-window edits) are NOT bundled into the
162
- archive commit. Callers handle each kind of change in its own
163
- commit boundary.
164
-
165
- Backwards-compat: with no arguments, the function walks the whole
166
- `.trellis/tasks/` subtree the old way (active tasks + archive). New
167
- callers should always pass `task_name`.
168
- """
169
- paths: list[str] = []
170
- tasks_dir = repo_root / DIR_WORKFLOW / DIR_TASKS
171
- if not tasks_dir.is_dir():
172
- return paths
173
-
174
- archive_dir = tasks_dir / DIR_ARCHIVE
175
-
176
- if task_name is not None:
177
- # Narrow scope — only paths that still exist on disk (so
178
- # `git add` doesn't choke on the moved-away source). The caller
179
- # handles the source-side deletes via `git rm --cached`
180
- # explicitly.
181
- if archive_dir.is_dir():
182
- paths.append(
183
- f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}"
184
- )
185
- for child_name in modified_children or []:
186
- paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{child_name}")
187
- return paths
188
-
189
- # Legacy wide scope (no task_name): preserve old behavior so callers
190
- # that have not been updated keep working.
191
- if archive_dir.is_dir():
192
- paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}")
193
- for child in sorted(tasks_dir.iterdir()):
194
- if not child.is_dir():
195
- continue
196
- if child.name == DIR_ARCHIVE:
197
- continue
198
- paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{child.name}")
199
126
  return paths
200
127
 
201
128
 
@@ -225,9 +152,7 @@ def safe_git_add(
225
152
 
226
153
  ``retry_on_index_lock`` opts into the bounded backoff-retry for a held
227
154
  ``.git/index.lock`` (see :func:`~.git.run_git_retry_index_lock`). It is
228
- off by default: only the archive path, which has already moved the task
229
- directory on disk by the time it stages, needs to wait out a transient
230
- lock rather than fail.
155
+ off by default; callers that already changed files on disk can opt in.
231
156
  """
232
157
  if not paths:
233
158
  return True, False, ""
@@ -275,10 +200,6 @@ def print_gitignore_warning(paths: list[str]) -> None:
275
200
  "[WARN] .trellis/tasks/<task-dir>/",
276
201
  file=sys.stderr,
277
202
  )
278
- print(
279
- "[WARN] .trellis/tasks/archive/",
280
- file=sys.stderr,
281
- )
282
203
  print("[WARN]", file=sys.stderr)
283
204
  print(
284
205
  "[WARN] Recommended: change your .gitignore from `.trellis/` to specific",
@@ -22,7 +22,6 @@ import sys
22
22
  from pathlib import Path
23
23
 
24
24
  from .active_task import resolve_context_key
25
- from .continuation_record import status as continuity_status
26
25
  from .config import get_git_packages
27
26
  from .git import run_git
28
27
  from .packages_context import get_packages_section
@@ -559,8 +558,6 @@ def get_context_json(repo_root: Path | None = None) -> dict:
559
558
  if pkg_git_info:
560
559
  result["packageGit"] = pkg_git_info
561
560
 
562
- result["continuity"] = continuity_status(repo_root)
563
-
564
561
  return result
565
562
 
566
563
 
@@ -647,8 +644,6 @@ def get_context_text(repo_root: Path | None = None) -> str:
647
644
  lines.append("[!] This task has prd.md - read it for task details")
648
645
  else:
649
646
  lines.append("(none)")
650
- continuity = continuity_status(repo_root)
651
- lines.append(f"Continuation Record: {continuity['status']}")
652
647
  lines.append("")
653
648
 
654
649
  # Active tasks
@@ -802,8 +797,6 @@ def get_context_record_json(repo_root: Path | None = None) -> dict:
802
797
  if pkg_git_info:
803
798
  result["packageGit"] = pkg_git_info
804
799
 
805
- result["continuity"] = continuity_status(repo_root)
806
-
807
800
  return result
808
801
 
809
802
 
@@ -831,7 +824,7 @@ def get_context_text_record(repo_root: Path | None = None) -> str:
831
824
 
832
825
  # MY ACTIVE TASKS — first and prominent
833
826
  lines.append(f"## [!!!] MY ACTIVE TASKS (Assigned to {developer})")
834
- lines.append("[!] Review whether any should be archived before recording this session.")
827
+ lines.append("Review task progress and remaining work before recording this session.")
835
828
  lines.append("")
836
829
 
837
830
  tasks_dir = get_tasks_dir(repo_root)
@@ -55,7 +55,7 @@ Translation examples (glob → matches / non-matches):
55
55
  matches only that exact file
56
56
  packages/cli/src/commands/*.ts
57
57
  matches packages/cli/src/commands/update.ts
58
- not packages/cli/src/commands/channel/spawn.ts
58
+ not packages/cli/src/commands/teamwork/spawn.ts
59
59
  packages/cli/src/templates/**
60
60
  matches packages/cli/src/templates/trellis/index.ts (any depth)
61
61
  not packages/cli/src/templates (the directory itself)
@@ -26,11 +26,10 @@ import json
26
26
  from pathlib import Path
27
27
 
28
28
  from .config import get_context_injection_limits
29
- from .context_projection import parse_context_manifest, project_agent_context
30
29
  from .git import branch_exists_locally
31
30
  from .io import read_json
32
31
  from .log import Colors, colored
33
- from .paths import FILE_TASK_JSON, get_repo_root
32
+ from .paths import DIR_TASKS, DIR_WORKFLOW, FILE_TASK_JSON, get_repo_root
34
33
  from .task_utils import resolve_task_dir
35
34
 
36
35
  # Extensions that look like code rather than spec/research docs. Entries with
@@ -92,6 +91,12 @@ def cmd_add_context(args: argparse.Namespace) -> int:
92
91
  jsonl_file = target_dir / jsonl_name
93
92
  full_path = repo_root / path
94
93
 
94
+ from .task_continuity import task_mutation_guard
95
+
96
+ task_data = read_json(target_dir / FILE_TASK_JSON)
97
+ if not isinstance(task_data, dict):
98
+ print(colored(f"Error: task.json is unavailable at {target_dir}", Colors.RED))
99
+ return 1
95
100
  entry_type = "file"
96
101
  if full_path.is_dir():
97
102
  entry_type = "directory"
@@ -115,8 +120,12 @@ def cmd_add_context(args: argparse.Namespace) -> int:
115
120
  else:
116
121
  entry = {"file": path, "reason": reason}
117
122
 
118
- with jsonl_file.open("a", encoding="utf-8") as f:
119
- f.write(json.dumps(entry, ensure_ascii=False) + "\n")
123
+ with task_mutation_guard(repo_root, target_dir, task_data) as allowed:
124
+ if not allowed:
125
+ print(colored("TASK_TRANSFER_ACTIVE: task changes are fenced until ownership is consumed or released", Colors.RED))
126
+ return 1
127
+ with jsonl_file.open("a", encoding="utf-8") as f:
128
+ f.write(json.dumps(entry, ensure_ascii=False) + "\n")
120
129
 
121
130
  print(colored(f"Added {entry_type}: {path}", Colors.GREEN))
122
131
  return 0
@@ -126,19 +135,6 @@ def cmd_add_context(args: argparse.Namespace) -> int:
126
135
  # Command: validate
127
136
  # =============================================================================
128
137
 
129
- def curated_entry_count(jsonl_file: Path) -> int | None:
130
- """Count curated entries in a jsonl context manifest.
131
-
132
- Returns None when the file does not exist — `task.py create` seeds the
133
- manifests only on sub-agent-capable platforms, so an absent file means no
134
- sub-agent will ever read it and callers should not gate on it. A curated
135
- entry is a JSON object row carrying a truthy ``file`` (or legacy ``path``)
136
- value: the same rows the sub-agent injection hook materializes.
137
- """
138
- entries, _, manifest_exists = parse_context_manifest(jsonl_file)
139
- return len(entries) if manifest_exists else None
140
-
141
-
142
138
  def cmd_validate(args: argparse.Namespace) -> int:
143
139
  """Validate JSONL context files."""
144
140
  repo_root = get_repo_root()
@@ -199,6 +195,55 @@ def _is_exempt_from_code_file_warning(file_path: str, task_rel: str) -> bool:
199
195
  return False
200
196
 
201
197
 
198
+ def _resolve_context_entry_path(
199
+ file_path: str, repo_root: Path, task_dir: Path | None
200
+ ) -> Path | None:
201
+ """Bind historical self-references to their archive copy without fallback."""
202
+ repo_path = repo_root / file_path
203
+ if task_dir is None:
204
+ return repo_path
205
+
206
+ try:
207
+ task_parts = task_dir.resolve().relative_to(repo_root.resolve()).parts
208
+ except ValueError:
209
+ return repo_path
210
+
211
+ archive_prefix = (DIR_WORKFLOW, DIR_TASKS, "archive")
212
+ if len(task_parts) != 5 or task_parts[:3] != archive_prefix:
213
+ return repo_path
214
+
215
+ year_month = task_parts[3]
216
+ if (
217
+ len(year_month) != 7
218
+ or year_month[4] != "-"
219
+ or not year_month[:4].isdigit()
220
+ or not year_month[5:].isdigit()
221
+ ):
222
+ return repo_path
223
+
224
+ historical_root = f"{DIR_WORKFLOW}/{DIR_TASKS}/{task_dir.name}"
225
+ posix_path = file_path.replace("\\", "/")
226
+ if posix_path == historical_root:
227
+ relative_parts: tuple[str, ...] = ()
228
+ elif posix_path.startswith(f"{historical_root}/"):
229
+ relative_path = posix_path[len(historical_root) + 1 :]
230
+ if relative_path.endswith("/"):
231
+ relative_path = relative_path[:-1]
232
+ relative_parts = tuple(relative_path.split("/")) if relative_path else ()
233
+ if any(part in ("", ".", "..") for part in relative_parts):
234
+ return None
235
+ else:
236
+ return repo_path
237
+
238
+ try:
239
+ archive_root = task_dir.resolve()
240
+ resolved_path = task_dir.joinpath(*relative_parts).resolve()
241
+ resolved_path.relative_to(archive_root)
242
+ except (OSError, RuntimeError, ValueError):
243
+ return None
244
+ return resolved_path
245
+
246
+
202
247
  def _validate_jsonl(jsonl_file: Path, repo_root: Path, task_dir: Path | None = None) -> int:
203
248
  """Validate a single JSONL file.
204
249
 
@@ -207,10 +252,11 @@ def _validate_jsonl(jsonl_file: Path, repo_root: Path, task_dir: Path | None = N
207
252
  accepting them here would pass locally and fail later. Other rows without
208
253
  a ``file`` field are skipped silently, matching what consumers do.
209
254
 
210
- The same Python projection that the shared Hook renders is evaluated for
211
- each role. Hygiene warnings remain advisory; every source that would be
212
- truncated, omitted, or indexed instead of appearing as complete body text
213
- is a hard validation error.
255
+ Beyond hard errors (missing file/dir, invalid JSON), this also prints
256
+ non-blocking hygiene warnings (never counted in ``errors``, never change
257
+ the exit code): entries that look like code files rather than
258
+ spec/research docs, and entries whose file size exceeds the configured
259
+ sub-agent context injection cap (``context_injection.max_file_bytes``).
214
260
  """
215
261
  file_name = jsonl_file.name
216
262
  errors = 0
@@ -226,57 +272,104 @@ def _validate_jsonl(jsonl_file: Path, repo_root: Path, task_dir: Path | None = N
226
272
  except ValueError:
227
273
  task_rel = ""
228
274
 
229
- entries, manifest_problems, _ = parse_context_manifest(jsonl_file)
230
- for problem in manifest_problems:
231
- print(f" {colored(f'{file_name}:{problem.line}: {problem.message}', Colors.RED)}")
232
- errors += 1
275
+ max_file_bytes = get_context_injection_limits(repo_root).get("max_file_bytes", 0)
276
+
277
+ line_num = 0
278
+ real_entries = 0
279
+ for line in jsonl_file.read_text(encoding="utf-8").splitlines():
280
+ line_num += 1
281
+ if not line.strip():
282
+ continue
283
+
284
+ try:
285
+ data = json.loads(line)
286
+ except json.JSONDecodeError:
287
+ print(f" {colored(f'{file_name}:{line_num}: Invalid JSON', Colors.RED)}")
288
+ errors += 1
289
+ continue
290
+
291
+ if not isinstance(data, dict):
292
+ print(
293
+ f" {colored(f'{file_name}:{line_num}: Expected a JSON object', Colors.RED)}"
294
+ )
295
+ errors += 1
296
+ continue
297
+
298
+ if "_example" in data:
299
+ error_message = (
300
+ f"{file_name}:{line_num}: Placeholder `_example` row left by an older "
301
+ "task.py create — delete this line, or replace it with "
302
+ '{"file": "<path>", "reason": "<why>"}'
303
+ )
304
+ print(f" {colored(error_message, Colors.RED)}")
305
+ errors += 1
306
+ continue
307
+
308
+ file_path = data.get("file")
309
+ entry_type = data.get("type", "file")
233
310
 
234
- for entry in entries:
235
- if entry.entry_type == "directory":
311
+ if not file_path:
312
+ # Comment / unknown row without a path — skip silently
236
313
  continue
237
- extension = Path(entry.path).suffix.lower()
314
+
315
+ if not isinstance(file_path, str):
316
+ # A truthy non-string (e.g. {"file": 1}) reached path joining and
317
+ # raised TypeError, so validation crashed on the row it exists to
318
+ # report.
319
+ print(
320
+ f" {colored(f'{file_name}:{line_num}: `file` must be a string path', Colors.RED)}"
321
+ )
322
+ errors += 1
323
+ continue
324
+
325
+ real_entries += 1
326
+ full_path = _resolve_context_entry_path(file_path, repo_root, task_dir)
327
+ if entry_type == "directory":
328
+ if full_path is None or not full_path.is_dir():
329
+ print(f" {colored(f'{file_name}:{line_num}: Directory not found: {file_path}', Colors.RED)}")
330
+ errors += 1
331
+ continue
332
+
333
+ if full_path is None or not full_path.is_file():
334
+ print(f" {colored(f'{file_name}:{line_num}: File not found: {file_path}', Colors.RED)}")
335
+ errors += 1
336
+ continue
337
+
338
+ extension = Path(file_path).suffix.lower()
238
339
  if extension in _CODE_FILE_EXTENSIONS and not _is_exempt_from_code_file_warning(
239
- entry.path, task_rel
340
+ file_path, task_rel
240
341
  ):
241
342
  warning_message = (
242
- f"{file_name}:{entry.line}: Warning: {entry.path} looks like a code file — "
343
+ f"{file_name}:{line_num}: Warning: {file_path} looks like a code file — "
243
344
  "implement/check.jsonl should reference spec/research docs; "
244
345
  "agents read code themselves"
245
346
  )
246
347
  print(f" {colored(warning_message, Colors.YELLOW)}")
247
348
 
248
- if errors == 0 and not entries:
249
- # Seed-only / empty manifest: sub-agents dispatched for this task
250
- # would run with zero spec context (#573). Silent-green here is how
251
- # more than half the tasks in the report ended up uncurated.
252
- action = file_name.split(".", 1)[0]
253
- print(
254
- f" {colored(f'{file_name}: ✗ (0 curated entries — sub-agents would get zero spec context)', Colors.RED)}"
255
- )
256
- print(
257
- f" Curate it: python3 .trellis/scripts/task.py add-context <task> {action} <path> \"<why>\""
258
- )
259
- print(
260
- " Intentionally empty? Bypass at start: task.py start <task> --allow-empty-context"
261
- )
262
- return 1
349
+ if max_file_bytes:
350
+ # Advisory hygiene warning, so it must never be what fails
351
+ # `validate`. `stat()` can still raise after the `is_file()` check
352
+ # above — a permission change, or the file removed in between.
353
+ try:
354
+ size: int | None = full_path.stat().st_size
355
+ except OSError:
356
+ size = None
357
+ if size is not None and size > max_file_bytes:
358
+ warning_message = (
359
+ f"{file_name}:{line_num}: Warning: {file_path} is {size} bytes, "
360
+ f"exceeds context_injection.max_file_bytes ({max_file_bytes}); "
361
+ "injection will truncate it"
362
+ )
363
+ print(f" {colored(warning_message, Colors.YELLOW)}")
263
364
 
264
- if errors == 0 and task_dir is not None:
265
- role = jsonl_file.stem
266
- projection = project_agent_context(
267
- repo_root, task_dir, role, get_context_injection_limits(repo_root)
365
+ if errors == 0 and real_entries == 0:
366
+ print(
367
+ f" {colored(f'{file_name}: ✓ (no context entries; manifests are optional)', Colors.YELLOW)}"
268
368
  )
269
- for issue in projection.issues:
270
- line_label = str(issue.line) if issue.line is not None else "artifact"
271
- message = (
272
- f"{file_name}:{line_label}: role={issue.role} source={issue.category} "
273
- f"path={issue.path}: cannot be injected in full — {issue.reason}"
274
- )
275
- print(f" {colored(message, Colors.RED)}")
276
- errors += 1
369
+ return 0
277
370
 
278
371
  if errors == 0:
279
- print(f" {colored(f'{file_name}: ✓ ({len(entries)} entries)', Colors.GREEN)}")
372
+ print(f" {colored(f'{file_name}: ✓ ({real_entries} entries)', Colors.GREEN)}")
280
373
  else:
281
374
  print(f" {colored(f'{file_name}: ✗ ({errors} errors)', Colors.RED)}")
282
375
 
@@ -320,7 +413,7 @@ def cmd_list_context(args: argparse.Namespace) -> int:
320
413
  if not isinstance(data, dict):
321
414
  continue
322
415
 
323
- file_path = data.get("file") or data.get("path")
416
+ file_path = data.get("file")
324
417
  if not file_path:
325
418
  # Placeholder / comment row — don't count as a real entry
326
419
  continue