@pennixrv/trellis 0.7.0-beta.8 → 0.7.1

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.0-beta.9.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 -191
  292. package/dist/templates/copilot/hooks/session-start.py +30 -26
  293. package/dist/templates/copilot/prompts/brainstorm.prompt.md +7 -150
  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 +563 -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 +114 -377
  340. package/dist/templates/trellis/workflow.md +111 -699
  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 -193
  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 -69
  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 -597
  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
@@ -87,14 +87,6 @@ def find_repo_root(start_path: str) -> str | None:
87
87
  return None
88
88
 
89
89
 
90
- def _real_path_contained(base_real: str, target_real: str) -> bool:
91
- """Return whether a real path is inside the real base path."""
92
- try:
93
- return os.path.commonpath([base_real, target_real]) == base_real
94
- except ValueError:
95
- return False
96
-
97
-
98
90
  def _detect_platform(input_data: dict) -> str | None:
99
91
  if _hook_event_name(input_data) == "SubagentStart":
100
92
  return "codex"
@@ -149,7 +141,7 @@ def get_current_task(
149
141
  input_data: dict,
150
142
  *,
151
143
  platform: str | None = None,
152
- allow_single_session_fallback: bool = False,
144
+ allow_single_session_fallback: bool = True,
153
145
  allow_environment_context: bool = True,
154
146
  require_existing: bool = False,
155
147
  ) -> str | None:
