@mindfoldhq/trellis 0.3.10 → 0.4.0-beta.10

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 (304) hide show
  1. package/README.md +19 -5
  2. package/dist/cli/index.js +5 -0
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/init.d.ts +4 -0
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +240 -43
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/update.d.ts.map +1 -1
  9. package/dist/commands/update.js +206 -47
  10. package/dist/commands/update.js.map +1 -1
  11. package/dist/configurators/codebuddy.d.ts +11 -0
  12. package/dist/configurators/codebuddy.d.ts.map +1 -0
  13. package/dist/configurators/codebuddy.js +58 -0
  14. package/dist/configurators/codebuddy.js.map +1 -0
  15. package/dist/configurators/codex.d.ts +7 -4
  16. package/dist/configurators/codex.d.ts.map +1 -1
  17. package/dist/configurators/codex.js +40 -10
  18. package/dist/configurators/codex.js.map +1 -1
  19. package/dist/configurators/copilot.d.ts +9 -0
  20. package/dist/configurators/copilot.d.ts.map +1 -0
  21. package/dist/configurators/copilot.js +34 -0
  22. package/dist/configurators/copilot.js.map +1 -0
  23. package/dist/configurators/index.d.ts +11 -1
  24. package/dist/configurators/index.d.ts.map +1 -1
  25. package/dist/configurators/index.js +72 -4
  26. package/dist/configurators/index.js.map +1 -1
  27. package/dist/configurators/opencode.d.ts +1 -1
  28. package/dist/configurators/opencode.js +1 -1
  29. package/dist/configurators/windsurf.d.ts +8 -0
  30. package/dist/configurators/windsurf.d.ts.map +1 -0
  31. package/dist/configurators/windsurf.js +18 -0
  32. package/dist/configurators/windsurf.js.map +1 -0
  33. package/dist/configurators/workflow.d.ts +6 -2
  34. package/dist/configurators/workflow.d.ts.map +1 -1
  35. package/dist/configurators/workflow.js +90 -58
  36. package/dist/configurators/workflow.js.map +1 -1
  37. package/dist/migrations/index.d.ts +1 -0
  38. package/dist/migrations/index.d.ts.map +1 -1
  39. package/dist/migrations/index.js +2 -0
  40. package/dist/migrations/index.js.map +1 -1
  41. package/dist/migrations/manifests/0.4.0-beta.1.json +228 -0
  42. package/dist/migrations/manifests/0.4.0-beta.10.json +9 -0
  43. package/dist/migrations/manifests/0.4.0-beta.2.json +9 -0
  44. package/dist/migrations/manifests/0.4.0-beta.3.json +9 -0
  45. package/dist/migrations/manifests/0.4.0-beta.4.json +9 -0
  46. package/dist/migrations/manifests/0.4.0-beta.5.json +9 -0
  47. package/dist/migrations/manifests/0.4.0-beta.6.json +9 -0
  48. package/dist/migrations/manifests/0.4.0-beta.7.json +9 -0
  49. package/dist/migrations/manifests/0.4.0-beta.8.json +34 -0
  50. package/dist/migrations/manifests/0.4.0-beta.9.json +9 -0
  51. package/dist/templates/claude/agents/dispatch.md +1 -2
  52. package/dist/templates/claude/agents/implement.md +2 -3
  53. package/dist/templates/claude/commands/trellis/before-dev.md +29 -0
  54. package/dist/templates/claude/commands/trellis/check.md +25 -0
  55. package/dist/templates/claude/commands/trellis/create-command.md +2 -2
  56. package/dist/templates/claude/commands/trellis/onboard.md +13 -13
  57. package/dist/templates/claude/commands/trellis/parallel.md +1 -2
  58. package/dist/templates/claude/commands/trellis/record-session.md +3 -2
  59. package/dist/templates/claude/commands/trellis/start.md +8 -4
  60. package/dist/templates/claude/hooks/inject-subagent-context.py +29 -14
  61. package/dist/templates/claude/hooks/ralph-loop.py +18 -10
  62. package/dist/templates/claude/hooks/session-start.py +201 -9
  63. package/dist/templates/claude/hooks/statusline.py +211 -0
  64. package/dist/templates/claude/settings.json +4 -0
  65. package/dist/templates/codebuddy/commands/trellis/before-dev.md +29 -0
  66. package/dist/templates/codebuddy/commands/trellis/brainstorm.md +487 -0
  67. package/dist/templates/codebuddy/commands/trellis/break-loop.md +107 -0
  68. package/dist/templates/codebuddy/commands/trellis/check-cross-layer.md +153 -0
  69. package/dist/templates/codebuddy/commands/trellis/check.md +25 -0
  70. package/dist/templates/codebuddy/commands/trellis/create-command.md +154 -0
  71. package/dist/templates/codebuddy/commands/trellis/finish-work.md +143 -0
  72. package/dist/templates/codebuddy/commands/trellis/integrate-skill.md +219 -0
  73. package/dist/templates/codebuddy/commands/trellis/onboard.md +358 -0
  74. package/dist/templates/codebuddy/commands/trellis/record-session.md +61 -0
  75. package/dist/templates/codebuddy/commands/trellis/start.md +373 -0
  76. package/dist/templates/codebuddy/commands/trellis/update-spec.md +354 -0
  77. package/dist/templates/codebuddy/index.d.ts +25 -0
  78. package/dist/templates/codebuddy/index.d.ts.map +1 -0
  79. package/dist/templates/codebuddy/index.js +45 -0
  80. package/dist/templates/codebuddy/index.js.map +1 -0
  81. package/dist/templates/codex/agents/check.toml +23 -0
  82. package/dist/templates/codex/agents/implement.toml +19 -0
  83. package/dist/templates/codex/agents/research.toml +26 -0
  84. package/dist/templates/codex/codex-skills/parallel/SKILL.md +194 -0
  85. package/dist/templates/codex/config.toml +5 -0
  86. package/dist/templates/codex/hooks/session-start.py +228 -0
  87. package/dist/templates/codex/hooks.json +16 -0
  88. package/dist/templates/codex/index.d.ts +27 -5
  89. package/dist/templates/codex/index.d.ts.map +1 -1
  90. package/dist/templates/codex/index.js +60 -8
  91. package/dist/templates/codex/index.js.map +1 -1
  92. package/dist/templates/codex/skills/before-dev/SKILL.md +34 -0
  93. package/dist/templates/codex/skills/brainstorm/SKILL.md +1 -1
  94. package/dist/templates/codex/skills/break-loop/SKILL.md +1 -1
  95. package/dist/templates/codex/skills/check/SKILL.md +30 -0
  96. package/dist/templates/codex/skills/check-cross-layer/SKILL.md +1 -1
  97. package/dist/templates/codex/skills/create-command/SKILL.md +3 -3
  98. package/dist/templates/codex/skills/finish-work/SKILL.md +1 -1
  99. package/dist/templates/codex/skills/improve-ut/SKILL.md +69 -0
  100. package/dist/templates/codex/skills/integrate-skill/SKILL.md +1 -1
  101. package/dist/templates/codex/skills/onboard/SKILL.md +12 -12
  102. package/dist/templates/codex/skills/record-session/SKILL.md +4 -3
  103. package/dist/templates/codex/skills/start/SKILL.md +9 -4
  104. package/dist/templates/codex/skills/update-spec/SKILL.md +1 -1
  105. package/dist/templates/copilot/hooks/session-start.py +218 -0
  106. package/dist/templates/copilot/hooks.json +11 -0
  107. package/dist/templates/copilot/index.d.ts +23 -0
  108. package/dist/templates/copilot/index.d.ts.map +1 -0
  109. package/dist/templates/copilot/index.js +54 -0
  110. package/dist/templates/copilot/index.js.map +1 -0
  111. package/dist/templates/copilot/prompts/before-dev.prompt.md +33 -0
  112. package/dist/templates/copilot/prompts/brainstorm.prompt.md +491 -0
  113. package/dist/templates/copilot/prompts/break-loop.prompt.md +129 -0
  114. package/dist/templates/copilot/prompts/check-cross-layer.prompt.md +157 -0
  115. package/dist/templates/copilot/prompts/check.prompt.md +29 -0
  116. package/dist/templates/copilot/prompts/create-command.prompt.md +116 -0
  117. package/dist/templates/copilot/prompts/finish-work.prompt.md +157 -0
  118. package/dist/templates/copilot/prompts/integrate-skill.prompt.md +223 -0
  119. package/dist/templates/copilot/prompts/onboard.prompt.md +362 -0
  120. package/dist/templates/copilot/prompts/parallel.prompt.md +196 -0
  121. package/dist/templates/copilot/prompts/record-session.prompt.md +66 -0
  122. package/dist/templates/copilot/prompts/start.prompt.md +397 -0
  123. package/dist/templates/copilot/prompts/update-spec.prompt.md +358 -0
  124. package/dist/templates/cursor/commands/trellis-before-dev.md +29 -0
  125. package/dist/templates/cursor/commands/trellis-check.md +25 -0
  126. package/dist/templates/cursor/commands/trellis-create-command.md +2 -2
  127. package/dist/templates/cursor/commands/trellis-onboard.md +13 -13
  128. package/dist/templates/cursor/commands/trellis-record-session.md +3 -2
  129. package/dist/templates/cursor/commands/trellis-start.md +7 -16
  130. package/dist/templates/extract.d.ts +36 -0
  131. package/dist/templates/extract.d.ts.map +1 -1
  132. package/dist/templates/extract.js +64 -0
  133. package/dist/templates/extract.js.map +1 -1
  134. package/dist/templates/gemini/commands/trellis/before-dev.toml +33 -0
  135. package/dist/templates/gemini/commands/trellis/check.toml +29 -0
  136. package/dist/templates/gemini/commands/trellis/create-command.toml +2 -2
  137. package/dist/templates/gemini/commands/trellis/onboard.toml +2 -2
  138. package/dist/templates/gemini/commands/trellis/record-session.toml +3 -2
  139. package/dist/templates/gemini/commands/trellis/start.toml +9 -4
  140. package/dist/templates/iflow/agents/dispatch.md +1 -2
  141. package/dist/templates/iflow/agents/implement.md +2 -3
  142. package/dist/templates/iflow/commands/trellis/before-dev.md +29 -0
  143. package/dist/templates/iflow/commands/trellis/check.md +25 -0
  144. package/dist/templates/iflow/commands/trellis/create-command.md +2 -2
  145. package/dist/templates/iflow/commands/trellis/onboard.md +13 -13
  146. package/dist/templates/iflow/commands/trellis/parallel.md +1 -2
  147. package/dist/templates/iflow/commands/trellis/record-session.md +3 -2
  148. package/dist/templates/iflow/commands/trellis/start.md +8 -4
  149. package/dist/templates/iflow/hooks/inject-subagent-context.py +29 -14
  150. package/dist/templates/iflow/hooks/ralph-loop.py +8 -1
  151. package/dist/templates/iflow/hooks/session-start.py +187 -8
  152. package/dist/templates/kilo/workflows/before-dev.md +29 -0
  153. package/dist/templates/kilo/workflows/check.md +25 -0
  154. package/dist/templates/kilo/workflows/create-command.md +2 -2
  155. package/dist/templates/kilo/workflows/onboard.md +13 -13
  156. package/dist/templates/kilo/workflows/parallel.md +1 -2
  157. package/dist/templates/kilo/workflows/record-session.md +3 -2
  158. package/dist/templates/kilo/workflows/start.md +8 -3
  159. package/dist/templates/kiro/skills/before-dev/SKILL.md +34 -0
  160. package/dist/templates/kiro/skills/brainstorm/SKILL.md +1 -1
  161. package/dist/templates/kiro/skills/break-loop/SKILL.md +1 -1
  162. package/dist/templates/kiro/skills/check/SKILL.md +30 -0
  163. package/dist/templates/kiro/skills/check-cross-layer/SKILL.md +1 -1
  164. package/dist/templates/kiro/skills/create-command/SKILL.md +3 -3
  165. package/dist/templates/kiro/skills/finish-work/SKILL.md +1 -1
  166. package/dist/templates/kiro/skills/integrate-skill/SKILL.md +1 -1
  167. package/dist/templates/kiro/skills/onboard/SKILL.md +12 -12
  168. package/dist/templates/kiro/skills/record-session/SKILL.md +4 -3
  169. package/dist/templates/kiro/skills/start/SKILL.md +9 -4
  170. package/dist/templates/kiro/skills/update-spec/SKILL.md +1 -1
  171. package/dist/templates/markdown/agents.md +4 -0
  172. package/dist/templates/markdown/spec/backend/directory-structure.md +1 -1
  173. package/dist/templates/markdown/spec/backend/script-conventions.md +93 -0
  174. package/dist/templates/markdown/workspace-index.md +2 -0
  175. package/dist/templates/opencode/agents/dispatch.md +21 -21
  176. package/dist/templates/opencode/agents/implement.md +2 -2
  177. package/dist/templates/opencode/agents/research.md +1 -2
  178. package/dist/templates/opencode/commands/trellis/before-dev.md +29 -0
  179. package/dist/templates/opencode/commands/trellis/check.md +25 -0
  180. package/dist/templates/opencode/commands/trellis/create-command.md +2 -2
  181. package/dist/templates/opencode/commands/trellis/onboard.md +13 -13
  182. package/dist/templates/opencode/commands/trellis/parallel.md +1 -2
  183. package/dist/templates/opencode/commands/trellis/record-session.md +3 -2
  184. package/dist/templates/opencode/commands/trellis/start.md +8 -3
  185. package/dist/templates/opencode/lib/trellis-context.js +42 -2
  186. package/dist/templates/opencode/{plugin → plugins}/inject-subagent-context.js +45 -18
  187. package/dist/templates/opencode/{plugin → plugins}/session-start.js +156 -28
  188. package/dist/templates/qoder/skills/before-dev/SKILL.md +34 -0
  189. package/dist/templates/qoder/skills/brainstorm/SKILL.md +1 -1
  190. package/dist/templates/qoder/skills/break-loop/SKILL.md +1 -1
  191. package/dist/templates/qoder/skills/check/SKILL.md +30 -0
  192. package/dist/templates/qoder/skills/check-cross-layer/SKILL.md +1 -1
  193. package/dist/templates/qoder/skills/create-command/SKILL.md +3 -3
  194. package/dist/templates/qoder/skills/finish-work/SKILL.md +1 -1
  195. package/dist/templates/qoder/skills/integrate-skill/SKILL.md +1 -1
  196. package/dist/templates/qoder/skills/onboard/SKILL.md +14 -14
  197. package/dist/templates/qoder/skills/record-session/SKILL.md +4 -3
  198. package/dist/templates/qoder/skills/start/SKILL.md +9 -4
  199. package/dist/templates/qoder/skills/update-spec/SKILL.md +1 -1
  200. package/dist/templates/trellis/config.yaml +20 -0
  201. package/dist/templates/trellis/index.d.ts +11 -0
  202. package/dist/templates/trellis/index.d.ts.map +1 -1
  203. package/dist/templates/trellis/index.js +22 -0
  204. package/dist/templates/trellis/index.js.map +1 -1
  205. package/dist/templates/trellis/scripts/add_session.py +111 -13
  206. package/dist/templates/trellis/scripts/common/__init__.py +2 -0
  207. package/dist/templates/trellis/scripts/common/cli_adapter.py +164 -64
  208. package/dist/templates/trellis/scripts/common/config.py +192 -0
  209. package/dist/templates/trellis/scripts/common/developer.py +2 -2
  210. package/dist/templates/trellis/scripts/common/git.py +31 -0
  211. package/dist/templates/trellis/scripts/common/git_context.py +23 -586
  212. package/dist/templates/trellis/scripts/common/io.py +37 -0
  213. package/dist/templates/trellis/scripts/common/log.py +45 -0
  214. package/dist/templates/trellis/scripts/common/packages_context.py +238 -0
  215. package/dist/templates/trellis/scripts/common/paths.py +103 -6
  216. package/dist/templates/trellis/scripts/common/phase.py +50 -49
  217. package/dist/templates/trellis/scripts/common/registry.py +41 -72
  218. package/dist/templates/trellis/scripts/common/session_context.py +562 -0
  219. package/dist/templates/trellis/scripts/common/task_context.py +410 -0
  220. package/dist/templates/trellis/scripts/common/task_queue.py +27 -98
  221. package/dist/templates/trellis/scripts/common/task_store.py +536 -0
  222. package/dist/templates/trellis/scripts/common/task_utils.py +106 -10
  223. package/dist/templates/trellis/scripts/common/tasks.py +109 -0
  224. package/dist/templates/trellis/scripts/common/types.py +112 -0
  225. package/dist/templates/trellis/scripts/create_bootstrap.py +32 -27
  226. package/dist/templates/trellis/scripts/hooks/linear_sync.py +243 -0
  227. package/dist/templates/trellis/scripts/multi_agent/_bootstrap.py +17 -0
  228. package/dist/templates/trellis/scripts/multi_agent/cleanup.py +43 -48
  229. package/dist/templates/trellis/scripts/multi_agent/create_pr.py +336 -45
  230. package/dist/templates/trellis/scripts/multi_agent/plan.py +9 -32
  231. package/dist/templates/trellis/scripts/multi_agent/start.py +142 -68
  232. package/dist/templates/trellis/scripts/multi_agent/status.py +12 -753
  233. package/dist/templates/trellis/scripts/multi_agent/status_display.py +542 -0
  234. package/dist/templates/trellis/scripts/multi_agent/status_monitor.py +225 -0
  235. package/dist/templates/trellis/scripts/task.py +51 -976
  236. package/dist/templates/trellis/scripts-shell-archive/create-bootstrap.sh +1 -1
  237. package/dist/templates/trellis/workflow.md +38 -38
  238. package/dist/templates/windsurf/index.d.ts +21 -0
  239. package/dist/templates/windsurf/index.d.ts.map +1 -0
  240. package/dist/templates/windsurf/index.js +44 -0
  241. package/dist/templates/windsurf/index.js.map +1 -0
  242. package/dist/templates/windsurf/workflows/trellis-before-dev.md +31 -0
  243. package/dist/templates/windsurf/workflows/trellis-brainstorm.md +491 -0
  244. package/dist/templates/windsurf/workflows/trellis-break-loop.md +111 -0
  245. package/dist/templates/windsurf/workflows/trellis-check-cross-layer.md +157 -0
  246. package/dist/templates/windsurf/workflows/trellis-check.md +27 -0
  247. package/dist/templates/windsurf/workflows/trellis-create-command.md +154 -0
  248. package/dist/templates/windsurf/workflows/trellis-finish-work.md +147 -0
  249. package/dist/templates/windsurf/workflows/trellis-integrate-skill.md +220 -0
  250. package/dist/templates/windsurf/workflows/trellis-onboard.md +362 -0
  251. package/dist/templates/windsurf/workflows/trellis-record-session.md +66 -0
  252. package/dist/templates/windsurf/workflows/trellis-start.md +373 -0
  253. package/dist/templates/windsurf/workflows/trellis-update-spec.md +358 -0
  254. package/dist/types/ai-tools.d.ts +15 -3
  255. package/dist/types/ai-tools.d.ts.map +1 -1
  256. package/dist/types/ai-tools.js +42 -2
  257. package/dist/types/ai-tools.js.map +1 -1
  258. package/dist/types/migration.d.ts +3 -1
  259. package/dist/types/migration.d.ts.map +1 -1
  260. package/dist/utils/project-detector.d.ts +28 -0
  261. package/dist/utils/project-detector.d.ts.map +1 -1
  262. package/dist/utils/project-detector.js +371 -0
  263. package/dist/utils/project-detector.js.map +1 -1
  264. package/dist/utils/template-fetcher.d.ts +19 -6
  265. package/dist/utils/template-fetcher.d.ts.map +1 -1
  266. package/dist/utils/template-fetcher.js +99 -17
  267. package/dist/utils/template-fetcher.js.map +1 -1
  268. package/package.json +1 -1
  269. package/dist/templates/claude/commands/trellis/before-backend-dev.md +0 -13
  270. package/dist/templates/claude/commands/trellis/before-frontend-dev.md +0 -13
  271. package/dist/templates/claude/commands/trellis/check-backend.md +0 -13
  272. package/dist/templates/claude/commands/trellis/check-frontend.md +0 -13
  273. package/dist/templates/codex/skills/before-backend-dev/SKILL.md +0 -18
  274. package/dist/templates/codex/skills/before-frontend-dev/SKILL.md +0 -18
  275. package/dist/templates/codex/skills/check-backend/SKILL.md +0 -18
  276. package/dist/templates/codex/skills/check-frontend/SKILL.md +0 -18
  277. package/dist/templates/cursor/commands/trellis-before-backend-dev.md +0 -13
  278. package/dist/templates/cursor/commands/trellis-before-frontend-dev.md +0 -13
  279. package/dist/templates/cursor/commands/trellis-check-backend.md +0 -13
  280. package/dist/templates/cursor/commands/trellis-check-frontend.md +0 -13
  281. package/dist/templates/gemini/commands/trellis/before-backend-dev.toml +0 -17
  282. package/dist/templates/gemini/commands/trellis/before-frontend-dev.toml +0 -17
  283. package/dist/templates/gemini/commands/trellis/check-backend.toml +0 -17
  284. package/dist/templates/gemini/commands/trellis/check-frontend.toml +0 -17
  285. package/dist/templates/iflow/commands/trellis/before-backend-dev.md +0 -13
  286. package/dist/templates/iflow/commands/trellis/before-frontend-dev.md +0 -13
  287. package/dist/templates/iflow/commands/trellis/check-backend.md +0 -13
  288. package/dist/templates/iflow/commands/trellis/check-frontend.md +0 -13
  289. package/dist/templates/kilo/workflows/before-backend-dev.md +0 -13
  290. package/dist/templates/kilo/workflows/before-frontend-dev.md +0 -13
  291. package/dist/templates/kilo/workflows/check-backend.md +0 -13
  292. package/dist/templates/kilo/workflows/check-frontend.md +0 -13
  293. package/dist/templates/kiro/skills/before-backend-dev/SKILL.md +0 -18
  294. package/dist/templates/kiro/skills/before-frontend-dev/SKILL.md +0 -18
  295. package/dist/templates/kiro/skills/check-backend/SKILL.md +0 -18
  296. package/dist/templates/kiro/skills/check-frontend/SKILL.md +0 -18
  297. package/dist/templates/opencode/commands/trellis/before-backend-dev.md +0 -13
  298. package/dist/templates/opencode/commands/trellis/before-frontend-dev.md +0 -13
  299. package/dist/templates/opencode/commands/trellis/check-backend.md +0 -13
  300. package/dist/templates/opencode/commands/trellis/check-frontend.md +0 -13
  301. package/dist/templates/qoder/skills/before-backend-dev/SKILL.md +0 -18
  302. package/dist/templates/qoder/skills/before-frontend-dev/SKILL.md +0 -18
  303. package/dist/templates/qoder/skills/check-backend/SKILL.md +0 -18
  304. package/dist/templates/qoder/skills/check-frontend/SKILL.md +0 -18
