@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,247 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Registry utility functions for multi-agent pipeline
|
|
3
|
+
#
|
|
4
|
+
# Usage: source this file in other scripts
|
|
5
|
+
# source "$(dirname "$0")/common/registry.sh"
|
|
6
|
+
#
|
|
7
|
+
# Provides:
|
|
8
|
+
# registry_get_file - Get registry file path
|
|
9
|
+
# registry_get_agent_by_id - Find agent by ID
|
|
10
|
+
# registry_get_agent_by_worktree - Find agent by worktree path
|
|
11
|
+
# registry_get_task_dir - Get task dir for a worktree
|
|
12
|
+
# registry_remove_by_id - Remove agent by ID
|
|
13
|
+
# registry_remove_by_worktree - Remove agent by worktree path
|
|
14
|
+
# registry_add_agent - Add agent to registry
|
|
15
|
+
|
|
16
|
+
# Ensure dependencies are loaded
|
|
17
|
+
if ! type get_repo_root &>/dev/null; then
|
|
18
|
+
echo "Error: paths.sh must be sourced before registry.sh" >&2
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
if ! type get_agents_dir &>/dev/null; then
|
|
23
|
+
echo "Error: developer.sh must be sourced before registry.sh" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# =============================================================================
|
|
28
|
+
# Registry File Access
|
|
29
|
+
# =============================================================================
|
|
30
|
+
|
|
31
|
+
# Get registry file path
|
|
32
|
+
# Args: [repo_root]
|
|
33
|
+
# Returns: path to registry.json
|
|
34
|
+
registry_get_file() {
|
|
35
|
+
local repo_root="${1:-$(get_repo_root)}"
|
|
36
|
+
local agents_dir=$(get_agents_dir "$repo_root")
|
|
37
|
+
echo "${agents_dir}/registry.json"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Ensure registry file exists with valid structure
|
|
41
|
+
# Args: [repo_root]
|
|
42
|
+
_ensure_registry() {
|
|
43
|
+
local repo_root="${1:-$(get_repo_root)}"
|
|
44
|
+
local registry_file=$(registry_get_file "$repo_root")
|
|
45
|
+
local agents_dir=$(dirname "$registry_file")
|
|
46
|
+
|
|
47
|
+
mkdir -p "$agents_dir"
|
|
48
|
+
|
|
49
|
+
if [[ ! -f "$registry_file" ]]; then
|
|
50
|
+
echo '{"agents":[]}' > "$registry_file"
|
|
51
|
+
fi
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# =============================================================================
|
|
55
|
+
# Agent Lookup
|
|
56
|
+
# =============================================================================
|
|
57
|
+
|
|
58
|
+
# Get agent by ID
|
|
59
|
+
# Args: agent_id, [repo_root]
|
|
60
|
+
# Returns: agent JSON object (compact), or empty if not found
|
|
61
|
+
registry_get_agent_by_id() {
|
|
62
|
+
local agent_id="$1"
|
|
63
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
64
|
+
local registry_file=$(registry_get_file "$repo_root")
|
|
65
|
+
|
|
66
|
+
if [[ ! -f "$registry_file" ]]; then
|
|
67
|
+
return 1
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
local agent=$(jq -c --arg id "$agent_id" '.agents[] | select(.id == $id)' "$registry_file" 2>/dev/null)
|
|
71
|
+
|
|
72
|
+
if [[ -n "$agent" ]] && [[ "$agent" != "null" ]]; then
|
|
73
|
+
echo "$agent"
|
|
74
|
+
return 0
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
return 1
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# Get agent by worktree path
|
|
81
|
+
# Args: worktree_path, [repo_root]
|
|
82
|
+
# Returns: agent JSON object (compact), or empty if not found
|
|
83
|
+
registry_get_agent_by_worktree() {
|
|
84
|
+
local worktree_path="$1"
|
|
85
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
86
|
+
local registry_file=$(registry_get_file "$repo_root")
|
|
87
|
+
|
|
88
|
+
if [[ ! -f "$registry_file" ]]; then
|
|
89
|
+
return 1
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
local agent=$(jq -c --arg path "$worktree_path" '.agents[] | select(.worktree_path == $path)' "$registry_file" 2>/dev/null)
|
|
93
|
+
|
|
94
|
+
if [[ -n "$agent" ]] && [[ "$agent" != "null" ]]; then
|
|
95
|
+
echo "$agent"
|
|
96
|
+
return 0
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
return 1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Search agent by ID or task_dir containing search term
|
|
103
|
+
# Args: search_term, [repo_root]
|
|
104
|
+
# Returns: first matching agent JSON object (compact), or empty if not found
|
|
105
|
+
registry_search_agent() {
|
|
106
|
+
local search="$1"
|
|
107
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
108
|
+
local registry_file=$(registry_get_file "$repo_root")
|
|
109
|
+
|
|
110
|
+
if [[ ! -f "$registry_file" ]]; then
|
|
111
|
+
return 1
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
local agent=$(jq -c --arg search "$search" \
|
|
115
|
+
'[.agents[] | select(.id == $search or (.task_dir | contains($search)))] | first' \
|
|
116
|
+
"$registry_file" 2>/dev/null)
|
|
117
|
+
|
|
118
|
+
if [[ -n "$agent" ]] && [[ "$agent" != "null" ]]; then
|
|
119
|
+
echo "$agent"
|
|
120
|
+
return 0
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
return 1
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Get task directory for a worktree
|
|
127
|
+
# Args: worktree_path, [repo_root]
|
|
128
|
+
# Returns: task_dir value, or empty if not found
|
|
129
|
+
registry_get_task_dir() {
|
|
130
|
+
local worktree_path="$1"
|
|
131
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
132
|
+
local registry_file=$(registry_get_file "$repo_root")
|
|
133
|
+
|
|
134
|
+
if [[ ! -f "$registry_file" ]]; then
|
|
135
|
+
return 1
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
local task_dir=$(jq -r --arg path "$worktree_path" \
|
|
139
|
+
'.agents[] | select(.worktree_path == $path) | .task_dir' \
|
|
140
|
+
"$registry_file" 2>/dev/null)
|
|
141
|
+
|
|
142
|
+
if [[ -n "$task_dir" ]] && [[ "$task_dir" != "null" ]]; then
|
|
143
|
+
echo "$task_dir"
|
|
144
|
+
return 0
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
return 1
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# =============================================================================
|
|
151
|
+
# Agent Modification
|
|
152
|
+
# =============================================================================
|
|
153
|
+
|
|
154
|
+
# Remove agent by ID
|
|
155
|
+
# Args: agent_id, [repo_root]
|
|
156
|
+
# Returns: 0 on success
|
|
157
|
+
registry_remove_by_id() {
|
|
158
|
+
local agent_id="$1"
|
|
159
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
160
|
+
local registry_file=$(registry_get_file "$repo_root")
|
|
161
|
+
|
|
162
|
+
if [[ ! -f "$registry_file" ]]; then
|
|
163
|
+
return 0
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
local updated=$(jq --arg id "$agent_id" \
|
|
167
|
+
'.agents = [.agents[] | select(.id != $id)]' \
|
|
168
|
+
"$registry_file")
|
|
169
|
+
|
|
170
|
+
echo "$updated" | jq '.' > "$registry_file"
|
|
171
|
+
return 0
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Remove agent by worktree path
|
|
175
|
+
# Args: worktree_path, [repo_root]
|
|
176
|
+
# Returns: 0 on success
|
|
177
|
+
registry_remove_by_worktree() {
|
|
178
|
+
local worktree_path="$1"
|
|
179
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
180
|
+
local registry_file=$(registry_get_file "$repo_root")
|
|
181
|
+
|
|
182
|
+
if [[ ! -f "$registry_file" ]]; then
|
|
183
|
+
return 0
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
local updated=$(jq --arg path "$worktree_path" \
|
|
187
|
+
'.agents = [.agents[] | select(.worktree_path != $path)]' \
|
|
188
|
+
"$registry_file")
|
|
189
|
+
|
|
190
|
+
echo "$updated" | jq '.' > "$registry_file"
|
|
191
|
+
return 0
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
# Add agent to registry (replaces if same ID exists)
|
|
195
|
+
# Args: agent_id, worktree_path, pid, task_dir, [repo_root]
|
|
196
|
+
# Returns: 0 on success
|
|
197
|
+
registry_add_agent() {
|
|
198
|
+
local agent_id="$1"
|
|
199
|
+
local worktree_path="$2"
|
|
200
|
+
local pid="$3"
|
|
201
|
+
local task_dir="$4"
|
|
202
|
+
local repo_root="${5:-$(get_repo_root)}"
|
|
203
|
+
|
|
204
|
+
_ensure_registry "$repo_root"
|
|
205
|
+
local registry_file=$(registry_get_file "$repo_root")
|
|
206
|
+
|
|
207
|
+
local started_at=$(date -Iseconds)
|
|
208
|
+
|
|
209
|
+
# Remove existing agent with same ID
|
|
210
|
+
local registry=$(jq --arg id "$agent_id" \
|
|
211
|
+
'.agents = [.agents[] | select(.id != $id)]' \
|
|
212
|
+
"$registry_file")
|
|
213
|
+
|
|
214
|
+
# Create new agent record
|
|
215
|
+
local new_agent=$(jq -n \
|
|
216
|
+
--arg id "$agent_id" \
|
|
217
|
+
--arg worktree "$worktree_path" \
|
|
218
|
+
--arg pid "$pid" \
|
|
219
|
+
--arg started_at "$started_at" \
|
|
220
|
+
--arg task_dir "$task_dir" \
|
|
221
|
+
'{
|
|
222
|
+
id: $id,
|
|
223
|
+
worktree_path: $worktree,
|
|
224
|
+
pid: ($pid | tonumber),
|
|
225
|
+
started_at: $started_at,
|
|
226
|
+
task_dir: $task_dir
|
|
227
|
+
}')
|
|
228
|
+
|
|
229
|
+
# Add to registry
|
|
230
|
+
echo "$registry" | jq --argjson agent "$new_agent" '.agents += [$agent]' > "$registry_file"
|
|
231
|
+
return 0
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
# List all agents
|
|
235
|
+
# Args: [repo_root]
|
|
236
|
+
# Returns: JSON array of agents
|
|
237
|
+
registry_list_agents() {
|
|
238
|
+
local repo_root="${1:-$(get_repo_root)}"
|
|
239
|
+
local registry_file=$(registry_get_file "$repo_root")
|
|
240
|
+
|
|
241
|
+
if [[ ! -f "$registry_file" ]]; then
|
|
242
|
+
echo '[]'
|
|
243
|
+
return 0
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
jq '.agents' "$registry_file"
|
|
247
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Task queue utility functions
|
|
3
|
+
#
|
|
4
|
+
# Usage: source this file in other scripts
|
|
5
|
+
# source "$(dirname "$0")/common/task-queue.sh"
|
|
6
|
+
#
|
|
7
|
+
# Provides:
|
|
8
|
+
# list_pending_tasks - List tasks with pending status
|
|
9
|
+
# get_task_stats - Get P0/P1/P2/P3 counts
|
|
10
|
+
|
|
11
|
+
# Ensure paths.sh is loaded
|
|
12
|
+
if ! type get_repo_root &>/dev/null; then
|
|
13
|
+
echo "Error: paths.sh must be sourced before task-queue.sh" >&2
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# =============================================================================
|
|
18
|
+
# Public Functions
|
|
19
|
+
# =============================================================================
|
|
20
|
+
|
|
21
|
+
# List tasks by status
|
|
22
|
+
# Args: [filter_status]
|
|
23
|
+
# Output: formatted list to stdout
|
|
24
|
+
list_tasks_by_status() {
|
|
25
|
+
local filter_status="${1:-}"
|
|
26
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
27
|
+
|
|
28
|
+
local tasks_dir=$(get_tasks_dir "$repo_root")
|
|
29
|
+
|
|
30
|
+
if [[ ! -d "$tasks_dir" ]]; then
|
|
31
|
+
return 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
for d in "$tasks_dir"/*/; do
|
|
35
|
+
if [[ -d "$d" ]] && [[ "$(basename "$d")" != "archive" ]]; then
|
|
36
|
+
local task_json="$d/$FILE_TASK_JSON"
|
|
37
|
+
if [[ -f "$task_json" ]]; then
|
|
38
|
+
local id=$(jq -r '.id' "$task_json")
|
|
39
|
+
local title=$(jq -r '.title // .name' "$task_json")
|
|
40
|
+
local priority=$(jq -r '.priority // "P2"' "$task_json")
|
|
41
|
+
local status=$(jq -r '.status // "planning"' "$task_json")
|
|
42
|
+
local assignee=$(jq -r '.assignee // "-"' "$task_json")
|
|
43
|
+
|
|
44
|
+
# Apply filter
|
|
45
|
+
if [[ -n "$filter_status" ]] && [[ "$status" != "$filter_status" ]]; then
|
|
46
|
+
continue
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
echo "$priority|$id|$title|$status|$assignee"
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
done
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# List pending tasks
|
|
56
|
+
list_pending_tasks() {
|
|
57
|
+
list_tasks_by_status "planning" "$@"
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# List tasks assigned to a specific developer
|
|
61
|
+
# Args: developer_name, [filter_status], [repo_root]
|
|
62
|
+
# Output: formatted list to stdout
|
|
63
|
+
list_tasks_by_assignee() {
|
|
64
|
+
local assignee="$1"
|
|
65
|
+
local filter_status="${2:-}"
|
|
66
|
+
local repo_root="${3:-$(get_repo_root)}"
|
|
67
|
+
|
|
68
|
+
local tasks_dir=$(get_tasks_dir "$repo_root")
|
|
69
|
+
|
|
70
|
+
if [[ ! -d "$tasks_dir" ]]; then
|
|
71
|
+
return 0
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
for d in "$tasks_dir"/*/; do
|
|
75
|
+
if [[ -d "$d" ]] && [[ "$(basename "$d")" != "archive" ]]; then
|
|
76
|
+
local task_json="$d/$FILE_TASK_JSON"
|
|
77
|
+
if [[ -f "$task_json" ]]; then
|
|
78
|
+
local id=$(jq -r '.id' "$task_json")
|
|
79
|
+
local title=$(jq -r '.title // .name' "$task_json")
|
|
80
|
+
local priority=$(jq -r '.priority // "P2"' "$task_json")
|
|
81
|
+
local status=$(jq -r '.status // "planning"' "$task_json")
|
|
82
|
+
local task_assignee=$(jq -r '.assignee // "-"' "$task_json")
|
|
83
|
+
|
|
84
|
+
# Apply assignee filter
|
|
85
|
+
if [[ "$task_assignee" != "$assignee" ]]; then
|
|
86
|
+
continue
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Apply status filter
|
|
90
|
+
if [[ -n "$filter_status" ]] && [[ "$status" != "$filter_status" ]]; then
|
|
91
|
+
continue
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
echo "$priority|$id|$title|$status|$task_assignee"
|
|
95
|
+
fi
|
|
96
|
+
fi
|
|
97
|
+
done
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# List my tasks (current developer)
|
|
101
|
+
# Args: [filter_status], [repo_root]
|
|
102
|
+
list_my_tasks() {
|
|
103
|
+
local filter_status="${1:-}"
|
|
104
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
105
|
+
local developer=$(get_developer "$repo_root")
|
|
106
|
+
|
|
107
|
+
if [[ -z "$developer" ]]; then
|
|
108
|
+
echo "Error: Developer not set" >&2
|
|
109
|
+
return 1
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
list_tasks_by_assignee "$developer" "$filter_status" "$repo_root"
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Get task statistics
|
|
116
|
+
# Output: "P0:N P1:N P2:N P3:N Total:N"
|
|
117
|
+
get_task_stats() {
|
|
118
|
+
local repo_root="${1:-$(get_repo_root)}"
|
|
119
|
+
local tasks_dir=$(get_tasks_dir "$repo_root")
|
|
120
|
+
|
|
121
|
+
local p0=0 p1=0 p2=0 p3=0 total=0
|
|
122
|
+
|
|
123
|
+
if [[ -d "$tasks_dir" ]]; then
|
|
124
|
+
for d in "$tasks_dir"/*/; do
|
|
125
|
+
if [[ -d "$d" ]] && [[ "$(basename "$d")" != "archive" ]]; then
|
|
126
|
+
local task_json="$d/$FILE_TASK_JSON"
|
|
127
|
+
if [[ -f "$task_json" ]]; then
|
|
128
|
+
local priority=$(jq -r '.priority // "P2"' "$task_json" 2>/dev/null)
|
|
129
|
+
case "$priority" in
|
|
130
|
+
P0) ((p0++)) ;;
|
|
131
|
+
P1) ((p1++)) ;;
|
|
132
|
+
P2) ((p2++)) ;;
|
|
133
|
+
P3) ((p3++)) ;;
|
|
134
|
+
esac
|
|
135
|
+
((total++))
|
|
136
|
+
fi
|
|
137
|
+
fi
|
|
138
|
+
done
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
echo "P0:$p0 P1:$p1 P2:$p2 P3:$p3 Total:$total"
|
|
142
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Task utility functions
|
|
3
|
+
#
|
|
4
|
+
# Usage: source this file in other scripts
|
|
5
|
+
# source "$(dirname "$0")/common/task-utils.sh"
|
|
6
|
+
#
|
|
7
|
+
# Provides:
|
|
8
|
+
# is_safe_task_path - Validate task path is safe to operate on
|
|
9
|
+
# find_task_by_name - Find task directory by name
|
|
10
|
+
# archive_task_dir - Archive task to monthly directory
|
|
11
|
+
|
|
12
|
+
# Ensure dependencies are loaded
|
|
13
|
+
if ! type get_repo_root &>/dev/null; then
|
|
14
|
+
echo "Error: paths.sh must be sourced before task-utils.sh" >&2
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# =============================================================================
|
|
19
|
+
# Path Safety
|
|
20
|
+
# =============================================================================
|
|
21
|
+
|
|
22
|
+
# Check if a relative task path is safe to operate on
|
|
23
|
+
# Args: task_path (relative), repo_root
|
|
24
|
+
# Returns: 0 if safe, 1 if dangerous
|
|
25
|
+
# Outputs: error message to stderr if unsafe
|
|
26
|
+
is_safe_task_path() {
|
|
27
|
+
local task_path="$1"
|
|
28
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
29
|
+
|
|
30
|
+
# Check empty or null
|
|
31
|
+
if [[ -z "$task_path" ]] || [[ "$task_path" = "null" ]]; then
|
|
32
|
+
echo "Error: empty or null task path" >&2
|
|
33
|
+
return 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Reject absolute paths
|
|
37
|
+
if [[ "$task_path" = /* ]]; then
|
|
38
|
+
echo "Error: absolute path not allowed: $task_path" >&2
|
|
39
|
+
return 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Reject ".", "..", paths starting with "./" or "../", or containing ".."
|
|
43
|
+
if [[ "$task_path" = "." ]] || [[ "$task_path" = ".." ]] || \
|
|
44
|
+
[[ "$task_path" = "./" ]] || [[ "$task_path" == ./* ]] || \
|
|
45
|
+
[[ "$task_path" == *".."* ]]; then
|
|
46
|
+
echo "Error: path traversal not allowed: $task_path" >&2
|
|
47
|
+
return 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Final check: ensure resolved path is not the repo root
|
|
51
|
+
local abs_path="${repo_root}/${task_path}"
|
|
52
|
+
if [[ -e "$abs_path" ]]; then
|
|
53
|
+
local resolved=$(realpath "$abs_path" 2>/dev/null)
|
|
54
|
+
local root_resolved=$(realpath "$repo_root" 2>/dev/null)
|
|
55
|
+
if [[ "$resolved" = "$root_resolved" ]]; then
|
|
56
|
+
echo "Error: path resolves to repo root: $task_path" >&2
|
|
57
|
+
return 1
|
|
58
|
+
fi
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
return 0
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# =============================================================================
|
|
65
|
+
# Task Lookup
|
|
66
|
+
# =============================================================================
|
|
67
|
+
|
|
68
|
+
# Find task directory by name (exact or suffix match)
|
|
69
|
+
# Args: task_name, tasks_dir
|
|
70
|
+
# Returns: absolute path to task directory, or empty if not found
|
|
71
|
+
find_task_by_name() {
|
|
72
|
+
local task_name="$1"
|
|
73
|
+
local tasks_dir="$2"
|
|
74
|
+
|
|
75
|
+
if [[ -z "$task_name" ]] || [[ -z "$tasks_dir" ]]; then
|
|
76
|
+
return 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Try exact match first
|
|
80
|
+
local task_dir=$(find "$tasks_dir" -maxdepth 1 -type d -name "${task_name}" 2>/dev/null | head -1)
|
|
81
|
+
|
|
82
|
+
# Try suffix match (e.g., "my-task" matches "01-21-my-task")
|
|
83
|
+
if [[ -z "$task_dir" ]]; then
|
|
84
|
+
task_dir=$(find "$tasks_dir" -maxdepth 1 -type d -name "*-${task_name}" 2>/dev/null | head -1)
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
if [[ -n "$task_dir" ]] && [[ -d "$task_dir" ]]; then
|
|
88
|
+
echo "$task_dir"
|
|
89
|
+
return 0
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
return 1
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# =============================================================================
|
|
96
|
+
# Archive Operations
|
|
97
|
+
# =============================================================================
|
|
98
|
+
|
|
99
|
+
# Archive a task directory to archive/{YYYY-MM}/
|
|
100
|
+
# Args: task_dir_abs, [repo_root]
|
|
101
|
+
# Returns: 0 on success, 1 on error
|
|
102
|
+
# Outputs: archive destination path
|
|
103
|
+
archive_task_dir() {
|
|
104
|
+
local task_dir_abs="$1"
|
|
105
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
106
|
+
|
|
107
|
+
if [[ ! -d "$task_dir_abs" ]]; then
|
|
108
|
+
echo "Error: task directory not found: $task_dir_abs" >&2
|
|
109
|
+
return 1
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# Get tasks directory (parent of the task)
|
|
113
|
+
local tasks_dir=$(dirname "$task_dir_abs")
|
|
114
|
+
local archive_dir="$tasks_dir/archive"
|
|
115
|
+
local year_month=$(date +%Y-%m)
|
|
116
|
+
local month_dir="$archive_dir/$year_month"
|
|
117
|
+
|
|
118
|
+
# Create archive directory
|
|
119
|
+
mkdir -p "$month_dir"
|
|
120
|
+
|
|
121
|
+
# Move task to archive
|
|
122
|
+
local task_name=$(basename "$task_dir_abs")
|
|
123
|
+
mv "$task_dir_abs" "$month_dir/"
|
|
124
|
+
|
|
125
|
+
# Output the destination
|
|
126
|
+
echo "$month_dir/$task_name"
|
|
127
|
+
return 0
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
# Complete archive workflow: archive directory
|
|
131
|
+
# Args: task_dir_abs, [repo_root]
|
|
132
|
+
# Returns: 0 on success
|
|
133
|
+
# Outputs: lines with status info
|
|
134
|
+
archive_task_complete() {
|
|
135
|
+
local task_dir_abs="$1"
|
|
136
|
+
local repo_root="${2:-$(get_repo_root)}"
|
|
137
|
+
|
|
138
|
+
if [[ ! -d "$task_dir_abs" ]]; then
|
|
139
|
+
echo "Error: task directory not found: $task_dir_abs" >&2
|
|
140
|
+
return 1
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# Archive the directory
|
|
144
|
+
local archive_dest
|
|
145
|
+
if archive_dest=$(archive_task_dir "$task_dir_abs" "$repo_root"); then
|
|
146
|
+
echo "archived_to:$archive_dest"
|
|
147
|
+
return 0
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
return 1
|
|
151
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Worktree utilities for Multi-Agent Pipeline
|
|
3
|
+
#
|
|
4
|
+
# Usage: source this file in multi-agent scripts
|
|
5
|
+
# source "$(dirname "$0")/../common/worktree.sh"
|
|
6
|
+
#
|
|
7
|
+
# Provides:
|
|
8
|
+
# get_worktree_config - Get worktree.yaml path
|
|
9
|
+
# get_worktree_base_dir - Get worktree storage directory
|
|
10
|
+
# get_worktree_copy_files - Get files to copy list
|
|
11
|
+
# get_worktree_post_create_hooks - Get post-create hooks
|
|
12
|
+
# get_agents_dir - Get agents registry directory
|
|
13
|
+
#
|
|
14
|
+
# Requires: paths.sh (for get_repo_root)
|
|
15
|
+
|
|
16
|
+
# Ensure paths.sh is loaded
|
|
17
|
+
if ! type get_repo_root &>/dev/null; then
|
|
18
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
|
+
source "$SCRIPT_DIR/paths.sh"
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# =============================================================================
|
|
23
|
+
# Worktree Configuration
|
|
24
|
+
# =============================================================================
|
|
25
|
+
|
|
26
|
+
# Worktree config file relative path (relative to repo root)
|
|
27
|
+
WORKTREE_CONFIG_PATH="$DIR_WORKFLOW/worktree.yaml"
|
|
28
|
+
|
|
29
|
+
# Get worktree.yaml config file path
|
|
30
|
+
# Args: $1 - repo_root (optional)
|
|
31
|
+
# Returns: absolute path to config file
|
|
32
|
+
get_worktree_config() {
|
|
33
|
+
local repo_root="${1:-$(get_repo_root)}"
|
|
34
|
+
echo "$repo_root/$WORKTREE_CONFIG_PATH"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Read simple value from worktree.yaml
|
|
38
|
+
# Args: $1 - key, $2 - config_file (optional)
|
|
39
|
+
# Returns: value
|
|
40
|
+
_yaml_get_value() {
|
|
41
|
+
local key="$1"
|
|
42
|
+
local config="${2:-$(get_worktree_config)}"
|
|
43
|
+
grep "^${key}:" "$config" 2>/dev/null | sed "s/^${key}:[[:space:]]*//" | tr -d '"' | tr -d "'"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Read list from worktree.yaml
|
|
47
|
+
# Args: $1 - section, $2 - config_file (optional)
|
|
48
|
+
# Returns: list items (one per line)
|
|
49
|
+
_yaml_get_list() {
|
|
50
|
+
local section="$1"
|
|
51
|
+
local config="${2:-$(get_worktree_config)}"
|
|
52
|
+
local in_section=0
|
|
53
|
+
|
|
54
|
+
while IFS= read -r line; do
|
|
55
|
+
if [[ "$line" =~ ^${section}: ]]; then
|
|
56
|
+
in_section=1
|
|
57
|
+
continue
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
if [ $in_section -eq 1 ]; then
|
|
61
|
+
# Exit when encountering new top-level key
|
|
62
|
+
if [[ "$line" =~ ^[a-z_]+: ]] && [[ ! "$line" =~ ^[[:space:]] ]]; then
|
|
63
|
+
break
|
|
64
|
+
fi
|
|
65
|
+
# Read list item
|
|
66
|
+
if [[ "$line" =~ ^[[:space:]]*-[[:space:]](.+)$ ]]; then
|
|
67
|
+
echo "${BASH_REMATCH[1]}" | tr -d '"' | tr -d "'"
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
done < "$config"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Get worktree base directory
|
|
74
|
+
# Args: $1 - repo_root (optional)
|
|
75
|
+
# Returns: absolute path to worktree base directory
|
|
76
|
+
get_worktree_base_dir() {
|
|
77
|
+
local repo_root="${1:-$(get_repo_root)}"
|
|
78
|
+
local config=$(get_worktree_config "$repo_root")
|
|
79
|
+
local worktree_dir=$(_yaml_get_value "worktree_dir" "$config")
|
|
80
|
+
|
|
81
|
+
# Default value
|
|
82
|
+
if [ -z "$worktree_dir" ]; then
|
|
83
|
+
worktree_dir="../worktrees"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Handle relative path
|
|
87
|
+
if [[ "$worktree_dir" == ../* ]] || [[ "$worktree_dir" == ./* ]]; then
|
|
88
|
+
# Relative to repo_root
|
|
89
|
+
echo "$repo_root/$worktree_dir"
|
|
90
|
+
else
|
|
91
|
+
# Absolute path
|
|
92
|
+
echo "$worktree_dir"
|
|
93
|
+
fi
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Get files to copy list
|
|
97
|
+
# Args: $1 - repo_root (optional)
|
|
98
|
+
# Returns: file list (one per line)
|
|
99
|
+
get_worktree_copy_files() {
|
|
100
|
+
local repo_root="${1:-$(get_repo_root)}"
|
|
101
|
+
local config=$(get_worktree_config "$repo_root")
|
|
102
|
+
_yaml_get_list "copy" "$config"
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Get post_create hooks
|
|
106
|
+
# Args: $1 - repo_root (optional)
|
|
107
|
+
# Returns: command list (one per line)
|
|
108
|
+
get_worktree_post_create_hooks() {
|
|
109
|
+
local repo_root="${1:-$(get_repo_root)}"
|
|
110
|
+
local config=$(get_worktree_config "$repo_root")
|
|
111
|
+
_yaml_get_list "post_create" "$config"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# =============================================================================
|
|
115
|
+
# Agents Registry
|
|
116
|
+
# =============================================================================
|
|
117
|
+
|
|
118
|
+
# Get agents directory for current developer
|
|
119
|
+
# Args: $1 - repo_root (optional)
|
|
120
|
+
# Returns: absolute path to agents directory
|
|
121
|
+
get_agents_dir() {
|
|
122
|
+
local repo_root="${1:-$(get_repo_root)}"
|
|
123
|
+
local workspace_dir=$(get_workspace_dir "$repo_root")
|
|
124
|
+
|
|
125
|
+
if [[ -n "$workspace_dir" ]]; then
|
|
126
|
+
echo "$workspace_dir/.agents"
|
|
127
|
+
fi
|
|
128
|
+
}
|