@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,329 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Multi-Agent Pipeline: Create PR.
4
+
5
+ Usage:
6
+ python3 create_pr.py [task-dir] [--dry-run]
7
+
8
+ This script:
9
+ 1. Stages and commits all changes (excluding workspace/)
10
+ 2. Pushes to origin
11
+ 3. Creates a Draft PR using `gh pr create`
12
+ 4. Updates task.json with status="completed", pr_url, and current_phase
13
+
14
+ Note: This is the only action that performs git commit, as it's the final
15
+ step after all implementation and checks are complete.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import argparse
21
+ import json
22
+ import subprocess
23
+ import sys
24
+ from pathlib import Path
25
+
26
+ # Add parent directory to path for imports
27
+ sys.path.insert(0, str(Path(__file__).parent.parent))
28
+
29
+ from common.git_context import _run_git_command
30
+ from common.paths import (
31
+ DIR_WORKFLOW,
32
+ FILE_TASK_JSON,
33
+ get_current_task,
34
+ get_repo_root,
35
+ )
36
+ from common.phase import get_phase_for_action
37
+
38
+ # =============================================================================
39
+ # Colors
40
+ # =============================================================================
41
+
42
+
43
+ class Colors:
44
+ RED = "\033[0;31m"
45
+ GREEN = "\033[0;32m"
46
+ YELLOW = "\033[1;33m"
47
+ BLUE = "\033[0;34m"
48
+ NC = "\033[0m"
49
+
50
+
51
+ # =============================================================================
52
+ # Helper Functions
53
+ # =============================================================================
54
+
55
+
56
+ def _read_json_file(path: Path) -> dict | None:
57
+ """Read and parse a JSON file."""
58
+ try:
59
+ return json.loads(path.read_text(encoding="utf-8"))
60
+ except (FileNotFoundError, json.JSONDecodeError, OSError):
61
+ return None
62
+
63
+
64
+ def _write_json_file(path: Path, data: dict) -> bool:
65
+ """Write dict to JSON file."""
66
+ try:
67
+ path.write_text(
68
+ json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8"
69
+ )
70
+ return True
71
+ except (OSError, IOError):
72
+ return False
73
+
74
+
75
+ # =============================================================================
76
+ # Main
77
+ # =============================================================================
78
+
79
+
80
+ def main() -> int:
81
+ """Main entry point."""
82
+ parser = argparse.ArgumentParser(description="Multi-Agent Pipeline: Create PR")
83
+ parser.add_argument("dir", nargs="?", help="Task directory")
84
+ parser.add_argument(
85
+ "--dry-run", action="store_true", help="Show what would be done"
86
+ )
87
+
88
+ args = parser.parse_args()
89
+ repo_root = get_repo_root()
90
+
91
+ # =============================================================================
92
+ # Get Task Directory
93
+ # =============================================================================
94
+ target_dir = args.dir
95
+ if not target_dir:
96
+ # Try to get from .current-task
97
+ current_task = get_current_task(repo_root)
98
+ if current_task:
99
+ target_dir = current_task
100
+
101
+ if not target_dir:
102
+ print(
103
+ f"{Colors.RED}Error: No task directory specified and no current task set{Colors.NC}"
104
+ )
105
+ print("Usage: python3 create_pr.py [task-dir] [--dry-run]")
106
+ return 1
107
+
108
+ # Support relative paths
109
+ if not target_dir.startswith("/"):
110
+ target_dir_path = repo_root / target_dir
111
+ else:
112
+ target_dir_path = Path(target_dir)
113
+
114
+ task_json = target_dir_path / FILE_TASK_JSON
115
+ if not task_json.is_file():
116
+ print(f"{Colors.RED}Error: task.json not found at {target_dir_path}{Colors.NC}")
117
+ return 1
118
+
119
+ # =============================================================================
120
+ # Main
121
+ # =============================================================================
122
+ print(f"{Colors.BLUE}=== Create PR ==={Colors.NC}")
123
+ if args.dry_run:
124
+ print(
125
+ f"{Colors.YELLOW}[DRY-RUN MODE] No actual changes will be made{Colors.NC}"
126
+ )
127
+ print()
128
+
129
+ # Read task config
130
+ task_data = _read_json_file(task_json)
131
+ if not task_data:
132
+ print(f"{Colors.RED}Error: Failed to read task.json{Colors.NC}")
133
+ return 1
134
+
135
+ task_name = task_data.get("name", "")
136
+ base_branch = task_data.get("base_branch", "main")
137
+ scope = task_data.get("scope", "core")
138
+ dev_type = task_data.get("dev_type", "feature")
139
+
140
+ # Map dev_type to commit prefix
141
+ prefix_map = {
142
+ "feature": "feat",
143
+ "frontend": "feat",
144
+ "backend": "feat",
145
+ "fullstack": "feat",
146
+ "bugfix": "fix",
147
+ "fix": "fix",
148
+ "refactor": "refactor",
149
+ "docs": "docs",
150
+ "test": "test",
151
+ }
152
+ commit_prefix = prefix_map.get(dev_type, "feat")
153
+
154
+ print(f"Task: {task_name}")
155
+ print(f"Base branch: {base_branch}")
156
+ print(f"Scope: {scope}")
157
+ print(f"Commit prefix: {commit_prefix}")
158
+ print()
159
+
160
+ # Get current branch
161
+ _, branch_out, _ = _run_git_command(["branch", "--show-current"])
162
+ current_branch = branch_out.strip()
163
+ print(f"Current branch: {current_branch}")
164
+
165
+ # Check for changes
166
+ print(f"{Colors.YELLOW}Checking for changes...{Colors.NC}")
167
+
168
+ # Stage changes
169
+ _run_git_command(["add", "-A"])
170
+
171
+ # Exclude workspace and temp files
172
+ _run_git_command(["reset", f"{DIR_WORKFLOW}/workspace/"])
173
+ _run_git_command(["reset", ".agent-log", ".session-id"])
174
+
175
+ # Check if there are staged changes
176
+ ret, _, _ = _run_git_command(["diff", "--cached", "--quiet"])
177
+ has_staged_changes = ret != 0
178
+
179
+ if not has_staged_changes:
180
+ print(f"{Colors.YELLOW}No staged changes to commit{Colors.NC}")
181
+
182
+ # Check for unpushed commits
183
+ ret, log_out, _ = _run_git_command(
184
+ ["log", f"origin/{current_branch}..HEAD", "--oneline"]
185
+ )
186
+ unpushed = len([line for line in log_out.splitlines() if line.strip()])
187
+
188
+ if unpushed == 0:
189
+ if args.dry_run:
190
+ _run_git_command(["reset", "HEAD"])
191
+ print(f"{Colors.RED}No changes to create PR{Colors.NC}")
192
+ return 1
193
+
194
+ print(f"Found {unpushed} unpushed commit(s)")
195
+ else:
196
+ # Commit changes
197
+ print(f"{Colors.YELLOW}Committing changes...{Colors.NC}")
198
+ commit_msg = f"{commit_prefix}({scope}): {task_name}"
199
+
200
+ if args.dry_run:
201
+ print(f"[DRY-RUN] Would commit with message: {commit_msg}")
202
+ print("[DRY-RUN] Staged files:")
203
+ _, staged_out, _ = _run_git_command(["diff", "--cached", "--name-only"])
204
+ for line in staged_out.splitlines():
205
+ print(f" - {line}")
206
+ else:
207
+ _run_git_command(["commit", "-m", commit_msg])
208
+ print(f"{Colors.GREEN}Committed: {commit_msg}{Colors.NC}")
209
+
210
+ # Push to remote
211
+ print(f"{Colors.YELLOW}Pushing to remote...{Colors.NC}")
212
+ if args.dry_run:
213
+ print(f"[DRY-RUN] Would push to: origin/{current_branch}")
214
+ else:
215
+ ret, _, err = _run_git_command(["push", "-u", "origin", current_branch])
216
+ if ret != 0:
217
+ print(f"{Colors.RED}Failed to push: {err}{Colors.NC}")
218
+ return 1
219
+ print(f"{Colors.GREEN}Pushed to origin/{current_branch}{Colors.NC}")
220
+
221
+ # Create PR
222
+ print(f"{Colors.YELLOW}Creating PR...{Colors.NC}")
223
+ pr_title = f"{commit_prefix}({scope}): {task_name}"
224
+ pr_url = ""
225
+
226
+ if args.dry_run:
227
+ print("[DRY-RUN] Would create PR:")
228
+ print(f" Title: {pr_title}")
229
+ print(f" Base: {base_branch}")
230
+ print(f" Head: {current_branch}")
231
+ prd_file = target_dir_path / "prd.md"
232
+ if prd_file.is_file():
233
+ print(" Body: (from prd.md)")
234
+ pr_url = "https://github.com/example/repo/pull/DRY-RUN"
235
+ else:
236
+ # Check if PR already exists
237
+ result = subprocess.run(
238
+ [
239
+ "gh",
240
+ "pr",
241
+ "list",
242
+ "--head",
243
+ current_branch,
244
+ "--base",
245
+ base_branch,
246
+ "--json",
247
+ "url",
248
+ "--jq",
249
+ ".[0].url",
250
+ ],
251
+ capture_output=True,
252
+ text=True,
253
+ encoding="utf-8",
254
+ errors="replace",
255
+ )
256
+ existing_pr = result.stdout.strip()
257
+
258
+ if existing_pr:
259
+ print(f"{Colors.YELLOW}PR already exists: {existing_pr}{Colors.NC}")
260
+ pr_url = existing_pr
261
+ else:
262
+ # Read PRD as PR body
263
+ pr_body = ""
264
+ prd_file = target_dir_path / "prd.md"
265
+ if prd_file.is_file():
266
+ pr_body = prd_file.read_text(encoding="utf-8")
267
+
268
+ # Create PR
269
+ result = subprocess.run(
270
+ [
271
+ "gh",
272
+ "pr",
273
+ "create",
274
+ "--draft",
275
+ "--base",
276
+ base_branch,
277
+ "--title",
278
+ pr_title,
279
+ "--body",
280
+ pr_body,
281
+ ],
282
+ capture_output=True,
283
+ text=True,
284
+ encoding="utf-8",
285
+ errors="replace",
286
+ )
287
+
288
+ if result.returncode != 0:
289
+ print(f"{Colors.RED}Failed to create PR: {result.stderr}{Colors.NC}")
290
+ return 1
291
+
292
+ pr_url = result.stdout.strip()
293
+ print(f"{Colors.GREEN}PR created: {pr_url}{Colors.NC}")
294
+
295
+ # Update task.json
296
+ print(f"{Colors.YELLOW}Updating task status...{Colors.NC}")
297
+ if args.dry_run:
298
+ print("[DRY-RUN] Would update task.json:")
299
+ print(" status: completed")
300
+ print(f" pr_url: {pr_url}")
301
+ print(" current_phase: (set to create-pr phase)")
302
+ else:
303
+ # Get the phase number for create-pr action
304
+ create_pr_phase = get_phase_for_action(task_json, "create-pr")
305
+ if not create_pr_phase:
306
+ create_pr_phase = 4 # Default fallback
307
+
308
+ task_data["status"] = "completed"
309
+ task_data["pr_url"] = pr_url
310
+ task_data["current_phase"] = create_pr_phase
311
+
312
+ _write_json_file(task_json, task_data)
313
+ print(
314
+ f"{Colors.GREEN}Task status updated to 'completed', phase {create_pr_phase}{Colors.NC}"
315
+ )
316
+
317
+ # In dry-run, reset the staging area
318
+ if args.dry_run:
319
+ _run_git_command(["reset", "HEAD"])
320
+
321
+ print()
322
+ print(f"{Colors.GREEN}=== PR Created Successfully ==={Colors.NC}")
323
+ print(f"PR URL: {pr_url}")
324
+
325
+ return 0
326
+
327
+
328
+ if __name__ == "__main__":
329
+ sys.exit(main())
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Multi-Agent Pipeline: Plan Agent Launcher.
4
+
5
+ Usage: python3 plan.py --name <task-name> --type <dev-type> --requirement "<requirement>"
6
+
7
+ This script:
8
+ 1. Creates task directory
9
+ 2. Starts Plan Agent in background
10
+ 3. Plan Agent produces fully configured task directory
11
+
12
+ After completion, use start.py to launch the Dispatch Agent.
13
+
14
+ Prerequisites:
15
+ - agents/plan.md must exist (in .claude/, .cursor/, .iflow/, or .opencode/)
16
+ - Developer must be initialized
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import argparse
22
+ import os
23
+ import subprocess
24
+ import sys
25
+ from pathlib import Path
26
+
27
+ # Add parent directory to path for imports
28
+ sys.path.insert(0, str(Path(__file__).parent.parent))
29
+
30
+ from common.cli_adapter import get_cli_adapter
31
+ from common.paths import get_repo_root
32
+ from common.developer import ensure_developer
33
+
34
+
35
+ # =============================================================================
36
+ # Colors
37
+ # =============================================================================
38
+
39
+ class Colors:
40
+ RED = "\033[0;31m"
41
+ GREEN = "\033[0;32m"
42
+ YELLOW = "\033[1;33m"
43
+ BLUE = "\033[0;34m"
44
+ NC = "\033[0m"
45
+
46
+
47
+ def log_info(msg: str) -> None:
48
+ print(f"{Colors.BLUE}[INFO]{Colors.NC} {msg}")
49
+
50
+
51
+ def log_success(msg: str) -> None:
52
+ print(f"{Colors.GREEN}[SUCCESS]{Colors.NC} {msg}")
53
+
54
+
55
+ def log_error(msg: str) -> None:
56
+ print(f"{Colors.RED}[ERROR]{Colors.NC} {msg}")
57
+
58
+
59
+ # =============================================================================
60
+ # Constants
61
+ # =============================================================================
62
+
63
+ DEFAULT_PLATFORM = "claude"
64
+
65
+
66
+ # =============================================================================
67
+ # Main
68
+ # =============================================================================
69
+
70
+ def main() -> int:
71
+ """Main entry point."""
72
+ parser = argparse.ArgumentParser(
73
+ description="Multi-Agent Pipeline: Plan Agent Launcher"
74
+ )
75
+ parser.add_argument("--name", "-n", required=True, help="Task name (e.g., user-auth)")
76
+ parser.add_argument("--type", "-t", required=True, help="Dev type: backend|frontend|fullstack")
77
+ parser.add_argument("--requirement", "-r", required=True, help="Requirement description")
78
+ parser.add_argument(
79
+ "--platform", "-p",
80
+ choices=["claude", "cursor", "iflow", "opencode"],
81
+ default=DEFAULT_PLATFORM,
82
+ help="Platform to use (default: claude)"
83
+ )
84
+
85
+ args = parser.parse_args()
86
+
87
+ task_name = args.name
88
+ dev_type = args.type
89
+ requirement = args.requirement
90
+ platform = args.platform
91
+
92
+ # Initialize CLI adapter
93
+ adapter = get_cli_adapter(platform)
94
+
95
+ # Validate dev type
96
+ if dev_type not in ("backend", "frontend", "fullstack"):
97
+ log_error(f"Invalid dev type: {dev_type} (must be: backend, frontend, fullstack)")
98
+ return 1
99
+
100
+ project_root = get_repo_root()
101
+
102
+ # Check plan agent exists (path varies by platform)
103
+ plan_md = adapter.get_agent_path("plan", project_root)
104
+ if not plan_md.is_file():
105
+ log_error(f"plan agent not found at {plan_md}")
106
+ log_info(f"Platform: {platform}")
107
+ return 1
108
+
109
+ ensure_developer(project_root)
110
+
111
+ # =============================================================================
112
+ # Step 1: Create Task Directory
113
+ # =============================================================================
114
+ print()
115
+ print(f"{Colors.BLUE}=== Multi-Agent Pipeline: Plan ==={Colors.NC}")
116
+ log_info(f"Task: {task_name}")
117
+ log_info(f"Type: {dev_type}")
118
+ log_info(f"Requirement: {requirement}")
119
+ print()
120
+
121
+ log_info("Step 1: Creating task directory...")
122
+
123
+ # Import task module to create task
124
+ from task import cmd_create
125
+ import argparse as ap
126
+
127
+ # Create task using task.py's create command
128
+ create_args = ap.Namespace(
129
+ title=requirement,
130
+ slug=task_name,
131
+ assignee=None,
132
+ priority="P2",
133
+ description=""
134
+ )
135
+
136
+ # Capture stdout to get task dir
137
+ import io
138
+ from contextlib import redirect_stdout
139
+
140
+ stdout_capture = io.StringIO()
141
+ with redirect_stdout(stdout_capture):
142
+ ret = cmd_create(create_args)
143
+
144
+ if ret != 0:
145
+ log_error("Failed to create task directory")
146
+ return 1
147
+
148
+ task_dir = stdout_capture.getvalue().strip().split("\n")[-1]
149
+ task_dir_abs = project_root / task_dir
150
+
151
+ log_success(f"Task directory: {task_dir}")
152
+
153
+ # =============================================================================
154
+ # Step 2: Prepare and Start Plan Agent
155
+ # =============================================================================
156
+ log_info("Step 2: Starting Plan Agent in background...")
157
+
158
+ log_file = task_dir_abs / ".plan-log"
159
+ log_file.touch()
160
+
161
+ # Get proxy environment variables
162
+ https_proxy = os.environ.get("https_proxy", "")
163
+ http_proxy = os.environ.get("http_proxy", "")
164
+ all_proxy = os.environ.get("all_proxy", "")
165
+
166
+ # Start agent in background (cross-platform, no shell script needed)
167
+ env = os.environ.copy()
168
+ env["PLAN_TASK_NAME"] = task_name
169
+ env["PLAN_DEV_TYPE"] = dev_type
170
+ env["PLAN_TASK_DIR"] = task_dir
171
+ env["PLAN_REQUIREMENT"] = requirement
172
+ env["https_proxy"] = https_proxy
173
+ env["http_proxy"] = http_proxy
174
+ env["all_proxy"] = all_proxy
175
+
176
+ # Set non-interactive env var based on platform
177
+ env.update(adapter.get_non_interactive_env())
178
+
179
+ # Build CLI command using adapter
180
+ cli_cmd = adapter.build_run_command(
181
+ agent="plan", # Will be mapped to "trellis-plan" for OpenCode
182
+ prompt=f"Start planning for task: {task_name}",
183
+ skip_permissions=True,
184
+ verbose=True,
185
+ json_output=True,
186
+ )
187
+
188
+ with log_file.open("w") as log_f:
189
+ # Use shell=False for cross-platform compatibility
190
+ # creationflags for Windows, start_new_session for Unix
191
+ popen_kwargs = {
192
+ "stdout": log_f,
193
+ "stderr": subprocess.STDOUT,
194
+ "cwd": str(project_root),
195
+ "env": env,
196
+ }
197
+ if sys.platform == "win32":
198
+ popen_kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP
199
+ else:
200
+ popen_kwargs["start_new_session"] = True
201
+
202
+ process = subprocess.Popen(cli_cmd, **popen_kwargs)
203
+ agent_pid = process.pid
204
+
205
+ log_success(f"Plan Agent started (PID: {agent_pid})")
206
+
207
+ # =============================================================================
208
+ # Summary
209
+ # =============================================================================
210
+ print()
211
+ print(f"{Colors.GREEN}=== Plan Agent Running ==={Colors.NC}")
212
+ print()
213
+ print(f" Task: {task_name}")
214
+ print(f" Type: {dev_type}")
215
+ print(f" Dir: {task_dir}")
216
+ print(f" Log: {log_file}")
217
+ print(f" PID: {agent_pid}")
218
+ print()
219
+ print(f"{Colors.YELLOW}To monitor:{Colors.NC}")
220
+ print(f" tail -f {log_file}")
221
+ print()
222
+ print(f"{Colors.YELLOW}To check status:{Colors.NC}")
223
+ print(f" ps -p {agent_pid}")
224
+ print(f" ls -la {task_dir}")
225
+ print()
226
+ print(f"{Colors.YELLOW}After completion, run:{Colors.NC}")
227
+ print(f" python3 ./.trellis/scripts/multi_agent/start.py {task_dir}")
228
+
229
+ return 0
230
+
231
+
232
+ if __name__ == "__main__":
233
+ sys.exit(main())