@@ -1,7 +1,7 @@
1
1
  """
2
2
  CLI Adapter for Multi-Platform Support.
3
3
 
4
- Abstracts differences between Claude Code, OpenCode, Cursor, iFlow, Codex, Kilo, Kiro Code, Gemini CLI, Antigravity, and Qoder interfaces.
4
+ Abstracts differences between Claude Code, OpenCode, Cursor, iFlow, Codex, Kilo, Kiro Code, Gemini CLI, Antigravity, Windsurf, Qoder, CodeBuddy, and GitHub Copilot interfaces.
5
5
 
6
6
  Supported platforms:
7
7
  - claude: Claude Code (default)
@@ -13,7 +13,10 @@ Supported platforms:
13
13
  - kiro: Kiro Code (skills-based)
14
14
  - gemini: Gemini CLI
15
15
  - antigravity: Antigravity (workflow-based)
16
+ - windsurf: Windsurf (workflow-based)
16
17
  - qoder: Qoder
18
+ - codebuddy: CodeBuddy
19
+ - copilot: GitHub Copilot (VS Code)
17
20
 
18
21
  Usage:
19
22
  from common.cli_adapter import CLIAdapter
@@ -42,7 +45,10 @@ Platform = Literal[
42
45
  "kiro",
43
46
  "gemini",
44
47
  "antigravity",
48
+ "windsurf",
45
49
  "qoder",
50
+ "codebuddy",
51
+ "copilot",
46
52
  ]
47
53
 
48
54
 
@@ -87,7 +93,7 @@ class CLIAdapter:
87
93
  """Get platform-specific config directory name.
