@jahanxu/trellis 0.4.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 (422) hide show
  1. package/LICENSE +235 -0
  2. package/README.md +212 -0
  3. package/bin/trellis.js +3 -0
  4. package/dist/cli/index.d.ts +3 -0
  5. package/dist/cli/index.d.ts.map +1 -0
  6. package/dist/cli/index.js +97 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/commands/init.d.ts +21 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +527 -0
  11. package/dist/commands/init.js.map +1 -0
  12. package/dist/commands/update.d.ts +27 -0
  13. package/dist/commands/update.d.ts.map +1 -0
  14. package/dist/commands/update.js +1289 -0
  15. package/dist/commands/update.js.map +1 -0
  16. package/dist/configurators/antigravity.d.ts +8 -0
  17. package/dist/configurators/antigravity.d.ts.map +1 -0
  18. package/dist/configurators/antigravity.js +18 -0
  19. package/dist/configurators/antigravity.js.map +1 -0
  20. package/dist/configurators/claude.d.ts +32 -0
  21. package/dist/configurators/claude.d.ts.map +1 -0
  22. package/dist/configurators/claude.js +98 -0
  23. package/dist/configurators/claude.js.map +1 -0
  24. package/dist/configurators/codex.d.ts +8 -0
  25. package/dist/configurators/codex.d.ts.map +1 -0
  26. package/dist/configurators/codex.js +20 -0
  27. package/dist/configurators/codex.js.map +1 -0
  28. package/dist/configurators/cursor.d.ts +5 -0
  29. package/dist/configurators/cursor.d.ts.map +1 -0
  30. package/dist/configurators/cursor.js +52 -0
  31. package/dist/configurators/cursor.js.map +1 -0
  32. package/dist/configurators/gemini.d.ts +8 -0
  33. package/dist/configurators/gemini.d.ts.map +1 -0
  34. package/dist/configurators/gemini.js +52 -0
  35. package/dist/configurators/gemini.js.map +1 -0
  36. package/dist/configurators/iflow.d.ts +33 -0
  37. package/dist/configurators/iflow.d.ts.map +1 -0
  38. package/dist/configurators/iflow.js +99 -0
  39. package/dist/configurators/iflow.js.map +1 -0
  40. package/dist/configurators/index.d.ts +55 -0
  41. package/dist/configurators/index.d.ts.map +1 -0
  42. package/dist/configurators/index.js +220 -0
  43. package/dist/configurators/index.js.map +1 -0
  44. package/dist/configurators/kilo.d.ts +8 -0
  45. package/dist/configurators/kilo.d.ts.map +1 -0
  46. package/dist/configurators/kilo.js +51 -0
  47. package/dist/configurators/kilo.js.map +1 -0
  48. package/dist/configurators/kiro.d.ts +8 -0
  49. package/dist/configurators/kiro.d.ts.map +1 -0
  50. package/dist/configurators/kiro.js +20 -0
  51. package/dist/configurators/kiro.js.map +1 -0
  52. package/dist/configurators/opencode.d.ts +32 -0
  53. package/dist/configurators/opencode.d.ts.map +1 -0
  54. package/dist/configurators/opencode.js +92 -0
  55. package/dist/configurators/opencode.js.map +1 -0
  56. package/dist/configurators/shared.d.ts +12 -0
  57. package/dist/configurators/shared.d.ts.map +1 -0
  58. package/dist/configurators/shared.js +21 -0
  59. package/dist/configurators/shared.js.map +1 -0
  60. package/dist/configurators/workflow.d.ts +28 -0
  61. package/dist/configurators/workflow.d.ts.map +1 -0
  62. package/dist/configurators/workflow.js +134 -0
  63. package/dist/configurators/workflow.js.map +1 -0
  64. package/dist/constants/paths.d.ts +68 -0
  65. package/dist/constants/paths.d.ts.map +1 -0
  66. package/dist/constants/paths.js +77 -0
  67. package/dist/constants/paths.js.map +1 -0
  68. package/dist/constants/version.d.ts +9 -0
  69. package/dist/constants/version.d.ts.map +1 -0
  70. package/dist/constants/version.js +15 -0
  71. package/dist/constants/version.js.map +1 -0
  72. package/dist/index.d.ts +9 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +9 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/migrations/index.d.ts +54 -0
  77. package/dist/migrations/index.d.ts.map +1 -0
  78. package/dist/migrations/index.js +160 -0
  79. package/dist/migrations/index.js.map +1 -0
  80. package/dist/migrations/manifests/0.1.9.json +30 -0
  81. package/dist/migrations/manifests/0.2.0.json +49 -0
  82. package/dist/migrations/manifests/0.2.12.json +9 -0
  83. package/dist/migrations/manifests/0.2.13.json +9 -0
  84. package/dist/migrations/manifests/0.2.14.json +175 -0
  85. package/dist/migrations/manifests/0.2.15.json +33 -0
  86. package/dist/migrations/manifests/0.3.0-beta.0.json +278 -0
  87. package/dist/migrations/manifests/0.3.0-beta.1.json +9 -0
  88. package/dist/migrations/manifests/0.3.0-beta.10.json +9 -0
  89. package/dist/migrations/manifests/0.3.0-beta.11.json +9 -0
  90. package/dist/migrations/manifests/0.3.0-beta.12.json +9 -0
  91. package/dist/migrations/manifests/0.3.0-beta.13.json +9 -0
  92. package/dist/migrations/manifests/0.3.0-beta.14.json +9 -0
  93. package/dist/migrations/manifests/0.3.0-beta.15.json +9 -0
  94. package/dist/migrations/manifests/0.3.0-beta.16.json +9 -0
  95. package/dist/migrations/manifests/0.3.0-beta.2.json +9 -0
  96. package/dist/migrations/manifests/0.3.0-beta.3.json +9 -0
  97. package/dist/migrations/manifests/0.3.0-beta.4.json +9 -0
  98. package/dist/migrations/manifests/0.3.0-beta.5.json +9 -0
  99. package/dist/migrations/manifests/0.3.0-beta.6.json +9 -0
  100. package/dist/migrations/manifests/0.3.0-beta.7.json +11 -0
  101. package/dist/migrations/manifests/0.3.0-beta.8.json +9 -0
  102. package/dist/migrations/manifests/0.3.0-beta.9.json +9 -0
  103. package/dist/migrations/manifests/0.3.0-rc.0.json +9 -0
  104. package/dist/migrations/manifests/0.3.0-rc.1.json +9 -0
  105. package/dist/migrations/manifests/0.3.0-rc.2.json +9 -0
  106. package/dist/migrations/manifests/0.3.0-rc.3.json +9 -0
  107. package/dist/migrations/manifests/0.3.0-rc.4.json +9 -0
  108. package/dist/migrations/manifests/0.3.0-rc.5.json +9 -0
  109. package/dist/migrations/manifests/0.3.0-rc.6.json +9 -0
  110. package/dist/migrations/manifests/0.3.0.json +11 -0
  111. package/dist/templates/antigravity/index.d.ts +12 -0
  112. package/dist/templates/antigravity/index.d.ts.map +1 -0
  113. package/dist/templates/antigravity/index.js +29 -0
  114. package/dist/templates/antigravity/index.js.map +1 -0
  115. package/dist/templates/claude/agents/check.md +122 -0
  116. package/dist/templates/claude/agents/debug.md +106 -0
  117. package/dist/templates/claude/agents/dispatch.md +214 -0
  118. package/dist/templates/claude/agents/implement.md +96 -0
  119. package/dist/templates/claude/agents/plan.md +396 -0
  120. package/dist/templates/claude/agents/research.md +120 -0
  121. package/dist/templates/claude/commands/trellis/before-backend-dev.md +13 -0
  122. package/dist/templates/claude/commands/trellis/before-frontend-dev.md +13 -0
  123. package/dist/templates/claude/commands/trellis/before-role-work.md +364 -0
  124. package/dist/templates/claude/commands/trellis/brainstorm.md +474 -0
  125. package/dist/templates/claude/commands/trellis/break-loop.md +125 -0
  126. package/dist/templates/claude/commands/trellis/check-backend.md +13 -0
  127. package/dist/templates/claude/commands/trellis/check-cross-layer.md +153 -0
  128. package/dist/templates/claude/commands/trellis/check-frontend.md +13 -0
  129. package/dist/templates/claude/commands/trellis/create-command.md +154 -0
  130. package/dist/templates/claude/commands/trellis/finish-work.md +153 -0
  131. package/dist/templates/claude/commands/trellis/handoff.md +445 -0
  132. package/dist/templates/claude/commands/trellis/integrate-skill.md +219 -0
  133. package/dist/templates/claude/commands/trellis/onboard.md +358 -0
  134. package/dist/templates/claude/commands/trellis/parallel.md +193 -0
  135. package/dist/templates/claude/commands/trellis/pick-task.md +515 -0
  136. package/dist/templates/claude/commands/trellis/record-session.md +62 -0
  137. package/dist/templates/claude/commands/trellis/start.md +373 -0
  138. package/dist/templates/claude/commands/trellis/update-spec.md +354 -0
  139. package/dist/templates/claude/hooks/inject-subagent-context.py +873 -0
  140. package/dist/templates/claude/hooks/ralph-loop.py +388 -0
  141. package/dist/templates/claude/hooks/session-start.py +200 -0
  142. package/dist/templates/claude/index.d.ts +54 -0
  143. package/dist/templates/claude/index.d.ts.map +1 -0
  144. package/dist/templates/claude/index.js +85 -0
  145. package/dist/templates/claude/index.js.map +1 -0
  146. package/dist/templates/claude/settings.json +41 -0
  147. package/dist/templates/codex/index.d.ts +18 -0
  148. package/dist/templates/codex/index.d.ts.map +1 -0
  149. package/dist/templates/codex/index.js +40 -0
  150. package/dist/templates/codex/index.js.map +1 -0
  151. package/dist/templates/codex/skills/before-backend-dev/SKILL.md +18 -0
  152. package/dist/templates/codex/skills/before-frontend-dev/SKILL.md +18 -0
  153. package/dist/templates/codex/skills/brainstorm/SKILL.md +479 -0
  154. package/dist/templates/codex/skills/break-loop/SKILL.md +130 -0
  155. package/dist/templates/codex/skills/check-backend/SKILL.md +18 -0
  156. package/dist/templates/codex/skills/check-cross-layer/SKILL.md +158 -0
  157. package/dist/templates/codex/skills/check-frontend/SKILL.md +18 -0
  158. package/dist/templates/codex/skills/create-command/SKILL.md +101 -0
  159. package/dist/templates/codex/skills/finish-work/SKILL.md +148 -0
  160. package/dist/templates/codex/skills/integrate-skill/SKILL.md +221 -0
  161. package/dist/templates/codex/skills/onboard/SKILL.md +363 -0
  162. package/dist/templates/codex/skills/record-session/SKILL.md +67 -0
  163. package/dist/templates/codex/skills/start/SKILL.md +330 -0
  164. package/dist/templates/codex/skills/update-spec/SKILL.md +335 -0
  165. package/dist/templates/cursor/commands/trellis-before-backend-dev.md +13 -0
  166. package/dist/templates/cursor/commands/trellis-before-frontend-dev.md +13 -0
  167. package/dist/templates/cursor/commands/trellis-brainstorm.md +474 -0
  168. package/dist/templates/cursor/commands/trellis-break-loop.md +107 -0
  169. package/dist/templates/cursor/commands/trellis-check-backend.md +13 -0
  170. package/dist/templates/cursor/commands/trellis-check-cross-layer.md +153 -0
  171. package/dist/templates/cursor/commands/trellis-check-frontend.md +13 -0
  172. package/dist/templates/cursor/commands/trellis-create-command.md +154 -0
  173. package/dist/templates/cursor/commands/trellis-finish-work.md +143 -0
  174. package/dist/templates/cursor/commands/trellis-integrate-skill.md +219 -0
  175. package/dist/templates/cursor/commands/trellis-onboard.md +358 -0
  176. package/dist/templates/cursor/commands/trellis-record-session.md +62 -0
  177. package/dist/templates/cursor/commands/trellis-start.md +366 -0
  178. package/dist/templates/cursor/commands/trellis-update-spec.md +354 -0
  179. package/dist/templates/cursor/index.d.ts +24 -0
  180. package/dist/templates/cursor/index.d.ts.map +1 -0
  181. package/dist/templates/cursor/index.js +44 -0
  182. package/dist/templates/cursor/index.js.map +1 -0
  183. package/dist/templates/extract.d.ts +166 -0
  184. package/dist/templates/extract.d.ts.map +1 -0
  185. package/dist/templates/extract.js +296 -0
  186. package/dist/templates/extract.js.map +1 -0
  187. package/dist/templates/gemini/commands/trellis/before-backend-dev.toml +17 -0
  188. package/dist/templates/gemini/commands/trellis/before-frontend-dev.toml +17 -0
  189. package/dist/templates/gemini/commands/trellis/brainstorm.toml +420 -0
  190. package/dist/templates/gemini/commands/trellis/break-loop.toml +129 -0
  191. package/dist/templates/gemini/commands/trellis/check-backend.toml +17 -0
  192. package/dist/templates/gemini/commands/trellis/check-cross-layer.toml +147 -0
  193. package/dist/templates/gemini/commands/trellis/check-frontend.toml +17 -0
  194. package/dist/templates/gemini/commands/trellis/create-command.toml +119 -0
  195. package/dist/templates/gemini/commands/trellis/finish-work.toml +133 -0
  196. package/dist/templates/gemini/commands/trellis/integrate-skill.toml +104 -0
  197. package/dist/templates/gemini/commands/trellis/onboard.toml +111 -0
  198. package/dist/templates/gemini/commands/trellis/record-session.toml +66 -0
  199. package/dist/templates/gemini/commands/trellis/start.toml +292 -0
  200. package/dist/templates/gemini/commands/trellis/update-spec.toml +132 -0
  201. package/dist/templates/gemini/index.d.ts +21 -0
  202. package/dist/templates/gemini/index.d.ts.map +1 -0
  203. package/dist/templates/gemini/index.js +44 -0
  204. package/dist/templates/gemini/index.js.map +1 -0
  205. package/dist/templates/iflow/agents/check.md +122 -0
  206. package/dist/templates/iflow/agents/debug.md +106 -0
  207. package/dist/templates/iflow/agents/dispatch.md +214 -0
  208. package/dist/templates/iflow/agents/implement.md +96 -0
  209. package/dist/templates/iflow/agents/plan.md +396 -0
  210. package/dist/templates/iflow/agents/research.md +120 -0
  211. package/dist/templates/iflow/commands/trellis/before-backend-dev.md +13 -0
  212. package/dist/templates/iflow/commands/trellis/before-frontend-dev.md +13 -0
  213. package/dist/templates/iflow/commands/trellis/brainstorm.md +474 -0
  214. package/dist/templates/iflow/commands/trellis/break-loop.md +125 -0
  215. package/dist/templates/iflow/commands/trellis/check-backend.md +13 -0
  216. package/dist/templates/iflow/commands/trellis/check-cross-layer.md +153 -0
  217. package/dist/templates/iflow/commands/trellis/check-frontend.md +13 -0
  218. package/dist/templates/iflow/commands/trellis/create-command.md +152 -0
  219. package/dist/templates/iflow/commands/trellis/finish-work.md +153 -0
  220. package/dist/templates/iflow/commands/trellis/integrate-skill.md +219 -0
  221. package/dist/templates/iflow/commands/trellis/onboard.md +358 -0
  222. package/dist/templates/iflow/commands/trellis/parallel.md +193 -0
  223. package/dist/templates/iflow/commands/trellis/record-session.md +62 -0
  224. package/dist/templates/iflow/commands/trellis/start.md +373 -0
  225. package/dist/templates/iflow/commands/trellis/update-spec.md +354 -0
  226. package/dist/templates/iflow/hooks/inject-subagent-context.py +788 -0
  227. package/dist/templates/iflow/hooks/ralph-loop.py +388 -0
  228. package/dist/templates/iflow/hooks/session-start.py +143 -0
  229. package/dist/templates/iflow/index.d.ts +54 -0
  230. package/dist/templates/iflow/index.d.ts.map +1 -0
  231. package/dist/templates/iflow/index.js +85 -0
  232. package/dist/templates/iflow/index.js.map +1 -0
  233. package/dist/templates/iflow/settings.json +40 -0
  234. package/dist/templates/kilo/commands/trellis/before-backend-dev.md +13 -0
  235. package/dist/templates/kilo/commands/trellis/before-frontend-dev.md +13 -0
  236. package/dist/templates/kilo/commands/trellis/brainstorm.md +474 -0
  237. package/dist/templates/kilo/commands/trellis/break-loop.md +125 -0
  238. package/dist/templates/kilo/commands/trellis/check-backend.md +13 -0
  239. package/dist/templates/kilo/commands/trellis/check-cross-layer.md +153 -0
  240. package/dist/templates/kilo/commands/trellis/check-frontend.md +13 -0
  241. package/dist/templates/kilo/commands/trellis/create-command.md +152 -0
  242. package/dist/templates/kilo/commands/trellis/finish-work.md +129 -0
  243. package/dist/templates/kilo/commands/trellis/integrate-skill.md +219 -0
  244. package/dist/templates/kilo/commands/trellis/onboard.md +358 -0
  245. package/dist/templates/kilo/commands/trellis/parallel.md +194 -0
  246. package/dist/templates/kilo/commands/trellis/record-session.md +62 -0
  247. package/dist/templates/kilo/commands/trellis/start.md +321 -0
  248. package/dist/templates/kilo/commands/trellis/update-spec.md +285 -0
  249. package/dist/templates/kilo/index.d.ts +16 -0
  250. package/dist/templates/kilo/index.d.ts.map +1 -0
  251. package/dist/templates/kilo/index.js +39 -0
  252. package/dist/templates/kilo/index.js.map +1 -0
  253. package/dist/templates/kiro/index.d.ts +18 -0
  254. package/dist/templates/kiro/index.d.ts.map +1 -0
  255. package/dist/templates/kiro/index.js +40 -0
  256. package/dist/templates/kiro/index.js.map +1 -0
  257. package/dist/templates/kiro/skills/before-backend-dev/SKILL.md +18 -0
  258. package/dist/templates/kiro/skills/before-frontend-dev/SKILL.md +18 -0
  259. package/dist/templates/kiro/skills/brainstorm/SKILL.md +479 -0
  260. package/dist/templates/kiro/skills/break-loop/SKILL.md +130 -0
  261. package/dist/templates/kiro/skills/check-backend/SKILL.md +18 -0
  262. package/dist/templates/kiro/skills/check-cross-layer/SKILL.md +158 -0
  263. package/dist/templates/kiro/skills/check-frontend/SKILL.md +18 -0
  264. package/dist/templates/kiro/skills/create-command/SKILL.md +101 -0
  265. package/dist/templates/kiro/skills/finish-work/SKILL.md +148 -0
  266. package/dist/templates/kiro/skills/integrate-skill/SKILL.md +221 -0
  267. package/dist/templates/kiro/skills/onboard/SKILL.md +363 -0
  268. package/dist/templates/kiro/skills/record-session/SKILL.md +67 -0
  269. package/dist/templates/kiro/skills/start/SKILL.md +330 -0
  270. package/dist/templates/kiro/skills/update-spec/SKILL.md +335 -0
  271. package/dist/templates/markdown/agents.md +18 -0
  272. package/dist/templates/markdown/gitignore.txt +12 -0
  273. package/dist/templates/markdown/index.d.ts +27 -0
  274. package/dist/templates/markdown/index.d.ts.map +1 -0
  275. package/dist/templates/markdown/index.js +52 -0
  276. package/dist/templates/markdown/index.js.map +1 -0
  277. package/dist/templates/markdown/spec/backend/database-guidelines.md.txt +51 -0
  278. package/dist/templates/markdown/spec/backend/directory-structure.md.txt +54 -0
  279. package/dist/templates/markdown/spec/backend/error-handling.md.txt +51 -0
  280. package/dist/templates/markdown/spec/backend/index.md +40 -0
  281. package/dist/templates/markdown/spec/backend/index.md.txt +38 -0
  282. package/dist/templates/markdown/spec/backend/logging-guidelines.md.txt +51 -0
  283. package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +51 -0
  284. package/dist/templates/markdown/spec/backend/script-conventions.md +467 -0
  285. package/dist/templates/markdown/spec/frontend/component-guidelines.md.txt +59 -0
  286. package/dist/templates/markdown/spec/frontend/directory-structure.md.txt +54 -0
  287. package/dist/templates/markdown/spec/frontend/hook-guidelines.md.txt +51 -0
  288. package/dist/templates/markdown/spec/frontend/index.md.txt +39 -0
  289. package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +51 -0
  290. package/dist/templates/markdown/spec/frontend/state-management.md.txt +51 -0
  291. package/dist/templates/markdown/spec/frontend/type-safety.md.txt +51 -0
  292. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md +118 -0
  293. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +92 -0
  294. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +94 -0
  295. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md +394 -0
  296. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +319 -0
  297. package/dist/templates/markdown/spec/guides/index.md.txt +79 -0
  298. package/dist/templates/markdown/workspace-index.md +123 -0
  299. package/dist/templates/markdown/worktree.yaml.txt +58 -0
  300. package/dist/templates/opencode/agents/check.md +146 -0
  301. package/dist/templates/opencode/agents/debug.md +129 -0
  302. package/dist/templates/opencode/agents/dispatch.md +223 -0
  303. package/dist/templates/opencode/agents/implement.md +120 -0
  304. package/dist/templates/opencode/agents/research.md +147 -0
  305. package/dist/templates/opencode/agents/trellis-plan.md +427 -0
  306. package/dist/templates/opencode/commands/trellis/before-backend-dev.md +13 -0
  307. package/dist/templates/opencode/commands/trellis/before-frontend-dev.md +13 -0
  308. package/dist/templates/opencode/commands/trellis/brainstorm.md +474 -0
  309. package/dist/templates/opencode/commands/trellis/break-loop.md +125 -0
  310. package/dist/templates/opencode/commands/trellis/check-backend.md +13 -0
  311. package/dist/templates/opencode/commands/trellis/check-cross-layer.md +153 -0
  312. package/dist/templates/opencode/commands/trellis/check-frontend.md +13 -0
  313. package/dist/templates/opencode/commands/trellis/create-command.md +154 -0
  314. package/dist/templates/opencode/commands/trellis/finish-work.md +144 -0
  315. package/dist/templates/opencode/commands/trellis/integrate-skill.md +219 -0
  316. package/dist/templates/opencode/commands/trellis/migrate-specs.md +0 -0
  317. package/dist/templates/opencode/commands/trellis/onboard.md +358 -0
  318. package/dist/templates/opencode/commands/trellis/parallel.md +194 -0
  319. package/dist/templates/opencode/commands/trellis/record-session.md +62 -0
  320. package/dist/templates/opencode/commands/trellis/start.md +338 -0
  321. package/dist/templates/opencode/commands/trellis/update-spec.md +354 -0
  322. package/dist/templates/opencode/lib/trellis-context.js +436 -0
  323. package/dist/templates/opencode/package.json +5 -0
  324. package/dist/templates/opencode/plugin/inject-subagent-context.js +538 -0
  325. package/dist/templates/opencode/plugin/session-start.js +192 -0
  326. package/dist/templates/trellis/VERSION +1 -0
  327. package/dist/templates/trellis/deliverables/README.md +51 -0
  328. package/dist/templates/trellis/gitignore.txt +29 -0
  329. package/dist/templates/trellis/index.d.ts +49 -0
  330. package/dist/templates/trellis/index.d.ts.map +1 -0
  331. package/dist/templates/trellis/index.js +92 -0
  332. package/dist/templates/trellis/index.js.map +1 -0
  333. package/dist/templates/trellis/paths.README.md +277 -0
  334. package/dist/templates/trellis/paths.yaml +41 -0
  335. package/dist/templates/trellis/pool/implementations.json +5 -0
  336. package/dist/templates/trellis/pool/prototypes.json +5 -0
  337. package/dist/templates/trellis/pool/requirements.json +5 -0
  338. package/dist/templates/trellis/scripts/__init__.py +5 -0
  339. package/dist/templates/trellis/scripts/add_session.py +391 -0
  340. package/dist/templates/trellis/scripts/common/__init__.py +80 -0
  341. package/dist/templates/trellis/scripts/common/cli_adapter.py +522 -0
  342. package/dist/templates/trellis/scripts/common/developer.py +189 -0
  343. package/dist/templates/trellis/scripts/common/git_context.py +383 -0
  344. package/dist/templates/trellis/scripts/common/paths.py +346 -0
  345. package/dist/templates/trellis/scripts/common/phase.py +253 -0
  346. package/dist/templates/trellis/scripts/common/project_paths.py +189 -0
  347. package/dist/templates/trellis/scripts/common/registry.py +365 -0
  348. package/dist/templates/trellis/scripts/common/task_queue.py +255 -0
  349. package/dist/templates/trellis/scripts/common/task_utils.py +177 -0
  350. package/dist/templates/trellis/scripts/common/worktree.py +218 -0
  351. package/dist/templates/trellis/scripts/create_bootstrap.py +290 -0
  352. package/dist/templates/trellis/scripts/get_context.py +16 -0
  353. package/dist/templates/trellis/scripts/get_developer.py +26 -0
  354. package/dist/templates/trellis/scripts/handoff_generator.py +380 -0
  355. package/dist/templates/trellis/scripts/init_developer.py +51 -0
  356. package/dist/templates/trellis/scripts/multi_agent/__init__.py +5 -0
  357. package/dist/templates/trellis/scripts/multi_agent/cleanup.py +403 -0
  358. package/dist/templates/trellis/scripts/multi_agent/create_pr.py +329 -0
  359. package/dist/templates/trellis/scripts/multi_agent/plan.py +233 -0
  360. package/dist/templates/trellis/scripts/multi_agent/start.py +461 -0
  361. package/dist/templates/trellis/scripts/multi_agent/status.py +817 -0
  362. package/dist/templates/trellis/scripts/pool.py +373 -0
  363. package/dist/templates/trellis/scripts/task.py +1162 -0
  364. package/dist/templates/trellis/scripts-shell-archive/add-session.sh +384 -0
  365. package/dist/templates/trellis/scripts-shell-archive/common/developer.sh +129 -0
  366. package/dist/templates/trellis/scripts-shell-archive/common/git-context.sh +263 -0
  367. package/dist/templates/trellis/scripts-shell-archive/common/paths.sh +208 -0
  368. package/dist/templates/trellis/scripts-shell-archive/common/phase.sh +150 -0
  369. package/dist/templates/trellis/scripts-shell-archive/common/registry.sh +247 -0
  370. package/dist/templates/trellis/scripts-shell-archive/common/task-queue.sh +142 -0
  371. package/dist/templates/trellis/scripts-shell-archive/common/task-utils.sh +151 -0
  372. package/dist/templates/trellis/scripts-shell-archive/common/worktree.sh +128 -0
  373. package/dist/templates/trellis/scripts-shell-archive/create-bootstrap.sh +299 -0
  374. package/dist/templates/trellis/scripts-shell-archive/get-context.sh +7 -0
  375. package/dist/templates/trellis/scripts-shell-archive/get-developer.sh +15 -0
  376. package/dist/templates/trellis/scripts-shell-archive/init-developer.sh +34 -0
  377. package/dist/templates/trellis/scripts-shell-archive/multi-agent/cleanup.sh +396 -0
  378. package/dist/templates/trellis/scripts-shell-archive/multi-agent/create-pr.sh +241 -0
  379. package/dist/templates/trellis/scripts-shell-archive/multi-agent/plan.sh +207 -0
  380. package/dist/templates/trellis/scripts-shell-archive/multi-agent/start.sh +317 -0
  381. package/dist/templates/trellis/scripts-shell-archive/multi-agent/status.sh +828 -0
  382. package/dist/templates/trellis/scripts-shell-archive/task.sh +1204 -0
  383. package/dist/templates/trellis/spec/roles/designer/index.md +243 -0
  384. package/dist/templates/trellis/spec/roles/designer/mock-data-standards.md +481 -0
  385. package/dist/templates/trellis/spec/roles/designer/prototype-guidelines.md +429 -0
  386. package/dist/templates/trellis/spec/roles/frontend-impl/api-integration.md +565 -0
  387. package/dist/templates/trellis/spec/roles/frontend-impl/index.md +321 -0
  388. package/dist/templates/trellis/spec/roles/frontend-impl/state-management.md +599 -0
  389. package/dist/templates/trellis/spec/roles/pm/index.md +112 -0
  390. package/dist/templates/trellis/spec/roles/pm/prd-template.md +124 -0
  391. package/dist/templates/trellis/tasks/.gitkeep +0 -0
  392. package/dist/templates/trellis/workflow.md +416 -0
  393. package/dist/templates/trellis/worktree.yaml +47 -0
  394. package/dist/types/ai-tools.d.ts +56 -0
  395. package/dist/types/ai-tools.d.ts.map +1 -0
  396. package/dist/types/ai-tools.js +103 -0
  397. package/dist/types/ai-tools.js.map +1 -0
  398. package/dist/types/migration.d.ts +86 -0
  399. package/dist/types/migration.d.ts.map +1 -0
  400. package/dist/types/migration.js +8 -0
  401. package/dist/types/migration.js.map +1 -0
  402. package/dist/utils/compare-versions.d.ts +12 -0
  403. package/dist/utils/compare-versions.d.ts.map +1 -0
  404. package/dist/utils/compare-versions.js +76 -0
  405. package/dist/utils/compare-versions.js.map +1 -0
  406. package/dist/utils/file-writer.d.ts +23 -0
  407. package/dist/utils/file-writer.d.ts.map +1 -0
  408. package/dist/utils/file-writer.js +140 -0
  409. package/dist/utils/file-writer.js.map +1 -0
  410. package/dist/utils/project-detector.d.ts +16 -0
  411. package/dist/utils/project-detector.d.ts.map +1 -0
  412. package/dist/utils/project-detector.js +186 -0
  413. package/dist/utils/project-detector.js.map +1 -0
  414. package/dist/utils/template-fetcher.d.ts +51 -0
  415. package/dist/utils/template-fetcher.d.ts.map +1 -0
  416. package/dist/utils/template-fetcher.js +174 -0
  417. package/dist/utils/template-fetcher.js.map +1 -0
  418. package/dist/utils/template-hash.d.ts +78 -0
  419. package/dist/utils/template-hash.d.ts.map +1 -0
  420. package/dist/utils/template-hash.js +233 -0
  421. package/dist/utils/template-hash.js.map +1 -0
  422. package/package.json +87 -0
