@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.
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/bin/aim.js +3 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +89 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +513 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/update.d.ts +27 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +1275 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/configurators/claude.d.ts +32 -0
- package/dist/configurators/claude.d.ts.map +1 -0
- package/dist/configurators/claude.js +98 -0
- package/dist/configurators/claude.js.map +1 -0
- package/dist/configurators/index.d.ts +51 -0
- package/dist/configurators/index.d.ts.map +1 -0
- package/dist/configurators/index.js +113 -0
- package/dist/configurators/index.js.map +1 -0
- package/dist/configurators/shared.d.ts +12 -0
- package/dist/configurators/shared.d.ts.map +1 -0
- package/dist/configurators/shared.js +21 -0
- package/dist/configurators/shared.js.map +1 -0
- package/dist/configurators/workflow.d.ts +28 -0
- package/dist/configurators/workflow.d.ts.map +1 -0
- package/dist/configurators/workflow.js +147 -0
- package/dist/configurators/workflow.js.map +1 -0
- package/dist/constants/paths.d.ts +68 -0
- package/dist/constants/paths.d.ts.map +1 -0
- package/dist/constants/paths.js +77 -0
- package/dist/constants/paths.js.map +1 -0
- package/dist/constants/version.d.ts +9 -0
- package/dist/constants/version.d.ts.map +1 -0
- package/dist/constants/version.js +15 -0
- package/dist/constants/version.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/index.d.ts +54 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +160 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/manifests/0.0.1.json +9 -0
- package/dist/migrations/manifests/0.1.9.json +30 -0
- package/dist/migrations/manifests/0.2.0.json +49 -0
- package/dist/migrations/manifests/0.2.12.json +9 -0
- package/dist/migrations/manifests/0.2.13.json +9 -0
- package/dist/migrations/manifests/0.2.14.json +175 -0
- package/dist/migrations/manifests/0.2.15.json +33 -0
- package/dist/migrations/manifests/0.3.0-beta.0.json +278 -0
- package/dist/migrations/manifests/0.3.0-beta.1.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.10.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.11.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.12.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.13.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.14.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.15.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.16.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.2.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.3.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.4.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.5.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.6.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.7.json +11 -0
- package/dist/migrations/manifests/0.3.0-beta.8.json +9 -0
- package/dist/migrations/manifests/0.3.0-beta.9.json +9 -0
- package/dist/migrations/manifests/0.3.0-rc.0.json +9 -0
- package/dist/migrations/manifests/0.3.0-rc.1.json +9 -0
- package/dist/migrations/manifests/0.3.0-rc.2.json +9 -0
- package/dist/templates/CLAUDE.md +71 -0
- package/dist/templates/aim/gitignore.txt +29 -0
- package/dist/templates/aim/index.d.ts +49 -0
- package/dist/templates/aim/index.d.ts.map +1 -0
- package/dist/templates/aim/index.js +92 -0
- package/dist/templates/aim/index.js.map +1 -0
- package/dist/templates/aim/scripts/__init__.py +5 -0
- package/dist/templates/aim/scripts/add_session.py +392 -0
- package/dist/templates/aim/scripts/common/__init__.py +80 -0
- package/dist/templates/aim/scripts/common/cli_adapter.py +435 -0
- package/dist/templates/aim/scripts/common/developer.py +190 -0
- package/dist/templates/aim/scripts/common/git_context.py +383 -0
- package/dist/templates/aim/scripts/common/paths.py +347 -0
- package/dist/templates/aim/scripts/common/phase.py +253 -0
- package/dist/templates/aim/scripts/common/registry.py +366 -0
- package/dist/templates/aim/scripts/common/task_queue.py +255 -0
- package/dist/templates/aim/scripts/common/task_utils.py +178 -0
- package/dist/templates/aim/scripts/common/worktree.py +219 -0
- package/dist/templates/aim/scripts/create_bootstrap.py +290 -0
- package/dist/templates/aim/scripts/get_context.py +16 -0
- package/dist/templates/aim/scripts/get_developer.py +26 -0
- package/dist/templates/aim/scripts/init_developer.py +51 -0
- package/dist/templates/aim/scripts/multi_agent/__init__.py +5 -0
- package/dist/templates/aim/scripts/multi_agent/cleanup.py +403 -0
- package/dist/templates/aim/scripts/multi_agent/create_pr.py +329 -0
- package/dist/templates/aim/scripts/multi_agent/plan.py +233 -0
- package/dist/templates/aim/scripts/multi_agent/start.py +461 -0
- package/dist/templates/aim/scripts/multi_agent/status.py +817 -0
- package/dist/templates/aim/scripts/task.py +1068 -0
- package/dist/templates/aim/scripts-shell-archive/add-session.sh +384 -0
- package/dist/templates/aim/scripts-shell-archive/common/developer.sh +129 -0
- package/dist/templates/aim/scripts-shell-archive/common/git-context.sh +263 -0
- package/dist/templates/aim/scripts-shell-archive/common/paths.sh +208 -0
- package/dist/templates/aim/scripts-shell-archive/common/phase.sh +150 -0
- package/dist/templates/aim/scripts-shell-archive/common/registry.sh +247 -0
- package/dist/templates/aim/scripts-shell-archive/common/task-queue.sh +142 -0
- package/dist/templates/aim/scripts-shell-archive/common/task-utils.sh +151 -0
- package/dist/templates/aim/scripts-shell-archive/common/worktree.sh +128 -0
- package/dist/templates/aim/scripts-shell-archive/create-bootstrap.sh +299 -0
- package/dist/templates/aim/scripts-shell-archive/get-context.sh +7 -0
- package/dist/templates/aim/scripts-shell-archive/get-developer.sh +15 -0
- package/dist/templates/aim/scripts-shell-archive/init-developer.sh +34 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/cleanup.sh +396 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/create-pr.sh +241 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/plan.sh +207 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/start.sh +317 -0
- package/dist/templates/aim/scripts-shell-archive/multi-agent/status.sh +828 -0
- package/dist/templates/aim/scripts-shell-archive/task.sh +1204 -0
- package/dist/templates/aim/tasks/.gitkeep +0 -0
- package/dist/templates/aim/workflow.md +258 -0
- package/dist/templates/aim/worktree.yaml +47 -0
- package/dist/templates/claude/agents/check.md +122 -0
- package/dist/templates/claude/agents/debug.md +106 -0
- package/dist/templates/claude/agents/dispatch.md +230 -0
- package/dist/templates/claude/agents/implement.md +96 -0
- package/dist/templates/claude/agents/plan.md +396 -0
- package/dist/templates/claude/agents/research.md +120 -0
- package/dist/templates/claude/agents/story.md +53 -0
- package/dist/templates/claude/commands/aim/before-backend-dev.md +13 -0
- package/dist/templates/claude/commands/aim/before-frontend-dev.md +13 -0
- package/dist/templates/claude/commands/aim/break-loop.md +153 -0
- package/dist/templates/claude/commands/aim/check-backend.md +13 -0
- package/dist/templates/claude/commands/aim/check-cross-layer.md +153 -0
- package/dist/templates/claude/commands/aim/check-frontend.md +13 -0
- package/dist/templates/claude/commands/aim/check-story.md +59 -0
- package/dist/templates/claude/commands/aim/create-command.md +154 -0
- package/dist/templates/claude/commands/aim/export.md +187 -0
- package/dist/templates/claude/commands/aim/finish-work.md +104 -0
- package/dist/templates/claude/commands/aim/integrate-skill.md +219 -0
- package/dist/templates/claude/commands/aim/onboard.md +358 -0
- package/dist/templates/claude/commands/aim/parallel.md +217 -0
- package/dist/templates/claude/commands/aim/portrait.md +170 -0
- package/dist/templates/claude/commands/aim/record-session.md +92 -0
- package/dist/templates/claude/commands/aim/start.md +112 -0
- package/dist/templates/claude/commands/aim/story.md +140 -0
- package/dist/templates/claude/commands/aim/update-spec.md +285 -0
- package/dist/templates/claude/commands/aim/visualize.md +182 -0
- package/dist/templates/claude/commands/trellis/before-backend-dev.md +13 -0
- package/dist/templates/claude/commands/trellis/before-frontend-dev.md +13 -0
- package/dist/templates/claude/commands/trellis/break-loop.md +125 -0
- package/dist/templates/claude/commands/trellis/check-backend.md +13 -0
- package/dist/templates/claude/commands/trellis/check-cross-layer.md +153 -0
- package/dist/templates/claude/commands/trellis/check-frontend.md +13 -0
- package/dist/templates/claude/commands/trellis/create-command.md +154 -0
- package/dist/templates/claude/commands/trellis/finish-work.md +129 -0
- package/dist/templates/claude/commands/trellis/integrate-skill.md +219 -0
- package/dist/templates/claude/commands/trellis/onboard.md +358 -0
- package/dist/templates/claude/commands/trellis/parallel.md +193 -0
- package/dist/templates/claude/commands/trellis/record-session.md +62 -0
- package/dist/templates/claude/commands/trellis/start.md +280 -0
- package/dist/templates/claude/commands/trellis/update-spec.md +285 -0
- package/dist/templates/claude/hooks/inject-subagent-context.py +772 -0
- package/dist/templates/claude/hooks/ralph-loop.py +388 -0
- package/dist/templates/claude/hooks/session-start.py +142 -0
- package/dist/templates/claude/index.d.ts +54 -0
- package/dist/templates/claude/index.d.ts.map +1 -0
- package/dist/templates/claude/index.js +85 -0
- package/dist/templates/claude/index.js.map +1 -0
- package/dist/templates/claude/settings.json +41 -0
- package/dist/templates/extract.d.ts +68 -0
- package/dist/templates/extract.d.ts.map +1 -0
- package/dist/templates/extract.js +128 -0
- package/dist/templates/extract.js.map +1 -0
- package/dist/templates/markdown/agents.md +25 -0
- package/dist/templates/markdown/gitignore.txt +12 -0
- package/dist/templates/markdown/index.d.ts +32 -0
- package/dist/templates/markdown/index.d.ts.map +1 -0
- package/dist/templates/markdown/index.js +58 -0
- package/dist/templates/markdown/index.js.map +1 -0
- package/dist/templates/markdown/spec/backend/database-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/spec/backend/error-handling.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/index.md +40 -0
- package/dist/templates/markdown/spec/backend/index.md.txt +38 -0
- package/dist/templates/markdown/spec/backend/logging-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/script-conventions.md +467 -0
- package/dist/templates/markdown/spec/frontend/component-guidelines.md.txt +59 -0
- package/dist/templates/markdown/spec/frontend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/spec/frontend/hook-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/index.md.txt +39 -0
- package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/state-management.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/type-safety.md.txt +51 -0
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md +118 -0
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +92 -0
- package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +94 -0
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md +394 -0
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +319 -0
- package/dist/templates/markdown/spec/guides/index.md.txt +89 -0
- package/dist/templates/markdown/spec/story/character.md.txt +95 -0
- package/dist/templates/markdown/spec/story/index.md.txt +31 -0
- package/dist/templates/markdown/spec/story/script.md.txt +313 -0
- package/dist/templates/markdown/spec/story/world.md.txt +92 -0
- package/dist/templates/markdown/workspace-index.md +123 -0
- package/dist/templates/markdown/worktree.yaml.txt +58 -0
- package/dist/templates/trellis/gitignore.txt +29 -0
- package/dist/templates/trellis/index.d.ts +49 -0
- package/dist/templates/trellis/index.d.ts.map +1 -0
- package/dist/templates/trellis/index.js +92 -0
- package/dist/templates/trellis/index.js.map +1 -0
- package/dist/templates/trellis/scripts/__init__.py +5 -0
- package/dist/templates/trellis/scripts/add_session.py +392 -0
- package/dist/templates/trellis/scripts/common/__init__.py +80 -0
- package/dist/templates/trellis/scripts/common/cli_adapter.py +435 -0
- package/dist/templates/trellis/scripts/common/developer.py +190 -0
- package/dist/templates/trellis/scripts/common/git_context.py +383 -0
- package/dist/templates/trellis/scripts/common/paths.py +347 -0
- package/dist/templates/trellis/scripts/common/phase.py +253 -0
- package/dist/templates/trellis/scripts/common/registry.py +366 -0
- package/dist/templates/trellis/scripts/common/task_queue.py +255 -0
- package/dist/templates/trellis/scripts/common/task_utils.py +178 -0
- package/dist/templates/trellis/scripts/common/worktree.py +219 -0
- package/dist/templates/trellis/scripts/create_bootstrap.py +290 -0
- package/dist/templates/trellis/scripts/get_context.py +16 -0
- package/dist/templates/trellis/scripts/get_developer.py +26 -0
- package/dist/templates/trellis/scripts/init_developer.py +51 -0
- package/dist/templates/trellis/scripts/multi_agent/__init__.py +5 -0
- package/dist/templates/trellis/scripts/multi_agent/cleanup.py +403 -0
- package/dist/templates/trellis/scripts/multi_agent/create_pr.py +329 -0
- package/dist/templates/trellis/scripts/multi_agent/plan.py +233 -0
- package/dist/templates/trellis/scripts/multi_agent/start.py +461 -0
- package/dist/templates/trellis/scripts/multi_agent/status.py +817 -0
- package/dist/templates/trellis/scripts/task.py +1056 -0
- package/dist/templates/trellis/scripts-shell-archive/add-session.sh +384 -0
- package/dist/templates/trellis/scripts-shell-archive/common/developer.sh +129 -0
- package/dist/templates/trellis/scripts-shell-archive/common/git-context.sh +263 -0
- package/dist/templates/trellis/scripts-shell-archive/common/paths.sh +208 -0
- package/dist/templates/trellis/scripts-shell-archive/common/phase.sh +150 -0
- package/dist/templates/trellis/scripts-shell-archive/common/registry.sh +247 -0
- package/dist/templates/trellis/scripts-shell-archive/common/task-queue.sh +142 -0
- package/dist/templates/trellis/scripts-shell-archive/common/task-utils.sh +151 -0
- package/dist/templates/trellis/scripts-shell-archive/common/worktree.sh +128 -0
- package/dist/templates/trellis/scripts-shell-archive/create-bootstrap.sh +299 -0
- package/dist/templates/trellis/scripts-shell-archive/get-context.sh +7 -0
- package/dist/templates/trellis/scripts-shell-archive/get-developer.sh +15 -0
- package/dist/templates/trellis/scripts-shell-archive/init-developer.sh +34 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/cleanup.sh +396 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/create-pr.sh +241 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/plan.sh +207 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/start.sh +317 -0
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/status.sh +828 -0
- package/dist/templates/trellis/scripts-shell-archive/task.sh +1204 -0
- package/dist/templates/trellis/tasks/.gitkeep +0 -0
- package/dist/templates/trellis/workflow.md +416 -0
- package/dist/templates/trellis/worktree.yaml +47 -0
- package/dist/types/ai-tools.d.ts +48 -0
- package/dist/types/ai-tools.d.ts.map +1 -0
- package/dist/types/ai-tools.js +32 -0
- package/dist/types/ai-tools.js.map +1 -0
- package/dist/types/migration.d.ts +86 -0
- package/dist/types/migration.d.ts.map +1 -0
- package/dist/types/migration.js +8 -0
- package/dist/types/migration.js.map +1 -0
- package/dist/utils/compare-versions.d.ts +12 -0
- package/dist/utils/compare-versions.d.ts.map +1 -0
- package/dist/utils/compare-versions.js +76 -0
- package/dist/utils/compare-versions.js.map +1 -0
- package/dist/utils/file-writer.d.ts +23 -0
- package/dist/utils/file-writer.d.ts.map +1 -0
- package/dist/utils/file-writer.js +140 -0
- package/dist/utils/file-writer.js.map +1 -0
- package/dist/utils/project-detector.d.ts +16 -0
- package/dist/utils/project-detector.d.ts.map +1 -0
- package/dist/utils/project-detector.js +188 -0
- package/dist/utils/project-detector.js.map +1 -0
- package/dist/utils/template-fetcher.d.ts +51 -0
- package/dist/utils/template-fetcher.d.ts.map +1 -0
- package/dist/utils/template-fetcher.js +174 -0
- package/dist/utils/template-fetcher.js.map +1 -0
- package/dist/utils/template-hash.d.ts +78 -0
- package/dist/utils/template-hash.d.ts.map +1 -0
- package/dist/utils/template-hash.js +239 -0
- package/dist/utils/template-hash.js.map +1 -0
- 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())
|