88
94
 
89
95
  Returns:
90
- Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.agents', '.kilocode', '.kiro', '.gemini', '.agent', or '.qoder')
96
+ Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.codex', '.kilocode', '.kiro', '.gemini', '.agent', '.windsurf', '.qoder', or '.codebuddy')
91
97
  """
92
98
  if self.platform == "opencode":
93
99
  return ".opencode"
@@ -96,7 +102,7 @@ class CLIAdapter:
96
102
  elif self.platform == "iflow":
97
103
  return ".iflow"
98
104
  elif self.platform == "codex":
99
- return ".agents"
105
+ return ".codex"
100
106
  elif self.platform == "kilo":
101
107
  return ".kilocode"
102
108
  elif self.platform == "kiro":
@@ -105,8 +111,14 @@ class CLIAdapter:
105
111
  return ".gemini"
106
112
  elif self.platform == "antigravity":
107
113
  return ".agent"
114
+ elif self.platform == "windsurf":
115
+ return ".windsurf"
108
116
  elif self.platform == "qoder":
109
117
  return ".qoder"
118
+ elif self.platform == "codebuddy":
119
+ return ".codebuddy"
120
+ elif self.platform == "copilot":
121
+ return ".github/copilot"
110
122
  else:
111
123
  return ".claude"
112
124
 
@@ -117,7 +129,7 @@ class CLIAdapter:
117
129
  project_root: Project root directory
118
130
 
119
131
  Returns:
120
- Path to config directory (.claude, .opencode, .cursor, .iflow, .agents, .kilocode, .kiro, .gemini, .agent, or .qoder)
132
+ Path to config directory (.claude, .opencode, .cursor, .iflow, .codex, .kilocode, .kiro, .gemini, .agent, .windsurf, .qoder, or .codebuddy)
121
133
  """
122
134
  return project_root / self.config_dir_name
123
135
 
@@ -129,9 +141,11 @@ class CLIAdapter:
129
141
  project_root: Project root directory
130
142
 
131
143
  Returns:
132
- Path to agent .md file
144
+ Path to agent definition file (.md for most platforms, .toml for Codex)
133
145
  """
134
146
  mapped_name = self.get_agent_name(agent)
147
+ if self.platform == "codex":
148
+ return self.get_config_dir(project_root) / "agents" / f"{mapped_name}.toml"
135
149
  return self.get_config_dir(project_root) / "agents" / f"{mapped_name}.md"
136
150
 
137
151
  def get_commands_path(self, project_root: Path, *parts: str) -> Path:
@@ -147,8 +161,19 @@ class CLIAdapter:
147
161
  Note:
148
162
  Cursor uses prefix naming: .cursor/commands/trellis-<name>.md
149
163
  Antigravity uses workflow directory: .agent/workflows/<name>.md
164
+ Windsurf uses workflow directory: .windsurf/workflows/trellis-<name>.md
165
+ Copilot uses prompt files: .github/prompts/<name>.prompt.md
150
166
  Claude/OpenCode use subdirectory: .claude/commands/trellis/<name>.md
151
167
  """
168
+ if self.platform == "windsurf":
169
+ workflow_dir = self.get_config_dir(project_root) / "workflows"
170
+ if not parts:
171
+ return workflow_dir
172
+ if len(parts) >= 2 and parts[0] == "trellis":
173
+ filename = parts[-1]
174
+ return workflow_dir / f"trellis-{filename}"
175
+ return workflow_dir / Path(*parts)
176
+
152
177
  if self.platform in ("antigravity", "kilo"):
153
178
  workflow_dir = self.get_config_dir(project_root) / "workflows"
154
179
  if not parts:
@@ -158,6 +183,17 @@ class CLIAdapter:
158
183
  return workflow_dir / filename
159
184
  return workflow_dir / Path(*parts)
160
185
 
186
+ if self.platform == "copilot":
187
+ prompts_dir = project_root / ".github" / "prompts"
188
+ if not parts:
189
+ return prompts_dir
190
+ if len(parts) >= 2 and parts[0] == "trellis":
191
+ filename = parts[-1]
192
+ if filename.endswith(".md"):
193
+ filename = filename[:-3]
194
+ return prompts_dir / f"{filename}.prompt.md"
195
+ return prompts_dir / Path(*parts)
196
+
161
197
  if not parts:
162
198
  return self.get_config_dir(project_root) / "commands"
163
199
 
@@ -175,7 +211,7 @@ class CLIAdapter:
175
211
  """Get relative path to a trellis command file.
176
212
 
177
213
  Args:
178
- name: Command name without extension (e.g., 'finish-work', 'check-backend')
214
+ name: Command name without extension (e.g., 'finish-work', 'check')
179
215
 
180
216
  Returns:
181
217
  Relative path string for use in JSONL entries
@@ -186,6 +222,7 @@ class CLIAdapter:
186
222
  Kiro: .kiro/skills/<name>/SKILL.md
187
223
  Gemini: .gemini/commands/trellis/<name>.toml
188
224
  Antigravity: .agent/workflows/<name>.md
225
+ Windsurf: .windsurf/workflows/trellis-<name>.md
189
226
  Others: .{platform}/commands/trellis/<name>.md
190
227
  """
191
228
  if self.platform == "cursor":
@@ -198,8 +235,12 @@ class CLIAdapter:
198
235
  return f".gemini/commands/trellis/{name}.toml"
199
236
  elif self.platform == "antigravity":
200
237
  return f".agent/workflows/{name}.md"
238
+ elif self.platform == "windsurf":
239
+ return f".windsurf/workflows/trellis-{name}.md"
201
240
  elif self.platform == "kilo":
202
241
  return f".kilocode/workflows/{name}.md"
242
+ elif self.platform == "copilot":
243
+ return f".github/prompts/{name}.prompt.md"
203
244
  else:
204
245
  return f"{self.config_dir_name}/commands/trellis/{name}.md"
205
246
 
@@ -225,8 +266,14 @@ class CLIAdapter:
225
266
  return {} # Gemini CLI doesn't have a non-interactive env var
226
267
  elif self.platform == "antigravity":
227
268
  return {}
269
+ elif self.platform == "windsurf":
270
+ return {}
228
271
  elif self.platform == "qoder":
229
272
  return {}
273
+ elif self.platform == "codebuddy":
274
+ return {}
275
+ elif self.platform == "copilot":
276
+ return {}
230
277
  else:
231
278
  return {"CLAUDE_NON_INTERACTIVE": "1"}
232
279
 
@@ -278,12 +325,8 @@ class CLIAdapter:
278
325
  cmd.append(prompt)
279
326
 