@@ -0,0 +1,255 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Task queue utility functions.
4
+
5
+ Provides:
6
+ list_tasks_by_status - List tasks by status
7
+ list_pending_tasks - List tasks with pending status
8
+ list_tasks_by_assignee - List tasks by assignee
9
+ list_my_tasks - List tasks assigned to current developer
10
+ get_task_stats - Get P0/P1/P2/P3 counts
11
+ """
12
+
13
+
14
+ import json
15
+ from pathlib import Path
16
+ from typing import Optional, List
17
+
18
+ from .paths import (
19
+ FILE_TASK_JSON,
20
+ get_repo_root,
21
+ get_developer,
22
+ get_tasks_dir,
23
+ )
24
+
25
+
26
+ def _read_json_file(path: Path) -> Optional[dict]:
27
+ """Read and parse a JSON file."""
28
+ try:
29
+ return json.loads(path.read_text(encoding="utf-8"))
30
+ except (FileNotFoundError, json.JSONDecodeError, OSError):
31
+ return None
32
+
33
+
34
+ # =============================================================================
35
+ # Public Functions
36
+ # =============================================================================
37
+
38
+ def list_tasks_by_status(
39
+ filter_status: Optional[str] = None,
40
+ repo_root: Optional[Path] = None
41
+ ) -> list[dict]:
42
+ """List tasks by status.
43
+
44
+ Args:
45
+ filter_status: Optional status filter.
46
+ repo_root: Repository root path. Defaults to auto-detected.
47
+
48
+ Returns:
49
+ List of task info dicts with keys: priority, id, title, status, assignee.
50
+ """
51
+ if repo_root is None:
52
+ repo_root = get_repo_root()
53
+
54
+ tasks_dir = get_tasks_dir(repo_root)
55
+ results = []
56
+
57
+ if not tasks_dir.is_dir():
58
+ return results
59
+
60
+ for d in tasks_dir.iterdir():
61
+ if not d.is_dir() or d.name == "archive":
62
+ continue
63
+
64
+ task_json = d / FILE_TASK_JSON
65
+ if not task_json.is_file():
66
+ continue
67
+
68
+ data = _read_json_file(task_json)
69
+ if not data:
70
+ continue
71
+
72
+ task_id = data.get("id", "")
73
+ title = data.get("title") or data.get("name", "")
74
+ priority = data.get("priority", "P2")
75
+ status = data.get("status", "planning")
76
+ assignee = data.get("assignee", "-")
77
+
78
+ # Apply filter
79
+ if filter_status and status != filter_status:
80
+ continue
81
+
82
+ results.append({
83
+ "priority": priority,
84
+ "id": task_id,
85
+ "title": title,
86
+ "status": status,
87
+ "assignee": assignee,
88
+ "dir": d.name,
89
+ })
90
+
91
+ return results
92
+
93
+
94
+ def list_pending_tasks(repo_root: Optional[Path] = None) -> list[dict]:
95
+ """List pending tasks.
96
+
97
+ Args:
98
+ repo_root: Repository root path. Defaults to auto-detected.
99
+
100
+ Returns:
101
+ List of task info dicts.
102
+ """
103
+ return list_tasks_by_status("planning", repo_root)
104
+
105
+
106
+ def list_tasks_by_assignee(
107
+ assignee: str,
108
+ filter_status: Optional[str] = None,
109
+ repo_root: Optional[Path] = None
110
+ ) -> list[dict]:
111
+ """List tasks assigned to a specific developer.
112
+
113
+ Args:
114
+ assignee: Developer name.
115
+ filter_status: Optional status filter.
116
+ repo_root: Repository root path. Defaults to auto-detected.
117
+
118
+ Returns:
119
+ List of task info dicts.
120
+ """
121
+ if repo_root is None:
122
+ repo_root = get_repo_root()
123
+
124
+ tasks_dir = get_tasks_dir(repo_root)
125
+ results = []
126
+
127
+ if not tasks_dir.is_dir():
128
+ return results
129
+
130
+ for d in tasks_dir.iterdir():
131
+ if not d.is_dir() or d.name == "archive":
132
+ continue
133
+
134
+ task_json = d / FILE_TASK_JSON
135
+ if not task_json.is_file():
136
+ continue
137
+
138
+ data = _read_json_file(task_json)
139
+ if not data:
140
+ continue
141
+
142
+ task_assignee = data.get("assignee", "-")
143
+
144
+ # Apply assignee filter
145
+ if task_assignee != assignee:
146
+ continue
147
+
148
+ task_id = data.get("id", "")
149
+ title = data.get("title") or data.get("name", "")
150
+ priority = data.get("priority", "P2")
151
+ status = data.get("status", "planning")
152
+
153
+ # Apply status filter
154
+ if filter_status and status != filter_status:
155
+ continue
156
+
157
+ results.append({
158
+ "priority": priority,
159
+ "id": task_id,
160
+ "title": title,
161
+ "status": status,
162
+ "assignee": task_assignee,
163
+ "dir": d.name,
164
+ })
165
+
166
+ return results
167
+
168
+
169
+ def list_my_tasks(
170
+ filter_status: Optional[str] = None,
171
+ repo_root: Optional[Path] = None
172
+ ) -> list[dict]:
173
+ """List tasks assigned to current developer.
174
+
175
+ Args:
176
+ filter_status: Optional status filter.
177
+ repo_root: Repository root path. Defaults to auto-detected.
178
+
179
+ Returns:
180
+ List of task info dicts.
181
+
182
+ Raises:
183
+ ValueError: If developer not set.
184
+ """
185
+ if repo_root is None:
186
+ repo_root = get_repo_root()
187
+
188
+ developer = get_developer(repo_root)
189
+ if not developer:
190
+ raise ValueError("Developer not set")
191
+
192
+ return list_tasks_by_assignee(developer, filter_status, repo_root)
193
+
194
+
195
+ def get_task_stats(repo_root: Optional[Path] = None) -> dict[str, int]:
196
+ """Get task statistics.
197
+
198
+ Args:
199
+ repo_root: Repository root path. Defaults to auto-detected.
200
+
201
+ Returns:
202
+ Dict with keys: P0, P1, P2, P3, Total.
203
+ """
204
+ if repo_root is None:
205
+ repo_root = get_repo_root()
206
+
207
+ tasks_dir = get_tasks_dir(repo_root)
208
+ stats = {"P0": 0, "P1": 0, "P2": 0, "P3": 0, "Total": 0}
209
+
210
+ if not tasks_dir.is_dir():
211
+ return stats
212
+
213
+ for d in tasks_dir.iterdir():
214
+ if not d.is_dir() or d.name == "archive":
215
+ continue
216
+
217
+ task_json = d / FILE_TASK_JSON
218
+ if not task_json.is_file():
219
+ continue
220
+
221
+ data = _read_json_file(task_json)
222
+ if not data:
223
+ continue
224
+
225
+ priority = data.get("priority", "P2")
226
+ if priority in stats:
227
+ stats[priority] += 1
228
+ stats["Total"] += 1
229
+
230
+ return stats
231
+
232
+
233
+ def format_task_stats(stats: dict[str, int]) -> str:
234
+ """Format task stats as string.
235
+
236
+ Args:
237
+ stats: Stats dict from get_task_stats.
238
+
239
+ Returns:
240
+ Formatted string like "P0:0 P1:1 P2:2 P3:0 Total:3".
241
+ """
242
+ return f"P0:{stats['P0']} P1:{stats['P1']} P2:{stats['P2']} P3:{stats['P3']} Total:{stats['Total']}"
243
+
244
+
245
+ # =============================================================================
246
+ # Main Entry (for testing)
247
+ # =============================================================================
248
+
249
+ if __name__ == "__main__":
250
+ stats = get_task_stats()
251
+ print(format_task_stats(stats))
252
+ print()
253
+ print("Pending tasks:")
254
+ for task in list_pending_tasks():
255
+ print(f" {task['priority']}|{task['id']}|{task['title']}|{task['status']}|{task['assignee']}")
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Task utility functions.
4
+
5
+ Provides:
6
+ is_safe_task_path - Validate task path is safe to operate on
7
+ find_task_by_name - Find task directory by name
8
+ archive_task_dir - Archive task to monthly directory
9
+ """
10
+
11
+
12
+ import shutil
13
+ import sys
14
+ from datetime import datetime
15
+ from pathlib import Path
16
+
17
+ from .paths import get_repo_root
18
+
19
+
20
+ # =============================================================================
21
+ # Path Safety
22
+ # =============================================================================
23
+
24
+ def is_safe_task_path(task_path: str, repo_root: Optional[Path] = None) -> bool:
25
+ """Check if a relative task path is safe to operate on.
26
+
27
+ Args:
28
+ task_path: Task path (relative to repo_root).
29
+ repo_root: Repository root path. Defaults to auto-detected.
30
+
31
+ Returns:
32
+ True if safe, False if dangerous.
33
+ """
34
+ if repo_root is None:
35
+ repo_root = get_repo_root()
36
+
37
+ # Check empty or null
38
+ if not task_path or task_path == "null":
39
+ print("Error: empty or null task path", file=sys.stderr)
40
+ return False
41
+
42
+ # Reject absolute paths
43
+ if task_path.startswith("/"):
44
+ print(f"Error: absolute path not allowed: {task_path}", file=sys.stderr)
45
+ return False
46
+
47
+ # Reject ".", "..", paths starting with "./" or "../", or containing ".."
48
+ if task_path in (".", "..") or task_path.startswith("./") or task_path.startswith("../") or ".." in task_path:
49
+ print(f"Error: path traversal not allowed: {task_path}", file=sys.stderr)
50
+ return False
51
+
52
+ # Final check: ensure resolved path is not the repo root
53
+ abs_path = repo_root / task_path
54
+ if abs_path.exists():
55
+ try:
56
+ resolved = abs_path.resolve()
57
+ root_resolved = repo_root.resolve()
58
+ if resolved == root_resolved:
59
+ print(f"Error: path resolves to repo root: {task_path}", file=sys.stderr)
60
+ return False
61
+ except (OSError, IOError):
62
+ pass
63
+
64
+ return True
65
+
66
+
67
+ # =============================================================================
68
+ # Task Lookup
69
+ # =============================================================================
70
+
71
+ def find_task_by_name(task_name: str, tasks_dir: Path) -> Optional[Path]:
72
+ """Find task directory by name (exact or suffix match).
73
+
74
+ Args:
75
+ task_name: Task name to find.
76
+ tasks_dir: Tasks directory path.
77
+
78
+ Returns:
79
+ Absolute path to task directory, or None if not found.
80
+ """
81
+ if not task_name or not tasks_dir or not tasks_dir.is_dir():
82
+ return None
83
+
84
+ # Try exact match first
85
+ exact_match = tasks_dir / task_name
86
+ if exact_match.is_dir():
87
+ return exact_match
88
+
89
+ # Try suffix match (e.g., "my-task" matches "01-21-my-task")
90
+ for d in tasks_dir.iterdir():
91
+ if d.is_dir() and d.name.endswith(f"-{task_name}"):
92
+ return d
93
+
94
+ return None
95
+
96
+
97
+ # =============================================================================
98
+ # Archive Operations
99
+ # =============================================================================
100
+
101
+ def archive_task_dir(task_dir_abs: Path, repo_root: Optional[Path] = None) -> Optional[Path]:
102
+ """Archive a task directory to archive/{YYYY-MM}/.
103
+
104
+ Args:
105
+ task_dir_abs: Absolute path to task directory.
106
+ repo_root: Repository root path. Defaults to auto-detected.
107
+
108
+ Returns:
109
+ Path to archived directory, or None on error.
110
+ """
111
+ if not task_dir_abs.is_dir():
112
+ print(f"Error: task directory not found: {task_dir_abs}", file=sys.stderr)
113
+ return None
114
+
115
+ # Get tasks directory (parent of the task)
116
+ tasks_dir = task_dir_abs.parent
117
+ archive_dir = tasks_dir / "archive"
118
+ year_month = datetime.now().strftime("%Y-%m")
119
+ month_dir = archive_dir / year_month
120
+
121
+ # Create archive directory
122
+ try:
123
+ month_dir.mkdir(parents=True, exist_ok=True)
124
+ except (OSError, IOError) as e:
125
+ print(f"Error: Failed to create archive directory: {e}", file=sys.stderr)
126
+ return None
127
+
128
+ # Move task to archive
129
+ task_name = task_dir_abs.name
130
+ dest = month_dir / task_name
131
+
132
+ try:
133
+ shutil.move(str(task_dir_abs), str(dest))
134
+ except (OSError, IOError, shutil.Error) as e:
135
+ print(f"Error: Failed to move task to archive: {e}", file=sys.stderr)
136
+ return None
137
+
138
+ return dest
139
+
140
+
141
+ def archive_task_complete(
142
+ task_dir_abs: Path,
143
+ repo_root: Optional[Path] = None
144
+ ) -> dict[str, str]:
145
+ """Complete archive workflow: archive directory.
146
+
147
+ Args:
148
+ task_dir_abs: Absolute path to task directory.
149
+ repo_root: Repository root path. Defaults to auto-detected.
150
+
151
+ Returns:
152
+ Dict with archive result info.
153
+ """
154
+ if not task_dir_abs.is_dir():
155
+ print(f"Error: task directory not found: {task_dir_abs}", file=sys.stderr)
156
+ return {}
157
+
158
+ archive_dest = archive_task_dir(task_dir_abs, repo_root)
159
+ if archive_dest:
160
+ return {"archived_to": str(archive_dest)}
161
+
162
+ return {}
163
+
164
+
165
+ # =============================================================================
166
+ # Main Entry (for testing)
167
+ # =============================================================================
168
+
169
+ if __name__ == "__main__":
170
+ from .paths import get_tasks_dir
171
+
172
+ repo = get_repo_root()
173
+ tasks = get_tasks_dir(repo)
174
+
175
+ print(f"Tasks dir: {tasks}")
176
+ print(f"is_safe_task_path('.trellis/tasks/test'): {is_safe_task_path('.trellis/tasks/test', repo)}")
177
+ print(f"is_safe_task_path('../test'): {is_safe_task_path('../test', repo)}")
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Worktree utilities for Multi-Agent Pipeline.
4
+
5
+ Provides:
6
+ get_worktree_config - Get worktree.yaml path
7
+ get_worktree_base_dir - Get worktree storage directory
8
+ get_worktree_copy_files - Get files to copy list
9
+ get_worktree_post_create_hooks - Get post-create hooks
10
+ get_agents_dir - Get agents registry directory
11
+ """
12
+
13
+
14
+ from pathlib import Path
15
+
16
+ from .paths import (
17
+ DIR_WORKFLOW,
18
+ get_repo_root,
19
+ get_workspace_dir,
20
+ )
21
+
22
+
23
+ # =============================================================================
24
+ # YAML Simple Parser (no dependencies)
25
+ # =============================================================================
26
+
27
+ def parse_simple_yaml(content: str) -> dict:
28
+ """Parse simple YAML (only supports key: value and lists).
29
+
30
+ Args:
31
+ content: YAML content string.
32
+
33
+ Returns:
34
+ Parsed dict.
35
+ """
36
+ result: dict = {}
37
+ current_list: Optional[list] = None
38
+
39
+ for line in content.splitlines():
40
+ stripped = line.strip()
41
+ if not stripped or stripped.startswith("#"):
42
+ continue
43
+
44
+ if stripped.startswith("- "):
45
+ if current_list is not None:
46
+ current_list.append(stripped[2:].strip().strip('"').strip("'"))
47
+ elif ":" in stripped:
48
+ key, _, value = stripped.partition(":")
49
+ key = key.strip()
50
+ value = value.strip().strip('"').strip("'")
51
+ if value:
52
+ result[key] = value
53
+ _ = None
54
+ current_list = None
55
+ else:
56
+ _ = key
57
+ current_list = []
58
+ result[key] = current_list
59
+
60
+ return result
61
+
62
+
63
+ def _yaml_get_value(config_file: Path, key: str) -> Optional[str]:
64
+ """Read simple value from worktree.yaml.
65
+
66
+ Args:
67
+ config_file: Path to config file.
68
+ key: Key to read.
69
+
70
+ Returns:
71
+ Value string or None.
72
+ """
73
+ try:
74
+ content = config_file.read_text(encoding="utf-8")
75
+ data = parse_simple_yaml(content)
76
+ value = data.get(key)
77
+ if isinstance(value, str):
78
+ return value
79
+ except (OSError, IOError):
80
+ pass
81
+ return None
82
+
83
+
84
+ def _yaml_get_list(config_file: Path, section: str) -> list[str]:
85
+ """Read list from worktree.yaml.
86
+
87
+ Args:
88
+ config_file: Path to config file.
89
+ section: Section name.
90
+
91
+ Returns:
92
+ List of items.
93
+ """
94
+ try:
95
+ content = config_file.read_text(encoding="utf-8")
96
+ data = parse_simple_yaml(content)
97
+ value = data.get(section)
98
+ if isinstance(value, list):
99
+ return [str(item) for item in value]
100
+ except (OSError, IOError):
101
+ pass
102
+ return []
103
+
104
+
105
+ # =============================================================================
106
+ # Worktree Configuration
107
+ # =============================================================================
108
+
109
+ # Worktree config file relative path (relative to repo root)
110
+ WORKTREE_CONFIG_PATH = f"{DIR_WORKFLOW}/worktree.yaml"
111
+
112
+
113
+ def get_worktree_config(repo_root: Optional[Path] = None) -> Path:
114
+ """Get worktree.yaml config file path.
115
+
116
+ Args:
117
+ repo_root: Repository root path. Defaults to auto-detected.
118
+
119
+ Returns:
120
+ Absolute path to config file.
121
+ """
122
+ if repo_root is None:
123
+ repo_root = get_repo_root()
124
+ return repo_root / WORKTREE_CONFIG_PATH
125
+
126
+
127
+ def get_worktree_base_dir(repo_root: Optional[Path] = None) -> Path:
128
+ """Get worktree base directory.
129
+
130
+ Args:
131
+ repo_root: Repository root path. Defaults to auto-detected.
132
+
133
+ Returns:
134
+ Absolute path to worktree base directory.
135
+ """
136
+ if repo_root is None:
137
+ repo_root = get_repo_root()
138
+
139
+ config = get_worktree_config(repo_root)
140
+ worktree_dir = _yaml_get_value(config, "worktree_dir")
141
+
142
+ # Default value
143
+ if not worktree_dir:
144
+ worktree_dir = "../worktrees"
145
+
146
+ # Handle relative path
147
+ if worktree_dir.startswith("../") or worktree_dir.startswith("./"):
148
+ # Relative to repo_root
149
+ return repo_root / worktree_dir
150
+ else:
151
+ # Absolute path
152
+ return Path(worktree_dir)
153
+
154
+
155
+ def get_worktree_copy_files(repo_root: Optional[Path] = None) -> list[str]:
156
+ """Get files to copy list.
157
+
158
+ Args:
159
+ repo_root: Repository root path. Defaults to auto-detected.
160
+
161
+ Returns:
162
+ List of file paths to copy.
163
+ """
164
+ if repo_root is None:
165
+ repo_root = get_repo_root()
166
+ config = get_worktree_config(repo_root)
167
+ return _yaml_get_list(config, "copy")
168
+
169
+
170
+ def get_worktree_post_create_hooks(repo_root: Optional[Path] = None) -> list[str]:
171
+ """Get post_create hooks.
172
+
173
+ Args:
174
+ repo_root: Repository root path. Defaults to auto-detected.
175
+
176
+ Returns:
177
+ List of commands to run.
178
+ """
179
+ if repo_root is None:
180
+ repo_root = get_repo_root()
181
+ config = get_worktree_config(repo_root)
182
+ return _yaml_get_list(config, "post_create")
183
+
184
+
185
+ # =============================================================================
186
+ # Agents Registry
187
+ # =============================================================================
188
+
189
+ def get_agents_dir(repo_root: Optional[Path] = None) -> Optional[Path]:
190
+ """Get agents directory for current developer.
191
+
192
+ Args:
193
+ repo_root: Repository root path. Defaults to auto-detected.
194
+
195
+ Returns:
196
+ Absolute path to agents directory, or None if no workspace.
197
+ """
198
+ if repo_root is None:
199
+ repo_root = get_repo_root()
200
+
201
+ workspace_dir = get_workspace_dir(repo_root)
202
+ if workspace_dir:
203
+ return workspace_dir / ".agents"
204
+ return None
205
+
206
+
207
+ # =============================================================================
208
+ # Main Entry (for testing)
209
+ # =============================================================================
210
+
211
+ if __name__ == "__main__":
212
+ repo = get_repo_root()
213
+ print(f"Repository root: {repo}")
214
+ print(f"Worktree config: {get_worktree_config(repo)}")
215
+ print(f"Worktree base dir: {get_worktree_base_dir(repo)}")
216
+ print(f"Copy files: {get_worktree_copy_files(repo)}")
217
+ print(f"Post create hooks: {get_worktree_post_create_hooks(repo)}")
218
+ print(f"Agents dir: {get_agents_dir(repo)}")