@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,26 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Get current developer name.
|
|
4
|
+
|
|
5
|
+
This is a wrapper that uses common/paths.py
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
from common.paths import get_developer
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main() -> None:
|
|
16
|
+
"""CLI entry point."""
|
|
17
|
+
developer = get_developer()
|
|
18
|
+
if developer:
|
|
19
|
+
print(developer)
|
|
20
|
+
else:
|
|
21
|
+
print("Developer not initialized", file=sys.stderr)
|
|
22
|
+
sys.exit(1)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == "__main__":
|
|
26
|
+
main()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Initialize developer for workflow.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python3 init_developer.py <developer-name>
|
|
7
|
+
|
|
8
|
+
This creates:
|
|
9
|
+
- .trellis/.developer file with developer info
|
|
10
|
+
- .trellis/workspace/<name>/ directory structure
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
from common.paths import (
|
|
18
|
+
DIR_WORKFLOW,
|
|
19
|
+
FILE_DEVELOPER,
|
|
20
|
+
get_developer,
|
|
21
|
+
)
|
|
22
|
+
from common.developer import init_developer
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main() -> None:
|
|
26
|
+
"""CLI entry point."""
|
|
27
|
+
if len(sys.argv) < 2:
|
|
28
|
+
print(f"Usage: {sys.argv[0]} <developer-name>")
|
|
29
|
+
print()
|
|
30
|
+
print("Example:")
|
|
31
|
+
print(f" {sys.argv[0]} john")
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
|
|
34
|
+
name = sys.argv[1]
|
|
35
|
+
|
|
36
|
+
# Check if already initialized
|
|
37
|
+
existing = get_developer()
|
|
38
|
+
if existing:
|
|
39
|
+
print(f"Developer already initialized: {existing}")
|
|
40
|
+
print()
|
|
41
|
+
print(f"To reinitialize, remove {DIR_WORKFLOW}/{FILE_DEVELOPER} first")
|
|
42
|
+
sys.exit(0)
|
|
43
|
+
|
|
44
|
+
if init_developer(name):
|
|
45
|
+
sys.exit(0)
|
|
46
|
+
else:
|
|
47
|
+
sys.exit(1)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
main()
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Multi-Agent Pipeline: Cleanup Worktree.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python3 cleanup.py <branch-name> Remove specific worktree
|
|
7
|
+
python3 cleanup.py --list List all worktrees
|
|
8
|
+
python3 cleanup.py --merged Remove merged worktrees
|
|
9
|
+
python3 cleanup.py --all Remove all worktrees (with confirmation)
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
-y, --yes Skip confirmation prompts
|
|
13
|
+
--keep-branch Don't delete the git branch
|
|
14
|
+
|
|
15
|
+
This script:
|
|
16
|
+
1. Archives task directory to archive/{YYYY-MM}/
|
|
17
|
+
2. Removes agent from registry
|
|
18
|
+
3. Removes git worktree
|
|
19
|
+
4. Optionally deletes git branch
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import argparse
|
|
25
|
+
import shutil
|
|
26
|
+
import subprocess
|
|
27
|
+
import sys
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
# Add parent directory to path for imports
|
|
31
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
32
|
+
|
|
33
|
+
from common.git_context import _run_git_command
|
|
34
|
+
from common.paths import get_repo_root
|
|
35
|
+
from common.registry import (
|
|
36
|
+
registry_get_file,
|
|
37
|
+
registry_get_task_dir,
|
|
38
|
+
registry_remove_by_id,
|
|
39
|
+
registry_remove_by_worktree,
|
|
40
|
+
registry_search_agent,
|
|
41
|
+
)
|
|
42
|
+
from common.task_utils import (
|
|
43
|
+
archive_task_complete,
|
|
44
|
+
is_safe_task_path,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# =============================================================================
|
|
48
|
+
# Colors
|
|
49
|
+
# =============================================================================
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Colors:
|
|
53
|
+
RED = "\033[0;31m"
|
|
54
|
+
GREEN = "\033[0;32m"
|
|
55
|
+
YELLOW = "\033[1;33m"
|
|
56
|
+
BLUE = "\033[0;34m"
|
|
57
|
+
NC = "\033[0m"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def log_info(msg: str) -> None:
|
|
61
|
+
print(f"{Colors.BLUE}[INFO]{Colors.NC} {msg}")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def log_success(msg: str) -> None:
|
|
65
|
+
print(f"{Colors.GREEN}[SUCCESS]{Colors.NC} {msg}")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def log_warn(msg: str) -> None:
|
|
69
|
+
print(f"{Colors.YELLOW}[WARN]{Colors.NC} {msg}")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def log_error(msg: str) -> None:
|
|
73
|
+
print(f"{Colors.RED}[ERROR]{Colors.NC} {msg}")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# =============================================================================
|
|
77
|
+
# Helper Functions
|
|
78
|
+
# =============================================================================
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def confirm(prompt: str, skip_confirm: bool) -> bool:
|
|
82
|
+
"""Ask for confirmation."""
|
|
83
|
+
if skip_confirm:
|
|
84
|
+
return True
|
|
85
|
+
|
|
86
|
+
if not sys.stdin.isatty():
|
|
87
|
+
log_error("Non-interactive mode detected. Use -y to skip confirmation.")
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
response = input(f"{prompt} [y/N] ")
|
|
91
|
+
return response.lower() in ("y", "yes")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# =============================================================================
|
|
95
|
+
# Commands
|
|
96
|
+
# =============================================================================
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def cmd_list(repo_root: Path) -> int:
|
|
100
|
+
"""List worktrees."""
|
|
101
|
+
print(f"{Colors.BLUE}=== Git Worktrees ==={Colors.NC}")
|
|
102
|
+
print()
|
|
103
|
+
|
|
104
|
+
subprocess.run(["git", "worktree", "list"], cwd=repo_root)
|
|
105
|
+
print()
|
|
106
|
+
|
|
107
|
+
# Show registry info
|
|
108
|
+
registry_file = registry_get_file(repo_root)
|
|
109
|
+
if registry_file and registry_file.is_file():
|
|
110
|
+
print(f"{Colors.BLUE}=== Registered Agents ==={Colors.NC}")
|
|
111
|
+
print()
|
|
112
|
+
|
|
113
|
+
import json
|
|
114
|
+
|
|
115
|
+
data = json.loads(registry_file.read_text(encoding="utf-8"))
|
|
116
|
+
agents = data.get("agents", [])
|
|
117
|
+
|
|
118
|
+
if agents:
|
|
119
|
+
for agent in agents:
|
|
120
|
+
print(
|
|
121
|
+
f" {agent.get('id', '?')}: PID={agent.get('pid', '?')} [{agent.get('worktree_path', '?')}]"
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
print(" (none)")
|
|
125
|
+
print()
|
|
126
|
+
|
|
127
|
+
return 0
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def archive_task(worktree_path: str, repo_root: Path) -> None:
|
|
131
|
+
"""Archive task directory."""
|
|
132
|
+
task_dir = registry_get_task_dir(worktree_path, repo_root)
|
|
133
|
+
|
|
134
|
+
if not task_dir or not is_safe_task_path(task_dir, repo_root):
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
task_dir_abs = repo_root / task_dir
|
|
138
|
+
if not task_dir_abs.is_dir():
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
result = archive_task_complete(task_dir_abs, repo_root)
|
|
142
|
+
if "archived_to" in result:
|
|
143
|
+
dest = Path(result["archived_to"])
|
|
144
|
+
log_success(f"Archived task: {dest.name} -> archive/{dest.parent.name}/")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def cleanup_registry_only(search: str, repo_root: Path, skip_confirm: bool) -> int:
|
|
148
|
+
"""Cleanup from registry only (no worktree)."""
|
|
149
|
+
agent_info = registry_search_agent(search, repo_root)
|
|
150
|
+
|
|
151
|
+
if not agent_info:
|
|
152
|
+
log_error(f"No agent found in registry matching: {search}")
|
|
153
|
+
return 1
|
|
154
|
+
|
|
155
|
+
agent_id = agent_info.get("id", "?")
|
|
156
|
+
task_dir = agent_info.get("task_dir", "?")
|
|
157
|
+
|
|
158
|
+
print()
|
|
159
|
+
print(f"{Colors.BLUE}=== Cleanup Agent (no worktree) ==={Colors.NC}")
|
|
160
|
+
print(f" Agent ID: {agent_id}")
|
|
161
|
+
print(f" Task Dir: {task_dir}")
|
|
162
|
+
print()
|
|
163
|
+
|
|
164
|
+
if not confirm("Archive task and remove from registry?", skip_confirm):
|
|
165
|
+
log_info("Aborted")
|
|
166
|
+
return 0
|
|
167
|
+
|
|
168
|
+
# Archive task directory if exists
|
|
169
|
+
if task_dir and is_safe_task_path(task_dir, repo_root):
|
|
170
|
+
task_dir_abs = repo_root / task_dir
|
|
171
|
+
if task_dir_abs.is_dir():
|
|
172
|
+
result = archive_task_complete(task_dir_abs, repo_root)
|
|
173
|
+
if "archived_to" in result:
|
|
174
|
+
dest = Path(result["archived_to"])
|
|
175
|
+
log_success(
|
|
176
|
+
f"Archived task: {dest.name} -> archive/{dest.parent.name}/"
|
|
177
|
+
)
|
|
178
|
+
else:
|
|
179
|
+
log_warn("Invalid task_dir in registry, skipping archive")
|
|
180
|
+
|
|
181
|
+
# Remove from registry
|
|
182
|
+
registry_remove_by_id(agent_id, repo_root)
|
|
183
|
+
log_success(f"Removed from registry: {agent_id}")
|
|
184
|
+
|
|
185
|
+
log_success("Cleanup complete")
|
|
186
|
+
return 0
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def cleanup_worktree(
|
|
190
|
+
branch: str, repo_root: Path, skip_confirm: bool, keep_branch: bool
|
|
191
|
+
) -> int:
|
|
192
|
+
"""Cleanup single worktree."""
|
|
193
|
+
# Find worktree path for branch
|
|
194
|
+
_, worktree_list, _ = _run_git_command(
|
|
195
|
+
["worktree", "list", "--porcelain"], cwd=repo_root
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
worktree_path = None
|
|
199
|
+
current_worktree = None
|
|
200
|
+
|
|
201
|
+
for line in worktree_list.splitlines():
|
|
202
|
+
if line.startswith("worktree "):
|
|
203
|
+
current_worktree = line[9:] # Remove "worktree " prefix
|
|
204
|
+
elif line.startswith("branch refs/heads/"):
|
|
205
|
+
current_branch = line[18:] # Remove "branch refs/heads/" prefix
|
|
206
|
+
if current_branch == branch:
|
|
207
|
+
worktree_path = current_worktree
|
|
208
|
+
break
|
|
209
|
+
|
|
210
|
+
if not worktree_path:
|
|
211
|
+
# No worktree found, try to cleanup from registry only
|
|
212
|
+
log_warn(f"No worktree found for: {branch}")
|
|
213
|
+
log_info("Trying to cleanup from registry...")
|
|
214
|
+
return cleanup_registry_only(branch, repo_root, skip_confirm)
|
|
215
|
+
|
|
216
|
+
print()
|
|
217
|
+
print(f"{Colors.BLUE}=== Cleanup Worktree ==={Colors.NC}")
|
|
218
|
+
print(f" Branch: {branch}")
|
|
219
|
+
print(f" Worktree: {worktree_path}")
|
|
220
|
+
print()
|
|
221
|
+
|
|
222
|
+
if not confirm("Remove this worktree?", skip_confirm):
|
|
223
|
+
log_info("Aborted")
|
|
224
|
+
return 0
|
|
225
|
+
|
|
226
|
+
# 1. Archive task
|
|
227
|
+
archive_task(worktree_path, repo_root)
|
|
228
|
+
|
|
229
|
+
# 2. Remove from registry
|
|
230
|
+
registry_remove_by_worktree(worktree_path, repo_root)
|
|
231
|
+
log_info("Removed from registry")
|
|
232
|
+
|
|
233
|
+
# 3. Remove worktree
|
|
234
|
+
log_info("Removing worktree...")
|
|
235
|
+
ret, _, _ = _run_git_command(
|
|
236
|
+
["worktree", "remove", worktree_path, "--force"], cwd=repo_root
|
|
237
|
+
)
|
|
238
|
+
if ret != 0:
|
|
239
|
+
# Try removing directory manually
|
|
240
|
+
try:
|
|
241
|
+
shutil.rmtree(worktree_path)
|
|
242
|
+
except Exception as e:
|
|
243
|
+
log_error(f"Failed to remove worktree: {e}")
|
|
244
|
+
|
|
245
|
+
log_success("Worktree removed")
|
|
246
|
+
|
|
247
|
+
# 4. Delete branch (optional)
|
|
248
|
+
if not keep_branch:
|
|
249
|
+
log_info("Deleting branch...")
|
|
250
|
+
ret, _, _ = _run_git_command(["branch", "-D", branch], cwd=repo_root)
|
|
251
|
+
if ret != 0:
|
|
252
|
+
log_warn("Could not delete branch (may be checked out elsewhere)")
|
|
253
|
+
|
|
254
|
+
log_success(f"Cleanup complete for: {branch}")
|
|
255
|
+
return 0
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def cmd_merged(repo_root: Path, skip_confirm: bool, keep_branch: bool) -> int:
|
|
259
|
+
"""Cleanup merged worktrees."""
|
|
260
|
+
# Get main branch
|
|
261
|
+
_, head_out, _ = _run_git_command(
|
|
262
|
+
["symbolic-ref", "refs/remotes/origin/HEAD"], cwd=repo_root
|
|
263
|
+
)
|
|
264
|
+
main_branch = head_out.strip().replace("refs/remotes/origin/", "") or "main"
|
|
265
|
+
|
|
266
|
+
print(f"{Colors.BLUE}=== Finding Merged Worktrees ==={Colors.NC}")
|
|
267
|
+
print()
|
|
268
|
+
|
|
269
|
+
# Get merged branches
|
|
270
|
+
_, merged_out, _ = _run_git_command(
|
|
271
|
+
["branch", "--merged", main_branch], cwd=repo_root
|
|
272
|
+
)
|
|
273
|
+
merged_branches = []
|
|
274
|
+
for line in merged_out.splitlines():
|
|
275
|
+
branch = line.strip().lstrip("* ")
|
|
276
|
+
if branch and branch != main_branch:
|
|
277
|
+
merged_branches.append(branch)
|
|
278
|
+
|
|
279
|
+
if not merged_branches:
|
|
280
|
+
log_info("No merged branches found")
|
|
281
|
+
return 0
|
|
282
|
+
|
|
283
|
+
# Get worktree list
|
|
284
|
+
_, worktree_list, _ = _run_git_command(["worktree", "list"], cwd=repo_root)
|
|
285
|
+
|
|
286
|
+
worktree_branches = []
|
|
287
|
+
for branch in merged_branches:
|
|
288
|
+
if f"[{branch}]" in worktree_list:
|
|
289
|
+
worktree_branches.append(branch)
|
|
290
|
+
print(f" - {branch}")
|
|
291
|
+
|
|
292
|
+
if not worktree_branches:
|
|
293
|
+
log_info("No merged worktrees found")
|
|
294
|
+
return 0
|
|
295
|
+
|
|
296
|
+
print()
|
|
297
|
+
if not confirm("Remove these merged worktrees?", skip_confirm):
|
|
298
|
+
log_info("Aborted")
|
|
299
|
+
return 0
|
|
300
|
+
|
|
301
|
+
for branch in worktree_branches:
|
|
302
|
+
cleanup_worktree(branch, repo_root, True, keep_branch)
|
|
303
|
+
|
|
304
|
+
return 0
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def cmd_all(repo_root: Path, skip_confirm: bool, keep_branch: bool) -> int:
|
|
308
|
+
"""Cleanup all worktrees."""
|
|
309
|
+
print(f"{Colors.BLUE}=== All Worktrees ==={Colors.NC}")
|
|
310
|
+
print()
|
|
311
|
+
|
|
312
|
+
# Get worktree list
|
|
313
|
+
_, worktree_list, _ = _run_git_command(
|
|
314
|
+
["worktree", "list", "--porcelain"], cwd=repo_root
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
worktrees = []
|
|
318
|
+
main_worktree = str(repo_root.resolve())
|
|
319
|
+
|
|
320
|
+
for line in worktree_list.splitlines():
|
|
321
|
+
if line.startswith("worktree "):
|
|
322
|
+
wt = line[9:]
|
|
323
|
+
if wt != main_worktree:
|
|
324
|
+
worktrees.append(wt)
|
|
325
|
+
|
|
326
|
+
if not worktrees:
|
|
327
|
+
log_info("No worktrees to remove")
|
|
328
|
+
return 0
|
|
329
|
+
|
|
330
|
+
for wt in worktrees:
|
|
331
|
+
print(f" - {wt}")
|
|
332
|
+
|
|
333
|
+
print()
|
|
334
|
+
print(f"{Colors.RED}WARNING: This will remove ALL worktrees!{Colors.NC}")
|
|
335
|
+
|
|
336
|
+
if not confirm("Are you sure?", skip_confirm):
|
|
337
|
+
log_info("Aborted")
|
|
338
|
+
return 0
|
|
339
|
+
|
|
340
|
+
# Get branch for each worktree
|
|
341
|
+
for wt in worktrees:
|
|
342
|
+
# Find branch name from worktree list
|
|
343
|
+
_, wt_list, _ = _run_git_command(["worktree", "list"], cwd=repo_root)
|
|
344
|
+
for line in wt_list.splitlines():
|
|
345
|
+
if wt in line:
|
|
346
|
+
# Extract branch from [branch] format
|
|
347
|
+
import re
|
|
348
|
+
|
|
349
|
+
match = re.search(r"\[([^\]]+)\]", line)
|
|
350
|
+
if match:
|
|
351
|
+
branch = match.group(1)
|
|
352
|
+
cleanup_worktree(branch, repo_root, True, keep_branch)
|
|
353
|
+
break
|
|
354
|
+
|
|
355
|
+
return 0
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
# =============================================================================
|
|
359
|
+
# Main
|
|
360
|
+
# =============================================================================
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def main() -> int:
|
|
364
|
+
"""Main entry point."""
|
|
365
|
+
parser = argparse.ArgumentParser(
|
|
366
|
+
description="Multi-Agent Pipeline: Cleanup Worktree"
|
|
367
|
+
)
|
|
368
|
+
parser.add_argument("branch", nargs="?", help="Branch name to cleanup")
|
|
369
|
+
parser.add_argument("-y", "--yes", action="store_true", help="Skip confirmation")
|
|
370
|
+
parser.add_argument(
|
|
371
|
+
"--keep-branch", action="store_true", help="Don't delete git branch"
|
|
372
|
+
)
|
|
373
|
+
parser.add_argument("--list", action="store_true", help="List all worktrees")
|
|
374
|
+
parser.add_argument("--merged", action="store_true", help="Remove merged worktrees")
|
|
375
|
+
parser.add_argument("--all", action="store_true", help="Remove all worktrees")
|
|
376
|
+
|
|
377
|
+
args = parser.parse_args()
|
|
378
|
+
repo_root = get_repo_root()
|
|
379
|
+
|
|
380
|
+
if args.list:
|
|
381
|
+
return cmd_list(repo_root)
|
|
382
|
+
elif args.merged:
|
|
383
|
+
return cmd_merged(repo_root, args.yes, args.keep_branch)
|
|
384
|
+
elif args.all:
|
|
385
|
+
return cmd_all(repo_root, args.yes, args.keep_branch)
|
|
386
|
+
elif args.branch:
|
|
387
|
+
return cleanup_worktree(args.branch, repo_root, args.yes, args.keep_branch)
|
|
388
|
+
else:
|
|
389
|
+
print("""Usage:
|
|
390
|
+
python3 cleanup.py <branch-name> Remove specific worktree
|
|
391
|
+
python3 cleanup.py --list List all worktrees
|
|
392
|
+
python3 cleanup.py --merged Remove merged worktrees
|
|
393
|
+
python3 cleanup.py --all Remove all worktrees
|
|
394
|
+
|
|
395
|
+
Options:
|
|
396
|
+
-y, --yes Skip confirmation
|
|
397
|
+
--keep-branch Don't delete git branch
|
|
398
|
+
""")
|
|
399
|
+
return 1
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
if __name__ == "__main__":
|
|
403
|
+
sys.exit(main())
|