280
327
  elif self.platform == "iflow":
281
- cmd = ["iflow", "-p"]
282
- cmd.extend(["-y", "--agent", mapped_agent])
283
- # iFlow doesn't support --session-id on creation
284
- if verbose:
285
- cmd.append("--verbose")
286
- cmd.append(prompt)
328
+ cmd = ["iflow", "-y", "-p"]
329
+ cmd.append(f"${mapped_agent} {prompt}")
287
330
  elif self.platform == "codex":
288
331
  cmd = ["codex", "exec"]
289
332
  cmd.append(prompt)
@@ -296,8 +339,20 @@ class CLIAdapter:
296
339
  raise ValueError(
297
340
  "Antigravity workflows are UI slash commands; CLI agent run is not supported."
298
341
  )
342
+ elif self.platform == "windsurf":
343
+ raise ValueError(
344
+ "Windsurf workflows are UI slash commands; CLI agent run is not supported."
345
+ )
299
346
  elif self.platform == "qoder":
300
347
  cmd = ["qodercli", "-p", prompt]
348
+ elif self.platform == "codebuddy":
349
+ raise ValueError(
350
+ "CodeBuddy does not support non-interactive mode (no CLI agent)"
351
+ )
352
+ elif self.platform == "copilot":
353
+ raise ValueError(
354
+ "GitHub Copilot is IDE-only; CLI agent run is not supported."
355
+ )
301
356
 
302
357
  else: # claude
303
358
  cmd = ["claude", "-p"]
@@ -344,8 +399,20 @@ class CLIAdapter:
344
399
  raise ValueError(
345
400
  "Antigravity workflows are UI slash commands; CLI resume is not supported."
346
401
  )
402
+ elif self.platform == "windsurf":
403
+ raise ValueError(
404
+ "Windsurf workflows are UI slash commands; CLI resume is not supported."
405
+ )
347
406
  elif self.platform == "qoder":
348
407
  return ["qodercli", "--resume", session_id]
408
+ elif self.platform == "codebuddy":
409
+ raise ValueError(
410
+ "CodeBuddy does not support non-interactive mode (no CLI agent)"
411
+ )
412
+ elif self.platform == "copilot":
413
+ raise ValueError(
414
+ "GitHub Copilot is IDE-only; CLI resume is not supported."
415
+ )
349
416
  else:
350
417
  return ["claude", "--resume", session_id]
351
418
 
@@ -408,8 +475,14 @@ class CLIAdapter:
408
475
  return "gemini"
409
476
  elif self.platform == "antigravity":
410
477
  return "agy"
478
+ elif self.platform == "windsurf":
479
+ return "windsurf"
411
480
  elif self.platform == "qoder":
412
481
  return "qodercli"
482
+ elif self.platform == "codebuddy":
483
+ return "codebuddy"
484
+ elif self.platform == "copilot":
485
+ return "copilot"
413
486
  else:
414
487
  return "claude"
415
488
 
@@ -417,9 +490,18 @@ class CLIAdapter:
417
490
  def supports_cli_agents(self) -> bool:
418
491
  """Check if platform supports running agents via CLI.
419
492
 
420
- Claude Code, OpenCode, and iFlow support CLI agent execution.
493
+ Claude Code, OpenCode, iFlow, and Codex support CLI agent execution.
421
494
  Cursor is IDE-only and doesn't support CLI agents.
422
495
  """
496
+ return self.platform in ("claude", "opencode", "iflow", "codex")
497
+
498
+ @property
499
+ def requires_agent_definition_file(self) -> bool:
500
+ """Check if platform requires an agent definition file (.md/.toml) to run.
501
+
502
+ Claude Code, OpenCode, iFlow: require agent .md files (--agent flag).
503
+ Codex: auto-discovers agents from .codex/agents/*.toml, no --agent flag.
504
+ """
423
505
  return self.platform in ("claude", "opencode", "iflow")
424
506
 
425
507
  # =========================================================================
@@ -465,7 +547,7 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
465
547
  """Get CLI adapter for the specified platform.
466
548
 
467
549
  Args:
468
- platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', or 'qoder')
550
+ platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', or 'codebuddy')
469
551
 
470
552
  Returns:
471
553
  CLIAdapter instance
@@ -483,15 +565,46 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
483
565
  "kiro",
484
566
  "gemini",
485
567
  "antigravity",
568
+ "windsurf",
486
569
  "qoder",
570
+ "codebuddy",
571
+ "copilot",
487
572
  ):
488
573
  raise ValueError(
489
- f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', or 'qoder')"
574
+ f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', or 'copilot')"
490
575
  )
491
576
 
492
577
  return CLIAdapter(platform=platform) # type: ignore
493
578
 
494
579
 
580
+ _ALL_PLATFORM_CONFIG_DIRS = (
581
+ ".claude",
582
+ ".cursor",
583
+ ".iflow",
584
+ ".opencode",
585
+ ".agents",
586
+ ".codex",
587
+ ".kilocode",
588
+ ".kiro",
589
+ ".gemini",
590
+ ".agent",
591
+ ".windsurf",
592
+ ".qoder",
593
+ ".codebuddy",
594
+ ".github/copilot",
595
+ )
596
+ """All platform config directory names (used by detect_platform exclusion checks)."""
597
+
598
+
599
+ def _has_other_platform_dir(project_root: Path, exclude: set[str]) -> bool:
600
+ """Check if any platform config dir exists besides those in *exclude*."""
601
+ return any(
602
+ (project_root / d).is_dir()
603
+ for d in _ALL_PLATFORM_CONFIG_DIRS
604
+ if d not in exclude
605
+ )
606
+
607
+
495
608
  def detect_platform(project_root: Path) -> Platform:
496
609
  """Auto-detect platform based on existing config directories.
497
610
 
@@ -500,19 +613,21 @@ def detect_platform(project_root: Path) -> Platform:
500
613
  2. .opencode directory exists → opencode
501
614
  3. .iflow directory exists → iflow
502
615
  4. .cursor directory exists (without .claude) → cursor
503
- 5. .agents/skills exists and no other platform dirs → codex
616
+ 5. .codex exists and no other platform dirs → codex
504
617
  6. .kilocode directory exists → kilo
505
618
  7. .kiro/skills exists and no other platform dirs → kiro
506
619
  8. .gemini directory exists → gemini
507
620
  9. .agent/workflows exists and no other platform dirs → antigravity