@@ -175,11 +167,11 @@ def get_current_task(
175
167
 
176
168
 
177
169
  # =============================================================================
178
- # Context Injection
170
+ # Context Injection Limits (issue #441)
179
171
  #
180
- # The shared Python projection lives in the active project's stamped
181
- # `.trellis/scripts/common/context_projection.py`. These fallback limits keep
182
- # the installed Hook fail-open when an older project has not been updated yet.
172
+ # Notice text and behavior mirrored byte-for-byte in the Pi TS extension
173
+ # (templates/pi/extensions/trellis/index.ts.txt). Changing wording here
174
+ # requires changing it there too.
183
175
  # =============================================================================
184
176
 
185
177
  DEFAULT_MAX_FILE_BYTES = 32768
@@ -206,64 +198,455 @@ def _get_limits(repo_root: str) -> dict[str, int]:
206
198
  return dict(DEFAULT_LIMITS)
207
199
 
208
200
 
209
- def _project_context(repo_root: str, task_dir: str, agent_type: str):
210
- """Load the task-owned projection evaluator for the current project.
201
+ def truncate_utf8(data: bytes, cap: int) -> bytes:
202
+ """Truncate ``data`` to at most ``cap`` bytes without splitting a UTF-8
203
+ multi-byte sequence.
211
204
 
212
- Hooks are installed outside the project, so the evaluator deliberately
213
- resolves from the active project's stamped `.trellis/scripts` tree.
205
+ ``cap <= 0`` means "no limit" — returns ``data`` unchanged.
214
206
  """
215
- scripts_dir = Path(repo_root) / DIR_WORKFLOW / "scripts"
216
- if str(scripts_dir) not in sys.path:
217
- sys.path.insert(0, str(scripts_dir))
218
- from common.context_projection import project_agent_context # type: ignore[import-not-found]
207
+ if cap <= 0 or len(data) <= cap:
208
+ return data
209
+
210
+ truncated = data[:cap]
211
+ i = len(truncated)
212
+ # Back off over continuation bytes (10xxxxxx) to find the lead byte.
213
+ while i > 0 and (truncated[i - 1] & 0xC0) == 0x80:
214
+ i -= 1
215
+ if i == 0:
216
+ return b""
217
+
218
+ lead = truncated[i - 1]
219
+ if lead & 0x80:
220
+ if (lead & 0xE0) == 0xC0:
221
+ seq_len = 2
222
+ elif (lead & 0xF0) == 0xE0:
223
+ seq_len = 3
224
+ elif (lead & 0xF8) == 0xF0:
225
+ seq_len = 4
226
+ else:
227
+ seq_len = 1
228
+ # Cut before the lead byte when its full sequence didn't fit;
229
+ # otherwise the trailing sequence is complete — keep it whole.
230
+ if (i - 1) + seq_len > len(truncated):
231
+ return truncated[: i - 1]
232
+
233
+ return truncated
234
+
235
+
236
+ class _Budget:
237
+ """Tracks the running total of bytes emitted into the sub-agent context."""
238
+
239
+ def __init__(self, max_total_bytes: int) -> None:
240
+ self.max_total_bytes = max_total_bytes
241
+ self.used = 0
242
+
243
+ def has_room(self, size: int) -> bool:
244
+ if self.max_total_bytes <= 0:
245
+ return True
246
+ return self.used + size <= self.max_total_bytes
247
+
248
+ def add(self, size: int) -> None:
249
+ self.used += size
250
+
251
+
252
+ def _real_path_contained(base_real: str, target_real: str) -> bool:
253
+ """Whether an already-realpath'd target sits under an already-realpath'd base.
254
+
255
+ ValueError on Windows when the two sit on different drives; that is
256
+ outside the base by definition, so it fails closed.
257
+ """
258
+ try:
259
+ return os.path.commonpath([base_real, target_real]) == base_real
260
+ except ValueError:
261
+ return False
262
+
263
+
264
+ def _read_file_bytes(base_path: str, file_path: str) -> bytes | None:
265
+ """Read raw file bytes, return None if file doesn't exist."""
266
+ full_path = os.path.join(base_path, file_path)
267
+ try:
268
+ root_real = os.path.realpath(base_path)
269
+ # `.trellis` may itself be a symlink into a store outside the repo
270
+ # (#567); its real location is a second legitimate containment base.
271
+ workflow_real = os.path.realpath(os.path.join(base_path, ".trellis"))
272
+ full_real = os.path.realpath(full_path)
273
+ if not _real_path_contained(root_real, full_real) and not (
274
+ _real_path_contained(workflow_real, full_real)
275
+ ):
276
+ return None
277
+ except OSError:
278
+ return None
279
+ if os.path.exists(full_path) and os.path.isfile(full_path):
280
+ try:
281
+ with open(full_path, "rb") as f:
282
+ return f.read()
283
+ except Exception:
284
+ return None
285
+ return None
286
+
287
+
288
+ def _truncate_notice(path: str, cap: int) -> str:
289
+ return f"\n[Trellis: truncated at {cap} bytes — read {path} for the full content]"
290
+
291
+
292
+ def _is_binary_content(data: bytes) -> bool:
293
+ """Return True when raw bytes should not be decoded into model context."""
294
+ if b"\x00" in data:
295
+ return True
296
+ try:
297
+ data.decode("utf-8", errors="strict")
298
+ except UnicodeDecodeError:
299
+ return True
300
+ return False
301
+
219
302
 
220
- return project_agent_context(
221
- Path(repo_root), Path(repo_root) / task_dir, agent_type, _get_limits(repo_root)
303
+ def _binary_notice(path: str, size: int, reason: str) -> str:
304
+ return (
305
+ f"[Trellis: not inlined (binary file) — "
306
+ f"{path} ({size} bytes): {reason}]"
222
307
  )
223
308
 
224
309
 
310
+ def _index_notice(path: str, size: int, reason: str) -> str:
311
+ return (
312
+ f"[Trellis: not inlined (total context limit reached) — "
313
+ f"{path} ({size} bytes): {reason}]"
314
+ )
315
+
316
+
317
+ def _budgeted_block(
318
+ budget: _Budget,
319
+ header: str,
320
+ plain_path: str,
321
+ content: str,
322
+ reason: str,
323
+ size_for_index: int,
324
+ ) -> str:
325
+ """Return an inlined ``=== header ===`` block, or degrade to an index
326
+ notice once the total context budget is exhausted."""
327
+ block = f"=== {header} ===\n{content}"
328
+ block_bytes = len(block.encode("utf-8"))
329
+ if not budget.has_room(block_bytes):
330
+ notice = _index_notice(plain_path, size_for_index, reason)
331
+ budget.add(len(notice.encode("utf-8")))
332
+ return notice
333
+ budget.add(block_bytes)
334
+ return block
335
+
336
+
337
+ def _materialize_file(
338
+ base_path: str,
339
+ file_path: str,
340
+ reason: str,
341
+ limits: dict[str, int],
342
+ budget: _Budget,
343
+ ) -> str | None:
344
+ """Read a JSONL-referenced file, apply the per-file cap, then budget it."""
345
+ data = _read_file_bytes(base_path, file_path)
346
+ if data is None:
347
+ return None
348
+
349
+ size = len(data)
350
+ if _is_binary_content(data):
351
+ notice = _binary_notice(file_path, size, reason)
352
+ budget.add(len(notice.encode("utf-8")))
353
+ return notice
354
+
355
+ cap = limits["max_file_bytes"]
356
+ truncated_bytes = truncate_utf8(data, cap)
357
+ content = truncated_bytes.decode("utf-8", errors="replace")
358
+ if len(truncated_bytes) < size:
359
+ content += _truncate_notice(file_path, cap)
360
+
361
+ return _budgeted_block(budget, file_path, file_path, content, reason, size)
362
+
363
+
364
+ def _materialize_directory(
365
+ base_path: str,
366
+ dir_path: str,
367
+ reason: str,
368
+ limits: dict[str, int],
369
+ budget: _Budget,
370
+ max_files: int = 20,
371
+ ) -> list[str]:
372
+ """Read all .md files in a directory, applying the same per-file and
373
+ total caps as a single-file JSONL entry."""
374
+ full_path = os.path.join(base_path, dir_path)
375
+ if not os.path.exists(full_path) or not os.path.isdir(full_path):
376
+ return []
377
+
378
+ blocks: list[str] = []
379
+ try:
380
+ md_files = sorted(
381
+ f
382
+ for f in os.listdir(full_path)
383
+ if f.endswith(".md") and os.path.isfile(os.path.join(full_path, f))
384
+ )
385
+ for filename in md_files[:max_files]:
386
+ relative_path = os.path.join(dir_path, filename)
387
+ block = _materialize_file(base_path, relative_path, reason, limits, budget)
388
+ if block:
389
+ blocks.append(block)
390
+ except Exception:
391
+ pass
392
+
393
+ return blocks
394
+
395
+
225
396
  def read_jsonl_entries(base_path: str, jsonl_path: str) -> list[dict]:
226
- """Keep the historical probe surface while using the shared parser."""
227
- scripts_dir = Path(base_path) / DIR_WORKFLOW / "scripts"
228
- if str(scripts_dir) not in sys.path:
229
- sys.path.insert(0, str(scripts_dir))
230
- from common.context_projection import parse_context_manifest # type: ignore[import-not-found]
397
+ """
398
+ Parse all file/directory entries referenced in a jsonl context file.
399
+
400
+ Schema:
401
+ {"file": "path/to/file.md", "reason": "..."}
402
+ {"file": "path/to/dir/", "type": "directory", "reason": "..."}
403
+ {"_example": "..."} # legacy placeholder — skipped (no `file` field)
231
404
 
232
- entries, _, exists = parse_context_manifest(Path(base_path) / jsonl_path)
233
- if not exists:
405
+ Rows without a ``file`` field (e.g. the placeholder line older Trellis
406
+ versions wrote at ``task.py create`` time) are skipped silently. If the
407
+ resulting entry list is empty, a stderr warning is emitted so the operator
408
+ can debug missing context.
409
+
410
+ Returns:
411
+ [{"file": path, "type": "file" | "directory", "reason": reason}, ...]
412
+ """
413
+ full_path = os.path.join(base_path, jsonl_path)
414
+ if not os.path.exists(full_path):
234
415
  print(
235
416
  f"[inject-subagent-context] WARN: {jsonl_path} not found — "
236
- "sub-agent will receive only task artifacts",
417
+ f"sub-agent will receive only task artifacts",
237
418
  file=sys.stderr,
238
419
  )
239
- elif not entries:
420
+ return []
421
+
422
+ entries: list[dict] = []
423
+ saw_real_entry = False
424
+ try:
425
+ with open(full_path, "r", encoding="utf-8") as f:
426
+ for line in f:
427
+ line = line.strip()
428
+ if not line:
429
+ continue
430
+ try:
431
+ item = json.loads(line)
432
+ file_path = item.get("file") or item.get("path")
433
+
434
+ if not file_path:
435
+ # Seed / comment row — skip silently
436
+ continue
437
+
438
+ saw_real_entry = True
439
+ entries.append(
440
+ {
441
+ "file": file_path,
442
+ "type": item.get("type", "file"),
443
+ "reason": item.get("reason") or "-",
444
+ }
445
+ )
446
+ except json.JSONDecodeError:
447
+ continue
448
+ except Exception:
449
+ pass
450
+
451
+ if not saw_real_entry:
240
452
  print(
241
453
  f"[inject-subagent-context] WARN: {jsonl_path} has no curated "
242
- "entries (only seed / empty) — sub-agent will receive only "
243
- "task artifacts. See workflow.md planning artifact guidance.",
454
+ f"entries (only seed / empty) — sub-agent will receive only "
455
+ f"task artifacts. See workflow.md planning artifact guidance.",
244
456
  file=sys.stderr,
245
457
  )
246
- return [
247
- {"file": entry.path, "type": entry.entry_type, "reason": entry.reason}
248
- for entry in entries
249
- ]
458
+
459
+ return entries
460
+
461
+
462
+ def _materialize_jsonl_entries(
463
+ base_path: str, jsonl_path: str, limits: dict[str, int], budget: _Budget
464
+ ) -> list[str]:
465
+ """Materialize every entry in a jsonl context file into context blocks,
466
+ applying per-file and total budget caps."""
467
+ blocks: list[str] = []
468
+ for entry in read_jsonl_entries(base_path, jsonl_path):
469
+ if entry["type"] == "directory":
470
+ blocks.extend(
471
+ _materialize_directory(
472
+ base_path, entry["file"], entry["reason"], limits, budget
473
+ )
474
+ )
475
+ else:
476
+ block = _materialize_file(
477
+ base_path, entry["file"], entry["reason"], limits, budget
478
+ )
479
+ if block:
480
+ blocks.append(block)
481
+ return blocks
482
+
483
+
484
+ def get_agent_context(
485
+ repo_root: str,
486
+ task_dir: str,
487
+ agent_type: str,
488
+ limits: dict[str, int],
489
+ budget: _Budget,
490
+ ) -> str:
491
+ """
492
+ Get context from {agent_type}.jsonl for the specified agent.
493
+ Only reads implement.jsonl or check.jsonl (the two JSONL files the task system creates).
494
+ """
495
+ agent_jsonl = f"{task_dir}/{agent_type}.jsonl"
496
+ blocks = _materialize_jsonl_entries(repo_root, agent_jsonl, limits, budget)
497
+ if not blocks:
498
+ # Zero curated context reaches the model silently otherwise — the
499
+ # stderr WARN above never enters any session (#573). Put the fact in
500
+ # the prompt itself so the sub-agent compensates instead of assuming
501
+ # the spec context was complete.
502
+ return (
503
+ f"[Trellis] {agent_jsonl} has no curated entries, so no spec/research "
504
+ "context was injected. Before working, read the guidelines relevant "
505
+ "to the code you will touch under .trellis/spec/, and treat the task "
506
+ "artifacts below as the only prepared context."
507
+ )
508
+ return "\n\n".join(blocks)
509
+
510
+
511
+ def _materialize_artifact(
512
+ base_path: str,
513
+ file_path: str,
514
+ header_label: str,
515
+ reason: str,
516
+ limits: dict[str, int],
517
+ budget: _Budget,
518
+ ) -> str | None:
519
+ """Read a task artifact (prd/design/implement.md), apply the per-artifact
520
+ cap, then budget it."""
521
+ data = _read_file_bytes(base_path, file_path)
522
+ if data is None:
523
+ return None
524
+
525
+ size = len(data)
526
+ cap = limits["max_artifact_bytes"]
527
+ truncated_bytes = truncate_utf8(data, cap)
528
+ content = truncated_bytes.decode("utf-8", errors="replace")
529
+ if len(truncated_bytes) < size:
530
+ content += _truncate_notice(file_path, cap)
531
+
532
+ return _budgeted_block(budget, header_label, file_path, content, reason, size)
250
533
 
251
534
 
252
535
  def get_implement_context(repo_root: str, task_dir: str) -> str:
253
- """Complete Python context for an Implement subagent."""
254
- return _project_context(repo_root, task_dir, "implement").text
536
+ """
537
+ Complete context for Implement Agent
538
+
539
+ Read order:
540
+ 1. All files in implement.jsonl (spec/research manifests)
541
+ 2. prd.md (requirements)
542
+ 3. design.md if present (technical design)
543
+ 4. implement.md if present (execution plan)
544
+ """
545
+ limits = _get_limits(repo_root)
546
+ budget = _Budget(limits["max_total_bytes"])
547
+ context_parts = []
548
+
549
+ # 1. Read implement.jsonl
550
+ base_context = get_agent_context(repo_root, task_dir, "implement", limits, budget)
551
+ if base_context:
552
+ context_parts.append(base_context)
553
+
554
+ # 2. Requirements document
555
+ prd_block = _materialize_artifact(
556
+ repo_root,
557
+ f"{task_dir}/prd.md",
558
+ f"{task_dir}/prd.md (Requirements)",
559
+ "Requirements document",
560
+ limits,
561
+ budget,
562
+ )
563
+ if prd_block:
564
+ context_parts.append(prd_block)
565
+
566
+ # 3. Technical design for complex tasks
567
+ design_block = _materialize_artifact(
568
+ repo_root,
569
+ f"{task_dir}/design.md",
570
+ f"{task_dir}/design.md (Technical Design)",
571
+ "Technical design document",
572
+ limits,
573
+ budget,
574
+ )
575
+ if design_block:
576
+ context_parts.append(design_block)
577
+
578
+ # 4. Execution plan for complex tasks
579
+ implement_plan_block = _materialize_artifact(
580
+ repo_root,
581
+ f"{task_dir}/implement.md",
582
+ f"{task_dir}/implement.md (Execution Plan)",
583
+ "Execution plan document",
584
+ limits,
585
+ budget,
586
+ )
587
+ if implement_plan_block:
588
+ context_parts.append(implement_plan_block)
589
+
590
+ return "\n\n".join(context_parts)
255
591
 
256
592
 
257
593
  def get_check_context(repo_root: str, task_dir: str) -> str:
258
- """Complete Python context for a Check subagent."""
259
- return _project_context(repo_root, task_dir, "check").text
594
+ """
595
+ Context for Check Agent: check.jsonl + task artifacts.
596
+ """
597
+ limits = _get_limits(repo_root)
598
+ budget = _Budget(limits["max_total_bytes"])
599
+ context_parts = []
600
+
601
+ base_context = get_agent_context(repo_root, task_dir, "check", limits, budget)
602
+ if base_context:
603
+ context_parts.append(base_context)
604
+
605
+ prd_block = _materialize_artifact(
606
+ repo_root,
607
+ f"{task_dir}/prd.md",
608
+ f"{task_dir}/prd.md (Requirements)",
609
+ "Requirements document",
610
+ limits,
611
+ budget,
612
+ )
613
+ if prd_block:
614
+ context_parts.append(prd_block)
615
+
616
+ design_block = _materialize_artifact(
617
+ repo_root,
618
+ f"{task_dir}/design.md",
619
+ f"{task_dir}/design.md (Technical Design)",
620
+ "Technical design document",
621
+ limits,
622
+ budget,
623
+ )
624
+ if design_block:
625
+ context_parts.append(design_block)
626
+
627
+ implement_plan_block = _materialize_artifact(
628
+ repo_root,
629
+ f"{task_dir}/implement.md",
630
+ f"{task_dir}/implement.md (Execution Plan)",
631
+ "Execution plan document",
632
+ limits,
633
+ budget,
634
+ )
635
+ if implement_plan_block:
636
+ context_parts.append(implement_plan_block)
637
+
638
+ return "\n\n".join(context_parts)
260
639
 
261
640
 
262
641
  def get_finish_context(repo_root: str, task_dir: str) -> str:
263
- """Finish reuses the Check projection."""
642
+ """
643
+ Context for Finish phase: reuses check.jsonl + prd.md
644
+ (Finish is a final check, same context source.)
645
+ """
264
646
  return get_check_context(repo_root, task_dir)
265
647
 
266
648
 
649
+
267
650
  def build_implement_prompt(original_prompt: str, context: str) -> str:
268
651
  """Build complete prompt for Implement"""
269
652
  return f"""<!-- trellis-hook-injected -->
@@ -774,31 +1157,26 @@ def main():
774
1157
  # Check for [finish] marker in prompt (check agent with finish context)
775
1158
  is_finish_phase = "[finish]" in original_prompt.lower()
776
1159
 
777
- # Get context and build prompt based on subagent type. A project can have
778
- # an older stamped `.trellis/scripts` tree while its platform Hook is
779
- # already refreshed; preserve the Hook's fail-open spawn contract there.
780
- try:
781
- if subagent_type == AGENT_IMPLEMENT:
782
- assert task_dir is not None # validated above
783
- context = get_implement_context(repo_root, task_dir)
784
- new_prompt = build_implement_prompt(original_prompt, context)
785
- elif subagent_type == AGENT_CHECK:
786
- assert task_dir is not None # validated above
787
- if is_finish_phase:
788
- # Finish phase: use finish context (lighter, focused on final verification)
789
- context = get_finish_context(repo_root, task_dir)
790
- new_prompt = build_finish_prompt(original_prompt, context)
791
- else:
792
- # Regular check phase: use check context (full specs for self-fix loop)
793
- context = get_check_context(repo_root, task_dir)
794
- new_prompt = build_check_prompt(original_prompt, context)
795
- elif subagent_type == AGENT_RESEARCH:
796
- # Research can work without task directory
797
- context = get_research_context(repo_root, task_dir)
798
- new_prompt = build_research_prompt(original_prompt, context)
1160
+ # Get context and build prompt based on subagent type
1161
+ if subagent_type == AGENT_IMPLEMENT:
1162
+ assert task_dir is not None # validated above
1163
+ context = get_implement_context(repo_root, task_dir)
1164
+ new_prompt = build_implement_prompt(original_prompt, context)
1165
+ elif subagent_type == AGENT_CHECK:
1166
+ assert task_dir is not None # validated above
1167
+ if is_finish_phase:
1168
+ # Finish phase: use finish context (lighter, focused on final verification)
1169
+ context = get_finish_context(repo_root, task_dir)
1170
+ new_prompt = build_finish_prompt(original_prompt, context)
799
1171
  else:
800
- sys.exit(0)
801
- except Exception:
1172
+ # Regular check phase: use check context (full specs for self-fix loop)
1173
+ context = get_check_context(repo_root, task_dir)
1174
+ new_prompt = build_check_prompt(original_prompt, context)
1175
+ elif subagent_type == AGENT_RESEARCH:
1176
+ # Research can work without task directory
1177
+ context = get_research_context(repo_root, task_dir)
1178
+ new_prompt = build_research_prompt(original_prompt, context)
1179
+ else:
802
1180
  sys.exit(0)
803
1181
 
804
1182
  if not context: