@fifine/aim-studio 0.0.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 (289) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +159 -0
  3. package/bin/aim.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 +89 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/commands/init.d.ts +13 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +513 -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 +1275 -0
  15. package/dist/commands/update.js.map +1 -0
  16. package/dist/configurators/claude.d.ts +32 -0
  17. package/dist/configurators/claude.d.ts.map +1 -0
  18. package/dist/configurators/claude.js +98 -0
  19. package/dist/configurators/claude.js.map +1 -0
  20. package/dist/configurators/index.d.ts +51 -0
  21. package/dist/configurators/index.d.ts.map +1 -0
  22. package/dist/configurators/index.js +113 -0
  23. package/dist/configurators/index.js.map +1 -0
  24. package/dist/configurators/shared.d.ts +12 -0
  25. package/dist/configurators/shared.d.ts.map +1 -0
  26. package/dist/configurators/shared.js +21 -0
  27. package/dist/configurators/shared.js.map +1 -0
  28. package/dist/configurators/workflow.d.ts +28 -0
  29. package/dist/configurators/workflow.d.ts.map +1 -0
  30. package/dist/configurators/workflow.js +147 -0
  31. package/dist/configurators/workflow.js.map +1 -0
  32. package/dist/constants/paths.d.ts +68 -0
  33. package/dist/constants/paths.d.ts.map +1 -0
  34. package/dist/constants/paths.js +77 -0
  35. package/dist/constants/paths.js.map +1 -0
  36. package/dist/constants/version.d.ts +9 -0
  37. package/dist/constants/version.d.ts.map +1 -0
  38. package/dist/constants/version.js +15 -0
  39. package/dist/constants/version.js.map +1 -0
  40. package/dist/index.d.ts +9 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +9 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/migrations/index.d.ts +54 -0
  45. package/dist/migrations/index.d.ts.map +1 -0
  46. package/dist/migrations/index.js +160 -0
  47. package/dist/migrations/index.js.map +1 -0
  48. package/dist/migrations/manifests/0.0.1.json +9 -0
  49. package/dist/migrations/manifests/0.1.9.json +30 -0
  50. package/dist/migrations/manifests/0.2.0.json +49 -0
  51. package/dist/migrations/manifests/0.2.12.json +9 -0
  52. package/dist/migrations/manifests/0.2.13.json +9 -0
  53. package/dist/migrations/manifests/0.2.14.json +175 -0
  54. package/dist/migrations/manifests/0.2.15.json +33 -0
  55. package/dist/migrations/manifests/0.3.0-beta.0.json +278 -0
  56. package/dist/migrations/manifests/0.3.0-beta.1.json +9 -0
  57. package/dist/migrations/manifests/0.3.0-beta.10.json +9 -0
  58. package/dist/migrations/manifests/0.3.0-beta.11.json +9 -0
  59. package/dist/migrations/manifests/0.3.0-beta.12.json +9 -0
  60. package/dist/migrations/manifests/0.3.0-beta.13.json +9 -0
  61. package/dist/migrations/manifests/0.3.0-beta.14.json +9 -0
  62. package/dist/migrations/manifests/0.3.0-beta.15.json +9 -0
  63. package/dist/migrations/manifests/0.3.0-beta.16.json +9 -0
  64. package/dist/migrations/manifests/0.3.0-beta.2.json +9 -0
  65. package/dist/migrations/manifests/0.3.0-beta.3.json +9 -0
  66. package/dist/migrations/manifests/0.3.0-beta.4.json +9 -0
  67. package/dist/migrations/manifests/0.3.0-beta.5.json +9 -0
  68. package/dist/migrations/manifests/0.3.0-beta.6.json +9 -0
  69. package/dist/migrations/manifests/0.3.0-beta.7.json +11 -0
  70. package/dist/migrations/manifests/0.3.0-beta.8.json +9 -0
  71. package/dist/migrations/manifests/0.3.0-beta.9.json +9 -0
  72. package/dist/migrations/manifests/0.3.0-rc.0.json +9 -0
  73. package/dist/migrations/manifests/0.3.0-rc.1.json +9 -0
  74. package/dist/migrations/manifests/0.3.0-rc.2.json +9 -0
  75. package/dist/templates/CLAUDE.md +71 -0
  76. package/dist/templates/aim/gitignore.txt +29 -0
  77. package/dist/templates/aim/index.d.ts +49 -0
  78. package/dist/templates/aim/index.d.ts.map +1 -0
  79. package/dist/templates/aim/index.js +92 -0
  80. package/dist/templates/aim/index.js.map +1 -0
  81. package/dist/templates/aim/scripts/__init__.py +5 -0
  82. package/dist/templates/aim/scripts/add_session.py +392 -0
  83. package/dist/templates/aim/scripts/common/__init__.py +80 -0
  84. package/dist/templates/aim/scripts/common/cli_adapter.py +435 -0
  85. package/dist/templates/aim/scripts/common/developer.py +190 -0
  86. package/dist/templates/aim/scripts/common/git_context.py +383 -0
  87. package/dist/templates/aim/scripts/common/paths.py +347 -0
  88. package/dist/templates/aim/scripts/common/phase.py +253 -0
  89. package/dist/templates/aim/scripts/common/registry.py +366 -0
  90. package/dist/templates/aim/scripts/common/task_queue.py +255 -0
  91. package/dist/templates/aim/scripts/common/task_utils.py +178 -0
  92. package/dist/templates/aim/scripts/common/worktree.py +219 -0
  93. package/dist/templates/aim/scripts/create_bootstrap.py +290 -0
  94. package/dist/templates/aim/scripts/get_context.py +16 -0
  95. package/dist/templates/aim/scripts/get_developer.py +26 -0
  96. package/dist/templates/aim/scripts/init_developer.py +51 -0
  97. package/dist/templates/aim/scripts/multi_agent/__init__.py +5 -0
  98. package/dist/templates/aim/scripts/multi_agent/cleanup.py +403 -0
  99. package/dist/templates/aim/scripts/multi_agent/create_pr.py +329 -0
  100. package/dist/templates/aim/scripts/multi_agent/plan.py +233 -0
  101. package/dist/templates/aim/scripts/multi_agent/start.py +461 -0
  102. package/dist/templates/aim/scripts/multi_agent/status.py +817 -0
  103. package/dist/templates/aim/scripts/task.py +1068 -0
  104. package/dist/templates/aim/scripts-shell-archive/add-session.sh +384 -0
  105. package/dist/templates/aim/scripts-shell-archive/common/developer.sh +129 -0
  106. package/dist/templates/aim/scripts-shell-archive/common/git-context.sh +263 -0
  107. package/dist/templates/aim/scripts-shell-archive/common/paths.sh +208 -0
  108. package/dist/templates/aim/scripts-shell-archive/common/phase.sh +150 -0
  109. package/dist/templates/aim/scripts-shell-archive/common/registry.sh +247 -0
  110. package/dist/templates/aim/scripts-shell-archive/common/task-queue.sh +142 -0
  111. package/dist/templates/aim/scripts-shell-archive/common/task-utils.sh +151 -0
  112. package/dist/templates/aim/scripts-shell-archive/common/worktree.sh +128 -0
  113. package/dist/templates/aim/scripts-shell-archive/create-bootstrap.sh +299 -0
  114. package/dist/templates/aim/scripts-shell-archive/get-context.sh +7 -0
  115. package/dist/templates/aim/scripts-shell-archive/get-developer.sh +15 -0
  116. package/dist/templates/aim/scripts-shell-archive/init-developer.sh +34 -0
  117. package/dist/templates/aim/scripts-shell-archive/multi-agent/cleanup.sh +396 -0
  118. package/dist/templates/aim/scripts-shell-archive/multi-agent/create-pr.sh +241 -0
  119. package/dist/templates/aim/scripts-shell-archive/multi-agent/plan.sh +207 -0
  120. package/dist/templates/aim/scripts-shell-archive/multi-agent/start.sh +317 -0
  121. package/dist/templates/aim/scripts-shell-archive/multi-agent/status.sh +828 -0
  122. package/dist/templates/aim/scripts-shell-archive/task.sh +1204 -0
  123. package/dist/templates/aim/tasks/.gitkeep +0 -0
  124. package/dist/templates/aim/workflow.md +258 -0
  125. package/dist/templates/aim/worktree.yaml +47 -0
  126. package/dist/templates/claude/agents/check.md +122 -0
  127. package/dist/templates/claude/agents/debug.md +106 -0
  128. package/dist/templates/claude/agents/dispatch.md +230 -0
  129. package/dist/templates/claude/agents/implement.md +96 -0
  130. package/dist/templates/claude/agents/plan.md +396 -0
  131. package/dist/templates/claude/agents/research.md +120 -0
  132. package/dist/templates/claude/agents/story.md +53 -0
  133. package/dist/templates/claude/commands/aim/before-backend-dev.md +13 -0
  134. package/dist/templates/claude/commands/aim/before-frontend-dev.md +13 -0
  135. package/dist/templates/claude/commands/aim/break-loop.md +153 -0
  136. package/dist/templates/claude/commands/aim/check-backend.md +13 -0
  137. package/dist/templates/claude/commands/aim/check-cross-layer.md +153 -0
  138. package/dist/templates/claude/commands/aim/check-frontend.md +13 -0
  139. package/dist/templates/claude/commands/aim/check-story.md +59 -0
  140. package/dist/templates/claude/commands/aim/create-command.md +154 -0
  141. package/dist/templates/claude/commands/aim/export.md +187 -0
  142. package/dist/templates/claude/commands/aim/finish-work.md +104 -0
  143. package/dist/templates/claude/commands/aim/integrate-skill.md +219 -0
  144. package/dist/templates/claude/commands/aim/onboard.md +358 -0
  145. package/dist/templates/claude/commands/aim/parallel.md +217 -0
  146. package/dist/templates/claude/commands/aim/portrait.md +170 -0
  147. package/dist/templates/claude/commands/aim/record-session.md +92 -0
  148. package/dist/templates/claude/commands/aim/start.md +112 -0
  149. package/dist/templates/claude/commands/aim/story.md +140 -0
  150. package/dist/templates/claude/commands/aim/update-spec.md +285 -0
  151. package/dist/templates/claude/commands/aim/visualize.md +182 -0
  152. package/dist/templates/claude/commands/trellis/before-backend-dev.md +13 -0
  153. package/dist/templates/claude/commands/trellis/before-frontend-dev.md +13 -0
  154. package/dist/templates/claude/commands/trellis/break-loop.md +125 -0
  155. package/dist/templates/claude/commands/trellis/check-backend.md +13 -0
  156. package/dist/templates/claude/commands/trellis/check-cross-layer.md +153 -0
  157. package/dist/templates/claude/commands/trellis/check-frontend.md +13 -0
  158. package/dist/templates/claude/commands/trellis/create-command.md +154 -0
  159. package/dist/templates/claude/commands/trellis/finish-work.md +129 -0
  160. package/dist/templates/claude/commands/trellis/integrate-skill.md +219 -0
  161. package/dist/templates/claude/commands/trellis/onboard.md +358 -0
  162. package/dist/templates/claude/commands/trellis/parallel.md +193 -0
  163. package/dist/templates/claude/commands/trellis/record-session.md +62 -0
  164. package/dist/templates/claude/commands/trellis/start.md +280 -0
  165. package/dist/templates/claude/commands/trellis/update-spec.md +285 -0
  166. package/dist/templates/claude/hooks/inject-subagent-context.py +772 -0
  167. package/dist/templates/claude/hooks/ralph-loop.py +388 -0
  168. package/dist/templates/claude/hooks/session-start.py +142 -0
  169. package/dist/templates/claude/index.d.ts +54 -0
  170. package/dist/templates/claude/index.d.ts.map +1 -0
  171. package/dist/templates/claude/index.js +85 -0
  172. package/dist/templates/claude/index.js.map +1 -0
  173. package/dist/templates/claude/settings.json +41 -0
  174. package/dist/templates/extract.d.ts +68 -0
  175. package/dist/templates/extract.d.ts.map +1 -0
  176. package/dist/templates/extract.js +128 -0
  177. package/dist/templates/extract.js.map +1 -0
  178. package/dist/templates/markdown/agents.md +25 -0
  179. package/dist/templates/markdown/gitignore.txt +12 -0
  180. package/dist/templates/markdown/index.d.ts +32 -0
  181. package/dist/templates/markdown/index.d.ts.map +1 -0
  182. package/dist/templates/markdown/index.js +58 -0
  183. package/dist/templates/markdown/index.js.map +1 -0
  184. package/dist/templates/markdown/spec/backend/database-guidelines.md.txt +51 -0
  185. package/dist/templates/markdown/spec/backend/directory-structure.md.txt +54 -0
  186. package/dist/templates/markdown/spec/backend/error-handling.md.txt +51 -0
  187. package/dist/templates/markdown/spec/backend/index.md +40 -0
  188. package/dist/templates/markdown/spec/backend/index.md.txt +38 -0
  189. package/dist/templates/markdown/spec/backend/logging-guidelines.md.txt +51 -0
  190. package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +51 -0
  191. package/dist/templates/markdown/spec/backend/script-conventions.md +467 -0
  192. package/dist/templates/markdown/spec/frontend/component-guidelines.md.txt +59 -0
  193. package/dist/templates/markdown/spec/frontend/directory-structure.md.txt +54 -0
  194. package/dist/templates/markdown/spec/frontend/hook-guidelines.md.txt +51 -0
  195. package/dist/templates/markdown/spec/frontend/index.md.txt +39 -0
  196. package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +51 -0
  197. package/dist/templates/markdown/spec/frontend/state-management.md.txt +51 -0
  198. package/dist/templates/markdown/spec/frontend/type-safety.md.txt +51 -0
  199. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md +118 -0
  200. package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +92 -0
  201. package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +94 -0
  202. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md +394 -0
  203. package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +319 -0
  204. package/dist/templates/markdown/spec/guides/index.md.txt +89 -0
  205. package/dist/templates/markdown/spec/story/character.md.txt +95 -0
  206. package/dist/templates/markdown/spec/story/index.md.txt +31 -0
  207. package/dist/templates/markdown/spec/story/script.md.txt +313 -0
  208. package/dist/templates/markdown/spec/story/world.md.txt +92 -0
  209. package/dist/templates/markdown/workspace-index.md +123 -0
  210. package/dist/templates/markdown/worktree.yaml.txt +58 -0
  211. package/dist/templates/trellis/gitignore.txt +29 -0
  212. package/dist/templates/trellis/index.d.ts +49 -0
  213. package/dist/templates/trellis/index.d.ts.map +1 -0
  214. package/dist/templates/trellis/index.js +92 -0
  215. package/dist/templates/trellis/index.js.map +1 -0
  216. package/dist/templates/trellis/scripts/__init__.py +5 -0
  217. package/dist/templates/trellis/scripts/add_session.py +392 -0
  218. package/dist/templates/trellis/scripts/common/__init__.py +80 -0
  219. package/dist/templates/trellis/scripts/common/cli_adapter.py +435 -0
  220. package/dist/templates/trellis/scripts/common/developer.py +190 -0
  221. package/dist/templates/trellis/scripts/common/git_context.py +383 -0
  222. package/dist/templates/trellis/scripts/common/paths.py +347 -0
  223. package/dist/templates/trellis/scripts/common/phase.py +253 -0
  224. package/dist/templates/trellis/scripts/common/registry.py +366 -0
  225. package/dist/templates/trellis/scripts/common/task_queue.py +255 -0
  226. package/dist/templates/trellis/scripts/common/task_utils.py +178 -0
  227. package/dist/templates/trellis/scripts/common/worktree.py +219 -0
  228. package/dist/templates/trellis/scripts/create_bootstrap.py +290 -0
  229. package/dist/templates/trellis/scripts/get_context.py +16 -0
  230. package/dist/templates/trellis/scripts/get_developer.py +26 -0
  231. package/dist/templates/trellis/scripts/init_developer.py +51 -0
  232. package/dist/templates/trellis/scripts/multi_agent/__init__.py +5 -0
  233. package/dist/templates/trellis/scripts/multi_agent/cleanup.py +403 -0
  234. package/dist/templates/trellis/scripts/multi_agent/create_pr.py +329 -0
  235. package/dist/templates/trellis/scripts/multi_agent/plan.py +233 -0
  236. package/dist/templates/trellis/scripts/multi_agent/start.py +461 -0
  237. package/dist/templates/trellis/scripts/multi_agent/status.py +817 -0
  238. package/dist/templates/trellis/scripts/task.py +1056 -0
  239. package/dist/templates/trellis/scripts-shell-archive/add-session.sh +384 -0
  240. package/dist/templates/trellis/scripts-shell-archive/common/developer.sh +129 -0
  241. package/dist/templates/trellis/scripts-shell-archive/common/git-context.sh +263 -0
  242. package/dist/templates/trellis/scripts-shell-archive/common/paths.sh +208 -0
  243. package/dist/templates/trellis/scripts-shell-archive/common/phase.sh +150 -0
  244. package/dist/templates/trellis/scripts-shell-archive/common/registry.sh +247 -0
  245. package/dist/templates/trellis/scripts-shell-archive/common/task-queue.sh +142 -0
  246. package/dist/templates/trellis/scripts-shell-archive/common/task-utils.sh +151 -0
  247. package/dist/templates/trellis/scripts-shell-archive/common/worktree.sh +128 -0
  248. package/dist/templates/trellis/scripts-shell-archive/create-bootstrap.sh +299 -0
  249. package/dist/templates/trellis/scripts-shell-archive/get-context.sh +7 -0
  250. package/dist/templates/trellis/scripts-shell-archive/get-developer.sh +15 -0
  251. package/dist/templates/trellis/scripts-shell-archive/init-developer.sh +34 -0
  252. package/dist/templates/trellis/scripts-shell-archive/multi-agent/cleanup.sh +396 -0
  253. package/dist/templates/trellis/scripts-shell-archive/multi-agent/create-pr.sh +241 -0
  254. package/dist/templates/trellis/scripts-shell-archive/multi-agent/plan.sh +207 -0
  255. package/dist/templates/trellis/scripts-shell-archive/multi-agent/start.sh +317 -0
  256. package/dist/templates/trellis/scripts-shell-archive/multi-agent/status.sh +828 -0
  257. package/dist/templates/trellis/scripts-shell-archive/task.sh +1204 -0
  258. package/dist/templates/trellis/tasks/.gitkeep +0 -0
  259. package/dist/templates/trellis/workflow.md +416 -0
  260. package/dist/templates/trellis/worktree.yaml +47 -0
  261. package/dist/types/ai-tools.d.ts +48 -0
  262. package/dist/types/ai-tools.d.ts.map +1 -0
  263. package/dist/types/ai-tools.js +32 -0
  264. package/dist/types/ai-tools.js.map +1 -0
  265. package/dist/types/migration.d.ts +86 -0
  266. package/dist/types/migration.d.ts.map +1 -0
  267. package/dist/types/migration.js +8 -0
  268. package/dist/types/migration.js.map +1 -0
  269. package/dist/utils/compare-versions.d.ts +12 -0
  270. package/dist/utils/compare-versions.d.ts.map +1 -0
  271. package/dist/utils/compare-versions.js +76 -0
  272. package/dist/utils/compare-versions.js.map +1 -0
  273. package/dist/utils/file-writer.d.ts +23 -0
  274. package/dist/utils/file-writer.d.ts.map +1 -0
  275. package/dist/utils/file-writer.js +140 -0
  276. package/dist/utils/file-writer.js.map +1 -0
  277. package/dist/utils/project-detector.d.ts +16 -0
  278. package/dist/utils/project-detector.d.ts.map +1 -0
  279. package/dist/utils/project-detector.js +188 -0
  280. package/dist/utils/project-detector.js.map +1 -0
  281. package/dist/utils/template-fetcher.d.ts +51 -0
  282. package/dist/utils/template-fetcher.d.ts.map +1 -0
  283. package/dist/utils/template-fetcher.js +174 -0
  284. package/dist/utils/template-fetcher.js.map +1 -0
  285. package/dist/utils/template-hash.d.ts +78 -0
  286. package/dist/utils/template-hash.d.ts.map +1 -0
  287. package/dist/utils/template-hash.js +239 -0
  288. package/dist/utils/template-hash.js.map +1 -0
  289. package/package.json +87 -0
@@ -0,0 +1,1204 @@
1
+ #!/bin/bash
2
+ # Task Management Script for Multi-Agent Pipeline
3
+ #
4
+ # Usage:
5
+ # ./.trellis/scripts/task.sh create "<title>" [--slug <name>] [--assignee <dev>] [--priority P0|P1|P2|P3]
6
+ # ./.trellis/scripts/task.sh init-context <dir> <type> # Initialize jsonl files
7
+ # ./.trellis/scripts/task.sh add-context <dir> <file> <path> [reason] # Add jsonl entry
8
+ # ./.trellis/scripts/task.sh validate <dir> # Validate jsonl files
9
+ # ./.trellis/scripts/task.sh list-context <dir> # List jsonl entries
10
+ # ./.trellis/scripts/task.sh start <dir> # Set as current task
11
+ # ./.trellis/scripts/task.sh finish # Clear current task
12
+ # ./.trellis/scripts/task.sh set-branch <dir> <branch> # Set git branch
13
+ # ./.trellis/scripts/task.sh set-scope <dir> <scope> # Set scope for PR title
14
+ # ./.trellis/scripts/task.sh create-pr [dir] [--dry-run] # Create PR from task
15
+ # ./.trellis/scripts/task.sh archive <task-name> # Archive completed task
16
+ # ./.trellis/scripts/task.sh list # List active tasks
17
+ # ./.trellis/scripts/task.sh list-archive [month] # List archived tasks
18
+ #
19
+ # Task Directory Structure:
20
+ # tasks/
21
+ # ├── 01-21-my-task/
22
+ # │ ├── task.json # Metadata
23
+ # │ ├── prd.md # Requirements
24
+ # │ ├── info.md # Technical design (optional)
25
+ # │ ├── implement.jsonl # Implement agent context
26
+ # │ ├── check.jsonl # Check agent context
27
+ # │ └── debug.jsonl # Debug agent context
28
+ # └── archive/
29
+ # └── 2026-01/
30
+ # └── 01-21-old-task/
31
+
32
+ set -e
33
+
34
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
35
+ source "$SCRIPT_DIR/common/paths.sh"
36
+ source "$SCRIPT_DIR/common/developer.sh"
37
+ source "$SCRIPT_DIR/common/task-queue.sh"
38
+ source "$SCRIPT_DIR/common/task-utils.sh"
39
+
40
+ # Colors
41
+ RED='\033[0;31m'
42
+ GREEN='\033[0;32m'
43
+ YELLOW='\033[1;33m'
44
+ BLUE='\033[0;34m'
45
+ CYAN='\033[0;36m'
46
+ NC='\033[0m'
47
+
48
+ REPO_ROOT=$(get_repo_root)
49
+
50
+ # Platform (claude | cursor), can be overridden via --platform flag
51
+ PLATFORM="claude"
52
+
53
+ # Get command file path based on platform
54
+ # Claude: .claude/commands/trellis/<name>.md
55
+ # Cursor: .cursor/commands/trellis-<name>.md
56
+ get_command_path() {
57
+ local name="$1"
58
+ if [[ "$PLATFORM" == "cursor" ]]; then
59
+ echo ".cursor/commands/trellis-${name}.md"
60
+ else
61
+ echo ".claude/commands/trellis/${name}.md"
62
+ fi
63
+ }
64
+
65
+ # =============================================================================
66
+ # Helper Functions
67
+ # =============================================================================
68
+
69
+ # Convert title to slug (only works with ASCII)
70
+ _slugify() {
71
+ local result=$(echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//' | sed 's/-$//')
72
+ echo "$result"
73
+ }
74
+
75
+ # =============================================================================
76
+ # jsonl Default Content Generators
77
+ # =============================================================================
78
+
79
+ get_implement_base() {
80
+ cat << EOF
81
+ {"file": "$DIR_WORKFLOW/workflow.md", "reason": "Project workflow and conventions"}
82
+ {"file": "$DIR_WORKFLOW/$DIR_SPEC/shared/index.md", "reason": "Shared coding standards"}
83
+ EOF
84
+ }
85
+
86
+ get_implement_backend() {
87
+ cat << EOF
88
+ {"file": "$DIR_WORKFLOW/$DIR_SPEC/backend/index.md", "reason": "Backend development guide"}
89
+ {"file": "$DIR_WORKFLOW/$DIR_SPEC/backend/api-module.md", "reason": "API module conventions"}
90
+ {"file": "$DIR_WORKFLOW/$DIR_SPEC/backend/quality.md", "reason": "Code quality requirements"}
91
+ EOF
92
+ }
93
+
94
+ get_implement_frontend() {
95
+ cat << EOF
96
+ {"file": "$DIR_WORKFLOW/$DIR_SPEC/frontend/index.md", "reason": "Frontend development guide"}
97
+ {"file": "$DIR_WORKFLOW/$DIR_SPEC/frontend/components.md", "reason": "Component conventions"}
98
+ EOF
99
+ }
100
+
101
+ get_check_context() {
102
+ local dev_type="$1"
103
+ local finish_work=$(get_command_path "finish-work")
104
+ local check_backend=$(get_command_path "check-backend")
105
+ local check_frontend=$(get_command_path "check-frontend")
106
+
107
+ cat << EOF
108
+ {"file": "${finish_work}", "reason": "Finish work checklist"}
109
+ {"file": "$DIR_WORKFLOW/$DIR_SPEC/shared/index.md", "reason": "Shared coding standards"}
110
+ EOF
111
+
112
+ if [[ "$dev_type" == "backend" ]] || [[ "$dev_type" == "fullstack" ]]; then
113
+ echo "{\"file\": \"${check_backend}\", \"reason\": \"Backend check spec\"}"
114
+ fi
115
+ if [[ "$dev_type" == "frontend" ]] || [[ "$dev_type" == "fullstack" ]]; then
116
+ echo "{\"file\": \"${check_frontend}\", \"reason\": \"Frontend check spec\"}"
117
+ fi
118
+ }
119
+
120
+ get_debug_context() {
121
+ local dev_type="$1"
122
+ local check_backend=$(get_command_path "check-backend")
123
+ local check_frontend=$(get_command_path "check-frontend")
124
+
125
+ echo "{\"file\": \"$DIR_WORKFLOW/$DIR_SPEC/shared/index.md\", \"reason\": \"Shared coding standards\"}"
126
+
127
+ if [[ "$dev_type" == "backend" ]] || [[ "$dev_type" == "fullstack" ]]; then
128
+ echo "{\"file\": \"${check_backend}\", \"reason\": \"Backend check spec\"}"
129
+ fi
130
+ if [[ "$dev_type" == "frontend" ]] || [[ "$dev_type" == "fullstack" ]]; then
131
+ echo "{\"file\": \"${check_frontend}\", \"reason\": \"Frontend check spec\"}"
132
+ fi
133
+ }
134
+
135
+ # =============================================================================
136
+ # Task Operations
137
+ # =============================================================================
138
+
139
+ ensure_tasks_dir() {
140
+ local tasks_dir=$(get_tasks_dir)
141
+ local archive_dir="$tasks_dir/archive"
142
+
143
+ if [[ ! -d "$tasks_dir" ]]; then
144
+ mkdir -p "$tasks_dir"
145
+ echo -e "${GREEN}Created tasks directory: $tasks_dir${NC}" >&2
146
+ fi
147
+
148
+ if [[ ! -d "$archive_dir" ]]; then
149
+ mkdir -p "$archive_dir"
150
+ fi
151
+ }
152
+
153
+ # =============================================================================
154
+ # Command: create
155
+ # =============================================================================
156
+
157
+ cmd_create() {
158
+ local title=""
159
+ local assignee=""
160
+ local priority="P2"
161
+ local slug=""
162
+ local description=""
163
+
164
+ # Parse arguments
165
+ while [[ $# -gt 0 ]]; do
166
+ case "$1" in
167
+ --assignee|-a)
168
+ assignee="$2"
169
+ shift 2
170
+ ;;
171
+ --priority|-p)
172
+ priority="$2"
173
+ shift 2
174
+ ;;
175
+ --slug|-s)
176
+ slug="$2"
177
+ shift 2
178
+ ;;
179
+ --description|-d)
180
+ description="$2"
181
+ shift 2
182
+ ;;
183
+ -*)
184
+ echo -e "${RED}Error: Unknown option $1${NC}" >&2
185
+ exit 1
186
+ ;;
187
+ *)
188
+ if [[ -z "$title" ]]; then
189
+ title="$1"
190
+ fi
191
+ shift
192
+ ;;
193
+ esac
194
+ done
195
+
196
+ # Validate required fields
197
+ if [[ -z "$title" ]]; then
198
+ echo -e "${RED}Error: title is required${NC}" >&2
199
+ echo "Usage: $0 create <title> [--assignee <dev>] [--priority P0|P1|P2|P3] [--slug <slug>]" >&2
200
+ exit 1
201
+ fi
202
+
203
+ # Default assignee to current developer
204
+ if [[ -z "$assignee" ]]; then
205
+ assignee=$(get_developer "$REPO_ROOT")
206
+ if [[ -z "$assignee" ]]; then
207
+ echo -e "${RED}Error: No developer set. Run init-developer.sh first or use --assignee${NC}" >&2
208
+ exit 1
209
+ fi
210
+ fi
211
+
212
+ ensure_tasks_dir
213
+
214
+ # Get current developer as creator
215
+ local creator=$(get_developer "$REPO_ROOT")
216
+ if [[ -z "$creator" ]]; then
217
+ creator="$assignee"
218
+ fi
219
+
220
+ # Generate slug if not provided
221
+ if [[ -z "$slug" ]]; then
222
+ slug=$(_slugify "$title")
223
+ fi
224
+
225
+ # Validate slug
226
+ if [[ -z "$slug" ]]; then
227
+ echo -e "${RED}Error: could not generate slug from title${NC}" >&2
228
+ exit 1
229
+ fi
230
+
231
+ # Create task directory with MM-DD-slug format
232
+ local tasks_dir=$(get_tasks_dir)
233
+ local date_prefix=$(generate_task_date_prefix)
234
+ local dir_name="${date_prefix}-${slug}"
235
+ local task_dir="$tasks_dir/$dir_name"
236
+ local task_json="$task_dir/$FILE_TASK_JSON"
237
+
238
+ if [[ -d "$task_dir" ]]; then
239
+ echo -e "${YELLOW}Warning: Task directory already exists: $dir_name${NC}" >&2
240
+ else
241
+ mkdir -p "$task_dir"
242
+ fi
243
+
244
+ local today=$(date +%Y-%m-%d)
245
+ # Record current branch as base_branch (PR target)
246
+ local current_branch=$(git branch --show-current 2>/dev/null || echo "main")
247
+
248
+ cat > "$task_json" << EOF
249
+ {
250
+ "id": "$slug",
251
+ "name": "$slug",
252
+ "title": "$title",
253
+ "description": "$description",
254
+ "status": "planning",
255
+ "dev_type": null,
256
+ "scope": null,
257
+ "priority": "$priority",
258
+ "creator": "$creator",
259
+ "assignee": "$assignee",
260
+ "createdAt": "$today",
261
+ "completedAt": null,
262
+ "branch": null,
263
+ "base_branch": "$current_branch",
264
+ "worktree_path": null,
265
+ "current_phase": 0,
266
+ "next_action": [
267
+ {"phase": 1, "action": "implement"},
268
+ {"phase": 2, "action": "check"},
269
+ {"phase": 3, "action": "finish"},
270
+ {"phase": 4, "action": "create-pr"}
271
+ ],
272
+ "commit": null,
273
+ "pr_url": null,
274
+ "subtasks": [],
275
+ "relatedFiles": [],
276
+ "notes": ""
277
+ }
278
+ EOF
279
+
280
+ echo -e "${GREEN}Created task: $dir_name${NC}" >&2
281
+ echo -e "" >&2
282
+ echo -e "${BLUE}Next steps:${NC}" >&2
283
+ echo -e " 1. Create prd.md with requirements" >&2
284
+ echo -e " 2. Run: $0 init-context <dir> <dev_type>" >&2
285
+ echo -e " 3. Run: $0 start <dir>" >&2
286
+ echo "" >&2
287
+
288
+ # Output relative path for script chaining
289
+ echo "$DIR_WORKFLOW/$DIR_TASKS/$dir_name"
290
+ }
291
+
292
+ # =============================================================================
293
+ # Command: init-context
294
+ # =============================================================================
295
+
296
+ cmd_init_context() {
297
+ local target_dir=""
298
+ local dev_type=""
299
+
300
+ # Parse arguments
301
+ while [[ $# -gt 0 ]]; do
302
+ case "$1" in
303
+ --platform)
304
+ PLATFORM="$2"
305
+ shift 2
306
+ ;;
307
+ -*)
308
+ echo -e "${RED}Error: Unknown option $1${NC}"
309
+ exit 1
310
+ ;;
311
+ *)
312
+ if [[ -z "$target_dir" ]]; then
313
+ target_dir="$1"
314
+ elif [[ -z "$dev_type" ]]; then
315
+ dev_type="$1"
316
+ fi
317
+ shift
318
+ ;;
319
+ esac
320
+ done
321
+
322
+ if [[ -z "$target_dir" ]] || [[ -z "$dev_type" ]]; then
323
+ echo -e "${RED}Error: Missing arguments${NC}"
324
+ echo "Usage: $0 init-context <task-dir> <dev_type> [--platform claude|cursor]"
325
+ echo " dev_type: backend | frontend | fullstack | test | docs"
326
+ echo " --platform: claude (default) | cursor"
327
+ exit 1
328
+ fi
329
+
330
+ # Support relative paths
331
+ if [[ ! "$target_dir" = /* ]]; then
332
+ target_dir="$REPO_ROOT/$target_dir"
333
+ fi
334
+
335
+ if [[ ! -d "$target_dir" ]]; then
336
+ echo -e "${RED}Error: Directory not found: $target_dir${NC}"
337
+ exit 1
338
+ fi
339
+
340
+ echo -e "${BLUE}=== Initializing Agent Context Files ===${NC}"
341
+ echo -e "Target dir: $target_dir"
342
+ echo -e "Dev type: $dev_type"
343
+ echo ""
344
+
345
+ # implement.jsonl
346
+ echo -e "${CYAN}Creating implement.jsonl...${NC}"
347
+ local implement_file="$target_dir/implement.jsonl"
348
+ {
349
+ get_implement_base
350
+ case "$dev_type" in
351
+ backend|test) get_implement_backend ;;
352
+ frontend) get_implement_frontend ;;
353
+ fullstack)
354
+ get_implement_backend
355
+ get_implement_frontend
356
+ ;;
357
+ esac
358
+ } > "$implement_file"
359
+ echo -e " ${GREEN}✓${NC} $(wc -l < "$implement_file" | tr -d ' ') entries"
360
+
361
+ # check.jsonl
362
+ echo -e "${CYAN}Creating check.jsonl...${NC}"
363
+ local check_file="$target_dir/check.jsonl"
364
+ get_check_context "$dev_type" > "$check_file"
365
+ echo -e " ${GREEN}✓${NC} $(wc -l < "$check_file" | tr -d ' ') entries"
366
+
367
+ # debug.jsonl
368
+ echo -e "${CYAN}Creating debug.jsonl...${NC}"
369
+ local debug_file="$target_dir/debug.jsonl"
370
+ get_debug_context "$dev_type" > "$debug_file"
371
+ echo -e " ${GREEN}✓${NC} $(wc -l < "$debug_file" | tr -d ' ') entries"
372
+
373
+ echo ""
374
+ echo -e "${GREEN}✓ All context files created${NC}"
375
+ echo -e ""
376
+ echo -e "${BLUE}Next steps:${NC}"
377
+ echo -e " 1. Add task-specific specs: $0 add-context <dir> <jsonl> <path>"
378
+ echo -e " 2. Set as current: $0 start <dir>"
379
+ }
380
+
381
+ # =============================================================================
382
+ # Command: add-context
383
+ # =============================================================================
384
+
385
+ cmd_add_context() {
386
+ local target_dir="$1"
387
+ local jsonl_name="$2"
388
+ local path="$3"
389
+ local reason="${4:-Added manually}"
390
+
391
+ if [[ -z "$target_dir" ]] || [[ -z "$jsonl_name" ]] || [[ -z "$path" ]]; then
392
+ echo -e "${RED}Error: Missing arguments${NC}"
393
+ echo "Usage: $0 add-context <task-dir> <jsonl-file> <path> [reason]"
394
+ echo " jsonl-file: implement | check | debug (or full filename)"
395
+ exit 1
396
+ fi
397
+
398
+ # Support relative paths
399
+ if [[ ! "$target_dir" = /* ]]; then
400
+ target_dir="$REPO_ROOT/$target_dir"
401
+ fi
402
+
403
+ # Support shorthand
404
+ if [[ "$jsonl_name" != *.jsonl ]]; then
405
+ jsonl_name="${jsonl_name}.jsonl"
406
+ fi
407
+
408
+ local jsonl_file="$target_dir/$jsonl_name"
409
+ local full_path="$REPO_ROOT/$path"
410
+ local entry_type="file"
411
+
412
+ if [[ -d "$full_path" ]]; then
413
+ entry_type="directory"
414
+ [[ "$path" != */ ]] && path="$path/"
415
+ elif [[ ! -f "$full_path" ]]; then
416
+ echo -e "${RED}Error: Path not found: $path${NC}"
417
+ exit 1
418
+ fi
419
+
420
+ # Check if already exists
421
+ if [[ -f "$jsonl_file" ]] && grep -q "\"$path\"" "$jsonl_file" 2>/dev/null; then
422
+ echo -e "${YELLOW}Warning: Entry already exists for $path${NC}"
423
+ exit 0
424
+ fi
425
+
426
+ # Add entry
427
+ if [[ "$entry_type" == "directory" ]]; then
428
+ echo "{\"file\": \"$path\", \"type\": \"directory\", \"reason\": \"$reason\"}" >> "$jsonl_file"
429
+ else
430
+ echo "{\"file\": \"$path\", \"reason\": \"$reason\"}" >> "$jsonl_file"
431
+ fi
432
+
433
+ echo -e "${GREEN}Added $entry_type: $path${NC}"
434
+ }
435
+
436
+ # =============================================================================
437
+ # Command: validate
438
+ # =============================================================================
439
+
440
+ validate_jsonl() {
441
+ local jsonl_file="$1"
442
+ local file_name=$(basename "$jsonl_file")
443
+ local errors=0
444
+ local line_num=0
445
+
446
+ if [[ ! -f "$jsonl_file" ]]; then
447
+ echo -e " ${YELLOW}$file_name: not found (skipped)${NC}"
448
+ return 0
449
+ fi
450
+
451
+ while IFS= read -r line || [[ -n "$line" ]]; do
452
+ line_num=$((line_num + 1))
453
+ [[ -z "$line" ]] && continue
454
+
455
+ if ! echo "$line" | jq -e . > /dev/null 2>&1; then
456
+ echo -e " ${RED}$file_name:$line_num: Invalid JSON${NC}"
457
+ errors=$((errors + 1))
458
+ continue
459
+ fi
460
+
461
+ local file_path=$(echo "$line" | jq -r '.file // empty')
462
+ local entry_type=$(echo "$line" | jq -r '.type // "file"')
463
+
464
+ if [[ -z "$file_path" ]]; then
465
+ echo -e " ${RED}$file_name:$line_num: Missing 'file' field${NC}"
466
+ errors=$((errors + 1))
467
+ continue
468
+ fi
469
+
470
+ local full_path="$REPO_ROOT/$file_path"
471
+ if [[ "$entry_type" == "directory" ]]; then
472
+ if [[ ! -d "$full_path" ]]; then
473
+ echo -e " ${RED}$file_name:$line_num: Directory not found: $file_path${NC}"
474
+ errors=$((errors + 1))
475
+ fi
476
+ else
477
+ if [[ ! -f "$full_path" ]]; then
478
+ echo -e " ${RED}$file_name:$line_num: File not found: $file_path${NC}"
479
+ errors=$((errors + 1))
480
+ fi
481
+ fi
482
+ done < "$jsonl_file"
483
+
484
+ if [[ $errors -eq 0 ]]; then
485
+ echo -e " ${GREEN}$file_name: ✓ ($line_num entries)${NC}"
486
+ else
487
+ echo -e " ${RED}$file_name: ✗ ($errors errors)${NC}"
488
+ fi
489
+
490
+ return $errors
491
+ }
492
+
493
+ cmd_validate() {
494
+ local target_dir="$1"
495
+
496
+ if [[ -z "$target_dir" ]]; then
497
+ echo -e "${RED}Error: task directory required${NC}"
498
+ exit 1
499
+ fi
500
+
501
+ if [[ ! "$target_dir" = /* ]]; then
502
+ target_dir="$REPO_ROOT/$target_dir"
503
+ fi
504
+
505
+ echo -e "${BLUE}=== Validating Context Files ===${NC}"
506
+ echo -e "Target dir: $target_dir"
507
+ echo ""
508
+
509
+ local total_errors=0
510
+ for jsonl_file in "$target_dir"/{implement,check,debug}.jsonl; do
511
+ validate_jsonl "$jsonl_file"
512
+ total_errors=$((total_errors + $?))
513
+ done
514
+
515
+ echo ""
516
+ if [[ $total_errors -eq 0 ]]; then
517
+ echo -e "${GREEN}✓ All validations passed${NC}"
518
+ else
519
+ echo -e "${RED}✗ Validation failed ($total_errors errors)${NC}"
520
+ exit 1
521
+ fi
522
+ }
523
+
524
+ # =============================================================================
525
+ # Command: list-context
526
+ # =============================================================================
527
+
528
+ cmd_list_context() {
529
+ local target_dir="$1"
530
+
531
+ if [[ -z "$target_dir" ]]; then
532
+ echo -e "${RED}Error: task directory required${NC}"
533
+ exit 1
534
+ fi
535
+
536
+ if [[ ! "$target_dir" = /* ]]; then
537
+ target_dir="$REPO_ROOT/$target_dir"
538
+ fi
539
+
540
+ echo -e "${BLUE}=== Context Files ===${NC}"
541
+ echo ""
542
+
543
+ for jsonl_file in "$target_dir"/{implement,check,debug}.jsonl; do
544
+ local file_name=$(basename "$jsonl_file")
545
+ [[ ! -f "$jsonl_file" ]] && continue
546
+
547
+ echo -e "${CYAN}[$file_name]${NC}"
548
+
549
+ local count=0
550
+ while IFS= read -r line || [[ -n "$line" ]]; do
551
+ [[ -z "$line" ]] && continue
552
+
553
+ local file_path=$(echo "$line" | jq -r '.file // "?"')
554
+ local entry_type=$(echo "$line" | jq -r '.type // "file"')
555
+ local reason=$(echo "$line" | jq -r '.reason // "-"')
556
+ count=$((count + 1))
557
+
558
+ if [[ "$entry_type" == "directory" ]]; then
559
+ echo -e " ${GREEN}$count.${NC} [DIR] $file_path"
560
+ else
561
+ echo -e " ${GREEN}$count.${NC} $file_path"
562
+ fi
563
+ echo -e " ${YELLOW}→${NC} $reason"
564
+ done < "$jsonl_file"
565
+
566
+ echo ""
567
+ done
568
+ }
569
+
570
+ # =============================================================================
571
+ # Command: start / finish
572
+ # =============================================================================
573
+
574
+ cmd_start() {
575
+ local task_dir="$1"
576
+
577
+ if [[ -z "$task_dir" ]]; then
578
+ echo -e "${RED}Error: task directory required${NC}"
579
+ exit 1
580
+ fi
581
+
582
+ # Convert to relative path
583
+ if [[ "$task_dir" = /* ]]; then
584
+ task_dir="${task_dir#$REPO_ROOT/}"
585
+ fi
586
+
587
+ # Verify directory exists
588
+ if [[ ! -d "$REPO_ROOT/$task_dir" ]]; then
589
+ echo -e "${RED}Error: Task directory not found: $task_dir${NC}"
590
+ exit 1
591
+ fi
592
+
593
+ set_current_task "$task_dir"
594
+ echo -e "${GREEN}✓ Current task set to: $task_dir${NC}"
595
+ echo ""
596
+ echo -e "${BLUE}The hook will now inject context from this task's jsonl files.${NC}"
597
+ }
598
+
599
+ cmd_finish() {
600
+ local current=$(get_current_task)
601
+
602
+ if [[ -z "$current" ]]; then
603
+ echo -e "${YELLOW}No current task set${NC}"
604
+ exit 0
605
+ fi
606
+
607
+ clear_current_task
608
+ echo -e "${GREEN}✓ Cleared current task (was: $current)${NC}"
609
+ }
610
+
611
+ # =============================================================================
612
+ # Command: archive
613
+ # =============================================================================
614
+
615
+ cmd_archive() {
616
+ local task_name="$1"
617
+
618
+ if [[ -z "$task_name" ]]; then
619
+ echo -e "${RED}Error: Task name is required${NC}" >&2
620
+ echo "Usage: $0 archive <task-name>" >&2
621
+ exit 1
622
+ fi
623
+
624
+ local tasks_dir=$(get_tasks_dir)
625
+
626
+ # Find task directory using common function
627
+ local task_dir=$(find_task_by_name "$task_name" "$tasks_dir")
628
+
629
+ if [[ -z "$task_dir" ]] || [[ ! -d "$task_dir" ]]; then
630
+ echo -e "${RED}Error: Task not found: $task_name${NC}" >&2
631
+ echo "Active tasks:" >&2
632
+ cmd_list >&2
633
+ exit 1
634
+ fi
635
+
636
+ local dir_name=$(basename "$task_dir")
637
+ local task_json="$task_dir/$FILE_TASK_JSON"
638
+
639
+ # Update status before archiving
640
+ local today=$(date +%Y-%m-%d)
641
+ if [[ -f "$task_json" ]] && command -v jq &> /dev/null; then
642
+ local temp_file=$(mktemp)
643
+ jq --arg date "$today" '.status = "completed" | .completedAt = $date' "$task_json" > "$temp_file"
644
+ mv "$temp_file" "$task_json"
645
+ fi
646
+
647
+ # Clear if current task
648
+ local current=$(get_current_task)
649
+ if [[ "$current" == *"$dir_name"* ]]; then
650
+ clear_current_task
651
+ fi
652
+
653
+ # Use common archive function
654
+ local result=$(archive_task_complete "$task_dir" "$REPO_ROOT")
655
+ local archive_dest=""
656
+
657
+ echo "$result" | while IFS= read -r line; do
658
+ case "$line" in
659
+ archived_to:*)
660
+ archive_dest="${line#archived_to:}"
661
+ local year_month=$(basename "$(dirname "$archive_dest")")
662
+ echo -e "${GREEN}Archived: $dir_name -> archive/$year_month/${NC}" >&2
663
+ ;;
664
+ esac
665
+ done
666
+
667
+ # Return the archive path
668
+ local year_month=$(date +%Y-%m)
669
+ echo "$DIR_WORKFLOW/$DIR_TASKS/$DIR_ARCHIVE/$year_month/$dir_name"
670
+ }
671
+
672
+ # =============================================================================
673
+ # Command: list
674
+ # =============================================================================
675
+
676
+ cmd_list() {
677
+ local filter_mine=false
678
+ local filter_status=""
679
+
680
+ # Parse arguments
681
+ while [[ $# -gt 0 ]]; do
682
+ case "$1" in
683
+ --mine|-m)
684
+ filter_mine=true
685
+ shift
686
+ ;;
687
+ --status|-s)
688
+ filter_status="$2"
689
+ shift 2
690
+ ;;
691
+ *)
692
+ shift
693
+ ;;
694
+ esac
695
+ done
696
+
697
+ local tasks_dir=$(get_tasks_dir)
698
+ local current_task=$(get_current_task)
699
+ local developer=$(get_developer "$REPO_ROOT")
700
+
701
+ if [[ "$filter_mine" == "true" ]]; then
702
+ if [[ -z "$developer" ]]; then
703
+ echo -e "${RED}Error: No developer set. Run init-developer.sh first${NC}" >&2
704
+ exit 1
705
+ fi
706
+ echo -e "${BLUE}My tasks (assignee: $developer):${NC}"
707
+ else
708
+ echo -e "${BLUE}All active tasks:${NC}"
709
+ fi
710
+ echo ""
711
+
712
+ local count=0
713
+
714
+ for d in "$tasks_dir"/*/; do
715
+ if [[ -d "$d" ]] && [[ "$(basename "$d")" != "archive" ]]; then
716
+ local dir_name=$(basename "$d")
717
+ local task_json="$d/$FILE_TASK_JSON"
718
+ local status="unknown"
719
+ local assignee="-"
720
+ local relative_path="$DIR_WORKFLOW/$DIR_TASKS/$dir_name"
721
+
722
+ if [[ -f "$task_json" ]] && command -v jq &> /dev/null; then
723
+ status=$(jq -r '.status // "unknown"' "$task_json")
724
+ assignee=$(jq -r '.assignee // "-"' "$task_json")
725
+ fi
726
+
727
+ # Apply --mine filter
728
+ if [[ "$filter_mine" == "true" ]] && [[ "$assignee" != "$developer" ]]; then
729
+ continue
730
+ fi
731
+
732
+ # Apply --status filter
733
+ if [[ -n "$filter_status" ]] && [[ "$status" != "$filter_status" ]]; then
734
+ continue
735
+ fi
736
+
737
+ local marker=""
738
+ if [[ "$relative_path" == "$current_task" ]]; then
739
+ marker=" ${GREEN}<- current${NC}"
740
+ fi
741
+
742
+ if [[ "$filter_mine" == "true" ]]; then
743
+ echo -e " - $dir_name/ ($status)$marker"
744
+ else
745
+ echo -e " - $dir_name/ ($status) [${CYAN}$assignee${NC}]$marker"
746
+ fi
747
+ ((count++))
748
+ fi
749
+ done
750
+
751
+ if [[ $count -eq 0 ]]; then
752
+ if [[ "$filter_mine" == "true" ]]; then
753
+ echo " (no tasks assigned to you)"
754
+ else
755
+ echo " (no active tasks)"
756
+ fi
757
+ fi
758
+
759
+ echo ""
760
+ echo "Total: $count task(s)"
761
+ }
762
+
763
+ # =============================================================================
764
+ # Command: list-archive
765
+ # =============================================================================
766
+
767
+ cmd_list_archive() {
768
+ local month="$1"
769
+
770
+ local tasks_dir=$(get_tasks_dir)
771
+ local archive_dir="$tasks_dir/archive"
772
+
773
+ echo -e "${BLUE}Archived tasks:${NC}"
774
+ echo ""
775
+
776
+ if [[ -n "$month" ]]; then
777
+ local month_dir="$archive_dir/$month"
778
+ if [[ -d "$month_dir" ]]; then
779
+ echo "[$month]"
780
+ for d in "$month_dir"/*/; do
781
+ if [[ -d "$d" ]]; then
782
+ echo " - $(basename "$d")/"
783
+ fi
784
+ done
785
+ else
786
+ echo " No archives for $month"
787
+ fi
788
+ else
789
+ for month_dir in "$archive_dir"/*/; do
790
+ if [[ -d "$month_dir" ]]; then
791
+ local month_name=$(basename "$month_dir")
792
+ local count=$(find "$month_dir" -maxdepth 1 -type d ! -name "$(basename "$month_dir")" | wc -l | tr -d ' ')
793
+ echo "[$month_name] - $count task(s)"
794
+ fi
795
+ done
796
+ fi
797
+ }
798
+
799
+ # =============================================================================
800
+ # Command: set-branch
801
+ # =============================================================================
802
+
803
+ cmd_set_branch() {
804
+ local target_dir="$1"
805
+ local branch="$2"
806
+
807
+ if [[ -z "$target_dir" ]] || [[ -z "$branch" ]]; then
808
+ echo -e "${RED}Error: Missing arguments${NC}"
809
+ echo "Usage: $0 set-branch <task-dir> <branch-name>"
810
+ echo "Example: $0 set-branch <dir> task/my-task"
811
+ exit 1
812
+ fi
813
+
814
+ # Support relative paths
815
+ if [[ ! "$target_dir" = /* ]]; then
816
+ target_dir="$REPO_ROOT/$target_dir"
817
+ fi
818
+
819
+ local task_json="$target_dir/$FILE_TASK_JSON"
820
+ if [[ ! -f "$task_json" ]]; then
821
+ echo -e "${RED}Error: task.json not found at $target_dir${NC}"
822
+ exit 1
823
+ fi
824
+
825
+ # Update branch field
826
+ jq --arg branch "$branch" '.branch = $branch' "$task_json" > "${task_json}.tmp"
827
+ mv "${task_json}.tmp" "$task_json"
828
+
829
+ echo -e "${GREEN}✓ Branch set to: $branch${NC}"
830
+ echo ""
831
+ echo -e "${BLUE}Now you can start the multi-agent pipeline:${NC}"
832
+ echo " ./.trellis/scripts/multi-agent/start.sh $1"
833
+ }
834
+
835
+ # =============================================================================
836
+ # Command: set-base-branch
837
+ # =============================================================================
838
+
839
+ cmd_set_base_branch() {
840
+ local target_dir="$1"
841
+ local base_branch="$2"
842
+
843
+ if [[ -z "$target_dir" ]] || [[ -z "$base_branch" ]]; then
844
+ echo -e "${RED}Error: Missing arguments${NC}"
845
+ echo "Usage: $0 set-base-branch <task-dir> <base-branch>"
846
+ echo "Example: $0 set-base-branch <dir> develop"
847
+ echo ""
848
+ echo "This sets the target branch for PR (the branch your feature will merge into)."
849
+ exit 1
850
+ fi
851
+
852
+ # Support relative paths
853
+ if [[ ! "$target_dir" = /* ]]; then
854
+ target_dir="$REPO_ROOT/$target_dir"
855
+ fi
856
+
857
+ local task_json="$target_dir/$FILE_TASK_JSON"
858
+ if [[ ! -f "$task_json" ]]; then
859
+ echo -e "${RED}Error: task.json not found at $target_dir${NC}"
860
+ exit 1
861
+ fi
862
+
863
+ # Update base_branch field
864
+ jq --arg base "$base_branch" '.base_branch = $base' "$task_json" > "${task_json}.tmp"
865
+ mv "${task_json}.tmp" "$task_json"
866
+
867
+ echo -e "${GREEN}✓ Base branch set to: $base_branch${NC}"
868
+ echo -e " PR will target: $base_branch"
869
+ }
870
+
871
+ # =============================================================================
872
+ # Command: set-scope
873
+ # =============================================================================
874
+
875
+ cmd_set_scope() {
876
+ local target_dir="$1"
877
+ local scope="$2"
878
+
879
+ if [[ -z "$target_dir" ]] || [[ -z "$scope" ]]; then
880
+ echo -e "${RED}Error: Missing arguments${NC}"
881
+ echo "Usage: $0 set-scope <task-dir> <scope>"
882
+ echo "Example: $0 set-scope <dir> api"
883
+ exit 1
884
+ fi
885
+
886
+ # Support relative paths
887
+ if [[ ! "$target_dir" = /* ]]; then
888
+ target_dir="$REPO_ROOT/$target_dir"
889
+ fi
890
+
891
+ local task_json="$target_dir/$FILE_TASK_JSON"
892
+ if [[ ! -f "$task_json" ]]; then
893
+ echo -e "${RED}Error: task.json not found at $target_dir${NC}"
894
+ exit 1
895
+ fi
896
+
897
+ # Update scope field
898
+ jq --arg scope "$scope" '.scope = $scope' "$task_json" > "${task_json}.tmp"
899
+ mv "${task_json}.tmp" "$task_json"
900
+
901
+ echo -e "${GREEN}✓ Scope set to: $scope${NC}"
902
+ }
903
+
904
+ # =============================================================================
905
+ # Command: create-pr
906
+ # =============================================================================
907
+
908
+ cmd_create_pr() {
909
+ local target_dir=""
910
+ local dry_run=false
911
+
912
+ # Parse arguments
913
+ while [[ $# -gt 0 ]]; do
914
+ case "$1" in
915
+ --dry-run)
916
+ dry_run=true
917
+ shift
918
+ ;;
919
+ *)
920
+ if [[ -z "$target_dir" ]]; then
921
+ target_dir="$1"
922
+ fi
923
+ shift
924
+ ;;
925
+ esac
926
+ done
927
+
928
+ # Get task directory
929
+ if [[ -z "$target_dir" ]]; then
930
+ target_dir=$(get_current_task)
931
+ if [[ -z "$target_dir" ]]; then
932
+ echo -e "${RED}Error: No task directory specified and no current task set${NC}"
933
+ echo "Usage: $0 create-pr [task-dir] [--dry-run]"
934
+ exit 1
935
+ fi
936
+ fi
937
+
938
+ # Support relative paths
939
+ if [[ ! "$target_dir" = /* ]]; then
940
+ target_dir="$REPO_ROOT/$target_dir"
941
+ fi
942
+
943
+ local task_json="$target_dir/$FILE_TASK_JSON"
944
+ if [[ ! -f "$task_json" ]]; then
945
+ echo -e "${RED}Error: task.json not found at $target_dir${NC}"
946
+ exit 1
947
+ fi
948
+
949
+ echo -e "${BLUE}=== Create PR ===${NC}"
950
+ if [[ "$dry_run" == "true" ]]; then
951
+ echo -e "${YELLOW}[DRY-RUN MODE] No actual changes will be made${NC}"
952
+ fi
953
+ echo ""
954
+
955
+ # Read task config
956
+ local task_name=$(jq -r '.name' "$task_json")
957
+ local base_branch=$(jq -r '.base_branch // "main"' "$task_json")
958
+ local scope=$(jq -r '.scope // "core"' "$task_json")
959
+ local dev_type=$(jq -r '.dev_type // "feature"' "$task_json")
960
+
961
+ # Map dev_type to commit prefix
962
+ local commit_prefix
963
+ case "$dev_type" in
964
+ feature|frontend|backend|fullstack) commit_prefix="feat" ;;
965
+ bugfix|fix) commit_prefix="fix" ;;
966
+ refactor) commit_prefix="refactor" ;;
967
+ docs) commit_prefix="docs" ;;
968
+ test) commit_prefix="test" ;;
969
+ *) commit_prefix="feat" ;;
970
+ esac
971
+
972
+ echo -e "Task: ${task_name}"
973
+ echo -e "Base branch: ${base_branch}"
974
+ echo -e "Scope: ${scope}"
975
+ echo -e "Commit prefix: ${commit_prefix}"
976
+ echo ""
977
+
978
+ # Get current branch
979
+ local current_branch=$(git branch --show-current)
980
+ echo -e "Current branch: ${current_branch}"
981
+
982
+ # Check for changes
983
+ echo -e "${YELLOW}Checking for changes...${NC}"
984
+
985
+ # Stage changes (even in dry-run to detect what would be committed)
986
+ git add -A
987
+ # Exclude workspace and temp files
988
+ git reset "$DIR_WORKFLOW/$DIR_WORKSPACE/" 2>/dev/null || true
989
+ git reset .agent-log .agent-runner.sh 2>/dev/null || true
990
+
991
+ # Check if there are staged changes
992
+ if git diff --cached --quiet 2>/dev/null; then
993
+ echo -e "${YELLOW}No staged changes to commit${NC}"
994
+
995
+ # Check for unpushed commits
996
+ local unpushed=$(git log "origin/${current_branch}..HEAD" --oneline 2>/dev/null | wc -l | tr -d ' ' || echo "0")
997
+ if [[ "$unpushed" -eq 0 ]] 2>/dev/null; then
998
+ # In dry-run, also reset the staging
999
+ if [[ "$dry_run" == "true" ]]; then
1000
+ git reset HEAD >/dev/null 2>&1 || true
1001
+ fi
1002
+ echo -e "${RED}No changes to create PR${NC}"
1003
+ exit 1
1004
+ fi
1005
+ echo -e "Found ${unpushed} unpushed commit(s)"
1006
+ else
1007
+ # Commit changes
1008
+ echo -e "${YELLOW}Committing changes...${NC}"
1009
+ local commit_msg="${commit_prefix}(${scope}): ${task_name}"
1010
+
1011
+ if [[ "$dry_run" == "true" ]]; then
1012
+ echo -e "[DRY-RUN] Would commit with message: ${commit_msg}"
1013
+ echo -e "[DRY-RUN] Staged files:"
1014
+ git diff --cached --name-only | sed 's/^/ - /'
1015
+ else
1016
+ git commit -m "$commit_msg"
1017
+ echo -e "${GREEN}Committed: ${commit_msg}${NC}"
1018
+ fi
1019
+ fi
1020
+
1021
+ # Push to remote
1022
+ echo -e "${YELLOW}Pushing to remote...${NC}"
1023
+ if [[ "$dry_run" == "true" ]]; then
1024
+ echo -e "[DRY-RUN] Would push to: origin/${current_branch}"
1025
+ else
1026
+ git push -u origin "$current_branch"
1027
+ echo -e "${GREEN}Pushed to origin/${current_branch}${NC}"
1028
+ fi
1029
+
1030
+ # Create PR
1031
+ echo -e "${YELLOW}Creating PR...${NC}"
1032
+ local pr_title="${commit_prefix}(${scope}): ${task_name}"
1033
+ local pr_url=""
1034
+
1035
+ if [[ "$dry_run" == "true" ]]; then
1036
+ echo -e "[DRY-RUN] Would create PR:"
1037
+ echo -e " Title: ${pr_title}"
1038
+ echo -e " Base: ${base_branch}"
1039
+ echo -e " Head: ${current_branch}"
1040
+ if [[ -f "$target_dir/prd.md" ]]; then
1041
+ echo -e " Body: (from prd.md)"
1042
+ fi
1043
+ pr_url="https://github.com/example/repo/pull/DRY-RUN"
1044
+ else
1045
+ # Check if PR already exists
1046
+ local existing_pr=$(gh pr list --head "$current_branch" --base "$base_branch" --json url --jq '.[0].url' 2>/dev/null || echo "")
1047
+
1048
+ if [[ -n "$existing_pr" ]]; then
1049
+ echo -e "${YELLOW}PR already exists: ${existing_pr}${NC}"
1050
+ pr_url="$existing_pr"
1051
+ else
1052
+ # Read PRD as PR body
1053
+ local pr_body=""
1054
+ if [[ -f "$target_dir/prd.md" ]]; then
1055
+ pr_body=$(cat "$target_dir/prd.md")
1056
+ fi
1057
+
1058
+ # Create PR
1059
+ pr_url=$(gh pr create \
1060
+ --draft \
1061
+ --base "$base_branch" \
1062
+ --title "$pr_title" \
1063
+ --body "$pr_body" \
1064
+ 2>&1)
1065
+
1066
+ echo -e "${GREEN}PR created: ${pr_url}${NC}"
1067
+ fi
1068
+ fi
1069
+
1070
+ # Update task.json
1071
+ echo -e "${YELLOW}Updating task status...${NC}"
1072
+ if [[ "$dry_run" == "true" ]]; then
1073
+ echo -e "[DRY-RUN] Would update task.json:"
1074
+ echo -e " status: review"
1075
+ echo -e " pr_url: ${pr_url}"
1076
+ echo -e " current_phase: (set to create-pr phase)"
1077
+ else
1078
+ # Find the phase number for create-pr action
1079
+ local create_pr_phase=$(jq -r '.next_action[] | select(.action == "create-pr") | .phase // 4' "$task_json")
1080
+ jq --arg url "$pr_url" --argjson phase "$create_pr_phase" \
1081
+ '.status = "review" | .pr_url = $url | .current_phase = $phase' "$task_json" > "${task_json}.tmp"
1082
+ mv "${task_json}.tmp" "$task_json"
1083
+ echo -e "${GREEN}Task status updated to 'review', phase ${create_pr_phase}${NC}"
1084
+ fi
1085
+
1086
+ # In dry-run, reset the staging area
1087
+ if [[ "$dry_run" == "true" ]]; then
1088
+ git reset HEAD >/dev/null 2>&1 || true
1089
+ fi
1090
+
1091
+ echo ""
1092
+ echo -e "${GREEN}=== PR Created Successfully ===${NC}"
1093
+ echo -e "PR URL: ${pr_url}"
1094
+ echo -e "Target: ${base_branch}"
1095
+ echo -e "Source: ${current_branch}"
1096
+ }
1097
+
1098
+ # =============================================================================
1099
+ # Help
1100
+ # =============================================================================
1101
+
1102
+ show_usage() {
1103
+ cat << EOF
1104
+ Task Management Script for Multi-Agent Pipeline
1105
+
1106
+ Usage:
1107
+ $0 create <title> Create new task directory
1108
+ $0 init-context <dir> <type> [--platform claude|cursor] Initialize jsonl files
1109
+ $0 add-context <dir> <jsonl> <path> [reason] Add entry to jsonl
1110
+ $0 validate <dir> Validate jsonl files
1111
+ $0 list-context <dir> List jsonl entries
1112
+ $0 start <dir> Set as current task
1113
+ $0 finish Clear current task
1114
+ $0 set-branch <dir> <branch> Set git branch for multi-agent
1115
+ $0 set-scope <dir> <scope> Set scope for PR title
1116
+ $0 create-pr [dir] [--dry-run] Create PR from task
1117
+ $0 archive <task-name> Archive completed task
1118
+ $0 list [--mine] [--status <status>] List tasks
1119
+ $0 list-archive [YYYY-MM] List archived tasks
1120
+
1121
+ Arguments:
1122
+ dev_type: backend | frontend | fullstack | test | docs
1123
+
1124
+ List options:
1125
+ --mine, -m Show only tasks assigned to current developer
1126
+ --status, -s <s> Filter by status (planning, in_progress, review, completed)
1127
+
1128
+ Examples:
1129
+ $0 create "Add login feature" --slug add-login
1130
+ $0 init-context .trellis/tasks/01-21-add-login backend
1131
+ $0 init-context .trellis/tasks/01-21-add-login frontend --platform cursor
1132
+ $0 add-context <dir> implement .trellis/spec/backend/auth.md "Auth guidelines"
1133
+ $0 set-branch <dir> task/add-login
1134
+ $0 start .trellis/tasks/01-21-add-login
1135
+ $0 create-pr # Uses current task
1136
+ $0 create-pr <dir> --dry-run # Preview without changes
1137
+ $0 finish
1138
+ $0 archive add-login
1139
+ $0 list # List all active tasks
1140
+ $0 list --mine # List my tasks only
1141
+ $0 list --mine --status in_progress # List my in-progress tasks
1142
+ EOF
1143
+ }
1144
+
1145
+ # =============================================================================
1146
+ # Main Entry
1147
+ # =============================================================================
1148
+
1149
+ case "${1:-}" in
1150
+ create)
1151
+ shift
1152
+ cmd_create "$@"
1153
+ ;;
1154
+ init-context)
1155
+ shift
1156
+ cmd_init_context "$@"
1157
+ ;;
1158
+ add-context)
1159
+ cmd_add_context "$2" "$3" "$4" "$5"
1160
+ ;;
1161
+ validate)
1162
+ cmd_validate "$2"
1163
+ ;;
1164
+ list-context)
1165
+ cmd_list_context "$2"
1166
+ ;;
1167
+ start)
1168
+ cmd_start "$2"
1169
+ ;;
1170
+ finish)
1171
+ cmd_finish
1172
+ ;;
1173
+ set-branch)
1174
+ cmd_set_branch "$2" "$3"
1175
+ ;;
1176
+ set-base-branch)
1177
+ cmd_set_base_branch "$2" "$3"
1178
+ ;;
1179
+ set-scope)
1180
+ cmd_set_scope "$2" "$3"
1181
+ ;;
1182
+ create-pr)
1183
+ # Delegate to multi-agent/create-pr.sh
1184
+ shift
1185
+ "$SCRIPT_DIR/multi-agent/create-pr.sh" "$@"
1186
+ ;;
1187
+ archive)
1188
+ cmd_archive "$2"
1189
+ ;;
1190
+ list)
1191
+ shift
1192
+ cmd_list "$@"
1193
+ ;;
1194
+ list-archive)
1195
+ cmd_list_archive "$2"
1196
+ ;;
1197
+ -h|--help|help)
1198
+ show_usage
1199
+ ;;
1200
+ *)
1201
+ show_usage
1202
+ exit 1
1203
+ ;;
1204
+ esac