508
- 10. .qoder directory exists → qoder
509
- 11. Defaultclaude
621
+ 10. .windsurf/workflows exists and no other platform dirs windsurf
622
+ 11. .codebuddy directory exists codebuddy
623
+ 12. .qoder directory exists → qoder
624
+ 13. Default → claude
510
625
 
511
626
  Args:
512
627
  project_root: Project root directory
513
628
 
514
629
  Returns:
515
- Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', or 'qoder')
630
+ Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'windsurf', 'qoder', 'codebuddy', or default 'claude')
516
631
  """
517
632
  import os
518
633
 
@@ -528,17 +643,18 @@ def detect_platform(project_root: Path) -> Platform:
528
643
  "kiro",
529
644
  "gemini",
530
645
  "antigravity",
646
+ "windsurf",
531
647
  "qoder",
648
+ "codebuddy",
649
+ "copilot",
532
650
  ):
533
651
  return env_platform # type: ignore
534
652
 
535
653
  # Check for .opencode directory (OpenCode-specific)
536
- # Note: .claude might exist in both platforms during migration
537
654
  if (project_root / ".opencode").is_dir():
538
655
  return "opencode"
539
656
 
540
657
  # Check for .iflow directory (iFlow-specific)
541
- # Note: .claude might exist in both platforms during migration
542
658
  if (project_root / ".iflow").is_dir():
543
659
  return "iflow"
544
660
 
@@ -551,21 +667,11 @@ def detect_platform(project_root: Path) -> Platform:
551
667
  if (project_root / ".gemini").is_dir():
552
668
  return "gemini"
553
669
 
554
- # Check for Codex skills directory only when no other platform config exists
555
- other_platform_dirs_codex = (
556
- ".claude",
557
- ".cursor",
558
- ".iflow",
559
- ".opencode",
560
- ".kilocode",
561
- ".kiro",
562
- ".gemini",
563
- ".agent",
564
- )
565
- has_other_platform_config = any(
566
- (project_root / directory).is_dir() for directory in other_platform_dirs_codex
567
- )
568
- if (project_root / ".agents" / "skills").is_dir() and not has_other_platform_config:
670
+ # Check for .codex directory (Codex-specific)
671
+ # .agents/skills/ alone does NOT trigger codex detection (it's a shared standard)
672
+ if (project_root / ".codex").is_dir() and not _has_other_platform_dir(
673
+ project_root, {".codex", ".agents"}
674
+ ):
569
675
  return "codex"
570
676
 
571
677
  # Check for .kilocode directory (Kilo-specific)
@@ -573,45 +679,39 @@ def detect_platform(project_root: Path) -> Platform:
573
679
  return "kilo"
574
680
 
575
681
  # Check for Kiro skills directory only when no other platform config exists
576
- other_platform_dirs_kiro = (
577
- ".claude",
578
- ".cursor",
579
- ".iflow",
580
- ".opencode",
581
- ".agents",
582
- ".kilocode",
583
- ".gemini",
584
- ".agent",
585
- )
586
- has_other_platform_config = any(
587
- (project_root / directory).is_dir() for directory in other_platform_dirs_kiro
588
- )
589
- if (project_root / ".kiro" / "skills").is_dir() and not has_other_platform_config:
682
+ if (project_root / ".kiro" / "skills").is_dir() and not _has_other_platform_dir(
683
+ project_root, {".kiro"}
684
+ ):
590
685
  return "kiro"
591
686
 
592
687
  # Check for Antigravity workflow directory only when no other platform config exists
593
- other_platform_dirs_antigravity = (
594
- ".claude",
595
- ".cursor",
596
- ".iflow",
597
- ".opencode",
598
- ".agents",
599
- ".kilocode",
600
- ".kiro",
601
- )
602
- has_other_platform_config = any(
603
- (project_root / directory).is_dir()
604
- for directory in other_platform_dirs_antigravity
605
- )
606
688
  if (
607
689
  project_root / ".agent" / "workflows"
608
- ).is_dir() and not has_other_platform_config:
690
+ ).is_dir() and not _has_other_platform_dir(
691
+ project_root, {".agent", ".gemini"}
692
+ ):
609
693
  return "antigravity"
610
694
 
695
+ # Check for Windsurf workflow directory only when no other platform config exists
696
+ if (
697
+ project_root / ".windsurf" / "workflows"
698
+ ).is_dir() and not _has_other_platform_dir(
699
+ project_root, {".windsurf"}
700
+ ):
701
+ return "windsurf"
702
+
703
+ # Check for .codebuddy directory (CodeBuddy-specific)
704
+ if (project_root / ".codebuddy").is_dir():
705
+ return "codebuddy"
706
+
611
707
  # Check for .qoder directory (Qoder-specific)
612
708
  if (project_root / ".qoder").is_dir():
613
709
  return "qoder"
614
710
 
711
+ # Check for .github/copilot directory (GitHub Copilot-specific)
712
+ if (project_root / ".github" / "copilot").is_dir():
713
+ return "copilot"
714
+
615
715
  return "claude"
616
716
 
617
717
 
@@ -7,6 +7,7 @@ Reads settings from .trellis/config.yaml with sensible defaults.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
+ import sys
10
11
  from pathlib import Path
11
12
 
12
13
  from .paths import DIR_WORKFLOW, get_repo_root
@@ -20,6 +21,15 @@ DEFAULT_MAX_JOURNAL_LINES = 2000
20
21
  CONFIG_FILE = "config.yaml"
21
22
 
22
23
 
24
+ def _is_true_config_value(value: object) -> bool:
25
+ """Return True when a config value represents an enabled flag."""
26
+ if isinstance(value, bool):
27
+ return value
28
+ if isinstance(value, str):
29
+ return value.strip().lower() == "true"
30
+ return False
31
+
32
+
23
33
  def _get_config_path(repo_root: Path | None = None) -> Path:
24
34
  """Get path to config.yaml."""
25
35
  root = repo_root or get_repo_root()
@@ -70,3 +80,185 @@ def get_hooks(event: str, repo_root: Path | None = None) -> list[str]:
70
80
  if isinstance(commands, list):
71
81
  return [str(c) for c in commands]
72
82
  return []
83
+
84
+
85
+ # =============================================================================
86
+ # Monorepo / Packages
87
+ # =============================================================================
88
+
89
+
90
+ def get_packages(repo_root: Path | None = None) -> dict[str, dict] | None:
91
+ """Get monorepo package declarations.
92
+
93
+ Returns:
94
+ Dict mapping package name to its config (path, type, etc.),
95
+ or None if not configured (single-repo mode).
96
+
97
+ Example return:
98
+ {"cli": {"path": "packages/cli"}, "docs-site": {"path": "docs-site", "type": "submodule"}}
99
+ """
100
+ config = _load_config(repo_root)
101
+ packages = config.get("packages")
102
+ if not isinstance(packages, dict):
103
+ return None
104
+ # Ensure each value is a dict (filter out scalar entries)
105
+ filtered = {k: v for k, v in packages.items() if isinstance(v, dict)}
106
+ if not filtered:
107
+ return None
108
+ return filtered
109
+
110
+
111
+ def get_default_package(repo_root: Path | None = None) -> str | None:
112
+ """Get the default package name from config.
113
+
114
+ Returns:
115
+ Package name string, or None if not configured.
116
+ """
117
+ config = _load_config(repo_root)
118
+ value = config.get("default_package")
119
+ return str(value) if value else None
120
+
121
+
122
+ def get_submodule_packages(repo_root: Path | None = None) -> dict[str, str]:
123
+ """Get packages that are git submodules.
124
+
125
+ Returns:
126
+ Dict mapping package name to its path for submodule-type packages.
127
+ Empty dict if none configured.
128
+
129
+ Example return:
130
+ {"docs-site": "docs-site"}
131
+ """
132
+ packages = get_packages(repo_root)
133
+ if packages is None:
134
+ return {}
135
+ return {
136
+ name: cfg.get("path", name)
137
+ for name, cfg in packages.items()
138
+ if cfg.get("type") == "submodule"
139
+ }
140
+
141
+
142
+ def get_git_packages(repo_root: Path | None = None) -> dict[str, str]:
143
+ """Get packages that have their own independent git repository.
144
+
145
+ These are sub-directories with their own .git (not submodules),
146
+ marked with ``git: true`` in config.yaml.
147
+
148
+ Returns:
149
+ Dict mapping package name to its path for git-repo packages.
150
+ Empty dict if none configured.
151
+
152
+ Example config::
153
+
154
+ packages:
155
+ backend:
156
+ path: iqs
157
+ git: true
158
+
159
+ Example return::
160
+
161
+ {"backend": "iqs"}
162
+ """
163
+ packages = get_packages(repo_root)
164
+ if packages is None:
165
+ return {}
166
+ return {
167
+ name: cfg.get("path", name)
168
+ for name, cfg in packages.items()
169
+ if _is_true_config_value(cfg.get("git"))
170
+ }
171
+
172
+
173
+ def is_monorepo(repo_root: Path | None = None) -> bool:
174
+ """Check if the project is configured as a monorepo (has packages in config)."""
175
+ return get_packages(repo_root) is not None
176
+
177
+
178
+ def get_spec_base(package: str | None = None, repo_root: Path | None = None) -> str:
179
+ """Get the spec directory base path relative to .trellis/.
180
+
181
+ Single-repo: returns "spec"
182
+ Monorepo with package: returns "spec/<package>"
183
+ Monorepo without package: returns "spec" (caller should specify package)
184
+ """
185
+ if package and is_monorepo(repo_root):
186
+ return f"spec/{package}"
187
+ return "spec"
188
+
189
+
190
+ def validate_package(package: str, repo_root: Path | None = None) -> bool:
191
+ """Check if a package name is valid in this project.
192
+
193
+ Single-repo (no packages configured): always returns True.
194
+ Monorepo: returns True only if package exists in config.yaml packages.
195
+ """
196
+ packages = get_packages(repo_root)
197
+ if packages is None:
198
+ return True # Single-repo, no validation needed
199
+ return package in packages
200
+
201
+
202
+ def resolve_package(
203
+ task_package: str | None = None,
204
+ repo_root: Path | None = None,
205
+ ) -> str | None:
206
+ """Resolve package from inferred sources with validation.
207
+
208
+ Checks in order: task_package → default_package.
209
+ Invalid inferred values print a warning to stderr and are skipped.
210
+
211
+ Returns:
212
+ Resolved package name, or None if no valid package found.
213
+
214
+ Note:
215
+ CLI --package should be validated separately by the caller
216
+ (fail-fast with available packages list on error).
217
+ """
218
+ packages = get_packages(repo_root)
219
+ if packages is None:
220
+ return None # Single-repo, no package needed
221
+
222
+ # Try task_package (guard against non-string values from malformed JSON)
223
+ if task_package and isinstance(task_package, str):
224
+ if task_package in packages:
225
+ return task_package
226
+ print(
227
+ f"Warning: task.json package '{task_package}' not found in config, skipping",
228
+ file=sys.stderr,
229
+ )
230
+
231
+ # Try default_package
232
+ default = get_default_package(repo_root)
233
+ if default:
234
+ if default in packages:
235
+ return default
236
+ print(
237
+ f"Warning: default_package '{default}' not found in config, skipping",
238
+ file=sys.stderr,
239
+ )
240
+
241
+ return None
242
+
243
+
244
+ def get_spec_scope(repo_root: Path | None = None) -> list[str] | str | None:
245
+ """Get session.spec_scope configuration.
246
+
247
+ Returns:
248
+ list[str]: Package names to include in spec scanning.
249
+ str: "active_task" to use current task's package.
250
+ None: No scope configured (scan all packages).
251
+ """
252
+ config = _load_config(repo_root)
253
+ session = config.get("session")
254
+ if not isinstance(session, dict):
255
+ return None
256
+
257
+ scope = session.get("spec_scope")
258
+ if scope is None:
259
+ return None
260
+ if isinstance(scope, str):
261
+ return scope # e.g. "active_task"
262
+ if isinstance(scope, list):
263
+ return [str(s) for s in scope]
264
+ return None
@@ -123,8 +123,8 @@ def init_developer(name: str, repo_root: Path | None = None) -> bool:
123
123
  ## Session History
124
124
 
125
125
  <!-- @@@auto:session-history -->
126
- | # | Date | Title | Commits |
127
- |---|------|-------|---------|
126
+ | # | Date | Title | Commits | Branch |
127
+ |---|------|-------|---------|--------|
128
128
  <!-- @@@/auto:session-history -->
129
129
 
130
130
  ---