oden-forge 2.0.0
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/.claude/CLAUDE.md +75 -0
- package/.claude/commands/oden/architect.md +204 -0
- package/.claude/commands/oden/checklist.md +199 -0
- package/.claude/commands/oden/daily.md +223 -0
- package/.claude/commands/oden/debug.md +203 -0
- package/.claude/commands/oden/epic.md +224 -0
- package/.claude/commands/oden/git.md +259 -0
- package/.claude/commands/oden/help.md +304 -0
- package/.claude/commands/oden/init-agents.md +268 -0
- package/.claude/commands/oden/init-mcp.md +460 -0
- package/.claude/commands/oden/init.md +495 -0
- package/.claude/commands/oden/mcp.md +585 -0
- package/.claude/commands/oden/prd.md +134 -0
- package/.claude/commands/oden/research.md +207 -0
- package/.claude/commands/oden/review.md +146 -0
- package/.claude/commands/oden/spec.md +539 -0
- package/.claude/commands/oden/sync.md +286 -0
- package/.claude/commands/oden/tasks.md +156 -0
- package/.claude/commands/oden/test.md +200 -0
- package/.claude/commands/oden/work.md +791 -0
- package/.claude/epics/.gitkeep +0 -0
- package/.claude/hooks/README.md +130 -0
- package/.claude/hooks/bash-worktree-fix.sh +189 -0
- package/.claude/prds/.gitkeep +0 -0
- package/.claude/rules/agent-coordination.md +224 -0
- package/.claude/rules/branch-operations.md +147 -0
- package/.claude/rules/datetime.md +118 -0
- package/.claude/rules/frontmatter-operations.md +58 -0
- package/.claude/rules/github-operations.md +89 -0
- package/.claude/rules/oden-methodology.md +111 -0
- package/.claude/rules/path-standards.md +155 -0
- package/.claude/rules/standard-patterns.md +174 -0
- package/.claude/rules/strip-frontmatter.md +82 -0
- package/.claude/rules/worktree-operations.md +136 -0
- package/.claude/scripts/oden/blocked.sh +72 -0
- package/.claude/scripts/oden/epic-list.sh +101 -0
- package/.claude/scripts/oden/epic-show.sh +91 -0
- package/.claude/scripts/oden/epic-status.sh +90 -0
- package/.claude/scripts/oden/help.sh +71 -0
- package/.claude/scripts/oden/in-progress.sh +74 -0
- package/.claude/scripts/oden/init.sh +192 -0
- package/.claude/scripts/oden/next.sh +65 -0
- package/.claude/scripts/oden/prd-list.sh +89 -0
- package/.claude/scripts/oden/prd-status.sh +63 -0
- package/.claude/scripts/oden/search.sh +71 -0
- package/.claude/scripts/oden/standup.sh +89 -0
- package/.claude/scripts/oden/status.sh +42 -0
- package/.claude/scripts/oden/validate.sh +101 -0
- package/.claude/settings.json +27 -0
- package/MIGRATION.md +217 -0
- package/README.md +368 -0
- package/bin/install.js +155 -0
- package/bin/migrate.js +191 -0
- package/bin/oden-forge.js +114 -0
- package/bin/post-install.js +47 -0
- package/bin/pre-uninstall.js +108 -0
- package/install.sh +231 -0
- package/package.json +76 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
echo "Getting status..."
|
|
3
|
+
echo ""
|
|
4
|
+
echo ""
|
|
5
|
+
|
|
6
|
+
echo "🔄 In Progress Work"
|
|
7
|
+
echo "==================="
|
|
8
|
+
echo ""
|
|
9
|
+
|
|
10
|
+
# Check for active work in updates directories
|
|
11
|
+
found=0
|
|
12
|
+
|
|
13
|
+
if [ -d ".claude/epics" ]; then
|
|
14
|
+
for updates_dir in .claude/epics/*/updates/*/; do
|
|
15
|
+
[ -d "$updates_dir" ] || continue
|
|
16
|
+
|
|
17
|
+
issue_num=$(basename "$updates_dir")
|
|
18
|
+
epic_name=$(basename $(dirname $(dirname "$updates_dir")))
|
|
19
|
+
|
|
20
|
+
if [ -f "$updates_dir/progress.md" ]; then
|
|
21
|
+
completion=$(grep "^completion:" "$updates_dir/progress.md" | head -1 | sed 's/^completion: *//')
|
|
22
|
+
[ -z "$completion" ] && completion="0%"
|
|
23
|
+
|
|
24
|
+
# Get task name from the task file
|
|
25
|
+
task_file=".claude/epics/$epic_name/$issue_num.md"
|
|
26
|
+
if [ -f "$task_file" ]; then
|
|
27
|
+
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
|
28
|
+
else
|
|
29
|
+
task_name="Unknown task"
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
echo "📝 Issue #$issue_num - $task_name"
|
|
33
|
+
echo " Epic: $epic_name"
|
|
34
|
+
echo " Progress: $completion complete"
|
|
35
|
+
|
|
36
|
+
# Check for recent updates
|
|
37
|
+
if [ -f "$updates_dir/progress.md" ]; then
|
|
38
|
+
last_update=$(grep "^last_sync:" "$updates_dir/progress.md" | head -1 | sed 's/^last_sync: *//')
|
|
39
|
+
[ -n "$last_update" ] && echo " Last update: $last_update"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
echo ""
|
|
43
|
+
((found++))
|
|
44
|
+
fi
|
|
45
|
+
done
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Also check for in-progress epics
|
|
49
|
+
echo "📚 Active Epics:"
|
|
50
|
+
for epic_dir in .claude/epics/*/; do
|
|
51
|
+
[ -d "$epic_dir" ] || continue
|
|
52
|
+
[ -f "$epic_dir/epic.md" ] || continue
|
|
53
|
+
|
|
54
|
+
status=$(grep "^status:" "$epic_dir/epic.md" | head -1 | sed 's/^status: *//')
|
|
55
|
+
if [ "$status" = "in-progress" ] || [ "$status" = "active" ]; then
|
|
56
|
+
epic_name=$(grep "^name:" "$epic_dir/epic.md" | head -1 | sed 's/^name: *//')
|
|
57
|
+
progress=$(grep "^progress:" "$epic_dir/epic.md" | head -1 | sed 's/^progress: *//')
|
|
58
|
+
[ -z "$epic_name" ] && epic_name=$(basename "$epic_dir")
|
|
59
|
+
[ -z "$progress" ] && progress="0%"
|
|
60
|
+
|
|
61
|
+
echo " • $epic_name - $progress complete"
|
|
62
|
+
fi
|
|
63
|
+
done
|
|
64
|
+
|
|
65
|
+
echo ""
|
|
66
|
+
if [ $found -eq 0 ]; then
|
|
67
|
+
echo "No active work items found."
|
|
68
|
+
echo ""
|
|
69
|
+
echo "💡 Start work with: /pm:next"
|
|
70
|
+
else
|
|
71
|
+
echo "📊 Total active items: $found"
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
exit 0
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
echo "Initializing..."
|
|
4
|
+
echo ""
|
|
5
|
+
echo ""
|
|
6
|
+
|
|
7
|
+
echo " ██████╗ ██████╗██████╗ ███╗ ███╗"
|
|
8
|
+
echo "██╔════╝██╔════╝██╔══██╗████╗ ████║"
|
|
9
|
+
echo "██║ ██║ ██████╔╝██╔████╔██║"
|
|
10
|
+
echo "╚██████╗╚██████╗██║ ██║ ╚═╝ ██║"
|
|
11
|
+
echo " ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═╝"
|
|
12
|
+
|
|
13
|
+
echo "┌─────────────────────────────────┐"
|
|
14
|
+
echo "│ Claude Code Project Management │"
|
|
15
|
+
echo "│ by https://x.com/aroussi │"
|
|
16
|
+
echo "└─────────────────────────────────┘"
|
|
17
|
+
echo "https://github.com/automazeio/ccpm"
|
|
18
|
+
echo ""
|
|
19
|
+
echo ""
|
|
20
|
+
|
|
21
|
+
echo "🚀 Initializing Claude Code PM System"
|
|
22
|
+
echo "======================================"
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
# Check for required tools
|
|
26
|
+
echo "🔍 Checking dependencies..."
|
|
27
|
+
|
|
28
|
+
# Check gh CLI
|
|
29
|
+
if command -v gh &> /dev/null; then
|
|
30
|
+
echo " ✅ GitHub CLI (gh) installed"
|
|
31
|
+
else
|
|
32
|
+
echo " ❌ GitHub CLI (gh) not found"
|
|
33
|
+
echo ""
|
|
34
|
+
echo " Installing gh..."
|
|
35
|
+
if command -v brew &> /dev/null; then
|
|
36
|
+
brew install gh
|
|
37
|
+
elif command -v apt-get &> /dev/null; then
|
|
38
|
+
sudo apt-get update && sudo apt-get install gh
|
|
39
|
+
else
|
|
40
|
+
echo " Please install GitHub CLI manually: https://cli.github.com/"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Check gh auth status
|
|
46
|
+
echo ""
|
|
47
|
+
echo "🔐 Checking GitHub authentication..."
|
|
48
|
+
if gh auth status &> /dev/null; then
|
|
49
|
+
echo " ✅ GitHub authenticated"
|
|
50
|
+
else
|
|
51
|
+
echo " ⚠️ GitHub not authenticated"
|
|
52
|
+
echo " Running: gh auth login"
|
|
53
|
+
gh auth login
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Check for gh-sub-issue extension
|
|
57
|
+
echo ""
|
|
58
|
+
echo "📦 Checking gh extensions..."
|
|
59
|
+
if gh extension list | grep -q "yahsan2/gh-sub-issue"; then
|
|
60
|
+
echo " ✅ gh-sub-issue extension installed"
|
|
61
|
+
else
|
|
62
|
+
echo " 📥 Installing gh-sub-issue extension..."
|
|
63
|
+
gh extension install yahsan2/gh-sub-issue
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Create directory structure
|
|
67
|
+
echo ""
|
|
68
|
+
echo "📁 Creating directory structure..."
|
|
69
|
+
mkdir -p .claude/prds
|
|
70
|
+
mkdir -p .claude/epics
|
|
71
|
+
mkdir -p .claude/rules
|
|
72
|
+
mkdir -p .claude/agents
|
|
73
|
+
mkdir -p .claude/scripts/pm
|
|
74
|
+
echo " ✅ Directories created"
|
|
75
|
+
|
|
76
|
+
# Copy scripts if in main repo
|
|
77
|
+
if [ -d "scripts/pm" ] && [ ! "$(pwd)" = *"/.claude"* ]; then
|
|
78
|
+
echo ""
|
|
79
|
+
echo "📝 Copying PM scripts..."
|
|
80
|
+
cp -r scripts/pm/* .claude/scripts/pm/
|
|
81
|
+
chmod +x .claude/scripts/pm/*.sh
|
|
82
|
+
echo " ✅ Scripts copied and made executable"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# Check for git
|
|
86
|
+
echo ""
|
|
87
|
+
echo "🔗 Checking Git configuration..."
|
|
88
|
+
if git rev-parse --git-dir > /dev/null 2>&1; then
|
|
89
|
+
echo " ✅ Git repository detected"
|
|
90
|
+
|
|
91
|
+
# Check remote
|
|
92
|
+
if git remote -v | grep -q origin; then
|
|
93
|
+
remote_url=$(git remote get-url origin)
|
|
94
|
+
echo " ✅ Remote configured: $remote_url"
|
|
95
|
+
|
|
96
|
+
# Check if remote is the CCPM template repository
|
|
97
|
+
if [[ "$remote_url" == *"automazeio/ccpm"* ]] || [[ "$remote_url" == *"automazeio/ccpm.git"* ]]; then
|
|
98
|
+
echo ""
|
|
99
|
+
echo " ⚠️ WARNING: Your remote origin points to the CCPM template repository!"
|
|
100
|
+
echo " This means any issues you create will go to the template repo, not your project."
|
|
101
|
+
echo ""
|
|
102
|
+
echo " To fix this:"
|
|
103
|
+
echo " 1. Fork the repository or create your own on GitHub"
|
|
104
|
+
echo " 2. Update your remote:"
|
|
105
|
+
echo " git remote set-url origin https://github.com/YOUR_USERNAME/YOUR_REPO.git"
|
|
106
|
+
echo ""
|
|
107
|
+
else
|
|
108
|
+
# Create GitHub labels if this is a GitHub repository
|
|
109
|
+
if gh repo view &> /dev/null; then
|
|
110
|
+
echo ""
|
|
111
|
+
echo "🏷️ Creating GitHub labels..."
|
|
112
|
+
|
|
113
|
+
# Create base labels with improved error handling
|
|
114
|
+
epic_created=false
|
|
115
|
+
task_created=false
|
|
116
|
+
|
|
117
|
+
if gh label create "epic" --color "0E8A16" --description "Epic issue containing multiple related tasks" --force 2>/dev/null; then
|
|
118
|
+
epic_created=true
|
|
119
|
+
elif gh label list 2>/dev/null | grep -q "^epic"; then
|
|
120
|
+
epic_created=true # Label already exists
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
if gh label create "task" --color "1D76DB" --description "Individual task within an epic" --force 2>/dev/null; then
|
|
124
|
+
task_created=true
|
|
125
|
+
elif gh label list 2>/dev/null | grep -q "^task"; then
|
|
126
|
+
task_created=true # Label already exists
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
# Report results
|
|
130
|
+
if $epic_created && $task_created; then
|
|
131
|
+
echo " ✅ GitHub labels created (epic, task)"
|
|
132
|
+
elif $epic_created || $task_created; then
|
|
133
|
+
echo " ⚠️ Some GitHub labels created (epic: $epic_created, task: $task_created)"
|
|
134
|
+
else
|
|
135
|
+
echo " ❌ Could not create GitHub labels (check repository permissions)"
|
|
136
|
+
fi
|
|
137
|
+
else
|
|
138
|
+
echo " ℹ️ Not a GitHub repository - skipping label creation"
|
|
139
|
+
fi
|
|
140
|
+
fi
|
|
141
|
+
else
|
|
142
|
+
echo " ⚠️ No remote configured"
|
|
143
|
+
echo " Add with: git remote add origin <url>"
|
|
144
|
+
fi
|
|
145
|
+
else
|
|
146
|
+
echo " ⚠️ Not a git repository"
|
|
147
|
+
echo " Initialize with: git init"
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
# Create CLAUDE.md if it doesn't exist
|
|
151
|
+
if [ ! -f "CLAUDE.md" ]; then
|
|
152
|
+
echo ""
|
|
153
|
+
echo "📄 Creating CLAUDE.md..."
|
|
154
|
+
cat > CLAUDE.md << 'EOF'
|
|
155
|
+
# CLAUDE.md
|
|
156
|
+
|
|
157
|
+
> Think carefully and implement the most concise solution that changes as little code as possible.
|
|
158
|
+
|
|
159
|
+
## Project-Specific Instructions
|
|
160
|
+
|
|
161
|
+
Add your project-specific instructions here.
|
|
162
|
+
|
|
163
|
+
## Testing
|
|
164
|
+
|
|
165
|
+
Always run tests before committing:
|
|
166
|
+
- `npm test` or equivalent for your stack
|
|
167
|
+
|
|
168
|
+
## Code Style
|
|
169
|
+
|
|
170
|
+
Follow existing patterns in the codebase.
|
|
171
|
+
EOF
|
|
172
|
+
echo " ✅ CLAUDE.md created"
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# Summary
|
|
176
|
+
echo ""
|
|
177
|
+
echo "✅ Initialization Complete!"
|
|
178
|
+
echo "=========================="
|
|
179
|
+
echo ""
|
|
180
|
+
echo "📊 System Status:"
|
|
181
|
+
gh --version | head -1
|
|
182
|
+
echo " Extensions: $(gh extension list | wc -l) installed"
|
|
183
|
+
echo " Auth: $(gh auth status 2>&1 | grep -o 'Logged in to [^ ]*' || echo 'Not authenticated')"
|
|
184
|
+
echo ""
|
|
185
|
+
echo "🎯 Next Steps:"
|
|
186
|
+
echo " 1. Create your first PRD: /pm:prd-new <feature-name>"
|
|
187
|
+
echo " 2. View help: /pm:help"
|
|
188
|
+
echo " 3. Check status: /pm:status"
|
|
189
|
+
echo ""
|
|
190
|
+
echo "📚 Documentation: README.md"
|
|
191
|
+
|
|
192
|
+
exit 0
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
echo "Getting status..."
|
|
3
|
+
echo ""
|
|
4
|
+
echo ""
|
|
5
|
+
|
|
6
|
+
echo "📋 Next Available Tasks"
|
|
7
|
+
echo "======================="
|
|
8
|
+
echo ""
|
|
9
|
+
|
|
10
|
+
# Find tasks that are open and have no dependencies or whose dependencies are closed
|
|
11
|
+
found=0
|
|
12
|
+
|
|
13
|
+
for epic_dir in .claude/epics/*/; do
|
|
14
|
+
[ -d "$epic_dir" ] || continue
|
|
15
|
+
epic_name=$(basename "$epic_dir")
|
|
16
|
+
|
|
17
|
+
for task_file in "$epic_dir"/[0-9]*.md; do
|
|
18
|
+
[ -f "$task_file" ] || continue
|
|
19
|
+
|
|
20
|
+
# Check if task is open
|
|
21
|
+
status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
|
22
|
+
if [ "$status" != "open" ] && [ -n "$status" ]; then
|
|
23
|
+
continue
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Check dependencies
|
|
27
|
+
# Extract dependencies from task file
|
|
28
|
+
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
|
29
|
+
if [ -n "$deps_line" ]; then
|
|
30
|
+
deps=$(echo "$deps_line" | sed 's/^depends_on: *//')
|
|
31
|
+
deps=$(echo "$deps" | sed 's/^\[//' | sed 's/\]$//')
|
|
32
|
+
# Trim whitespace and handle empty cases
|
|
33
|
+
deps=$(echo "$deps" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
|
34
|
+
[ -z "$deps" ] && deps=""
|
|
35
|
+
else
|
|
36
|
+
deps=""
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# If no dependencies or empty, task is available
|
|
40
|
+
if [ -z "$deps" ] || [ "$deps" = "depends_on:" ]; then
|
|
41
|
+
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
|
42
|
+
task_num=$(basename "$task_file" .md)
|
|
43
|
+
parallel=$(grep "^parallel:" "$task_file" | head -1 | sed 's/^parallel: *//')
|
|
44
|
+
|
|
45
|
+
echo "✅ Ready: #$task_num - $task_name"
|
|
46
|
+
echo " Epic: $epic_name"
|
|
47
|
+
[ "$parallel" = "true" ] && echo " 🔄 Can run in parallel"
|
|
48
|
+
echo ""
|
|
49
|
+
((found++))
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
done
|
|
53
|
+
|
|
54
|
+
if [ $found -eq 0 ]; then
|
|
55
|
+
echo "No available tasks found."
|
|
56
|
+
echo ""
|
|
57
|
+
echo "💡 Suggestions:"
|
|
58
|
+
echo " • Check blocked tasks: /pm:blocked"
|
|
59
|
+
echo " • View all tasks: /pm:epic-list"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
echo ""
|
|
63
|
+
echo "📊 Summary: $found tasks ready to start"
|
|
64
|
+
|
|
65
|
+
exit 0
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# !/bin/bash
|
|
2
|
+
# Check if PRD directory exists
|
|
3
|
+
if [ ! -d ".claude/prds" ]; then
|
|
4
|
+
echo "📁 No PRD directory found. Create your first PRD with: /pm:prd-new <feature-name>"
|
|
5
|
+
exit 0
|
|
6
|
+
fi
|
|
7
|
+
|
|
8
|
+
# Check for PRD files
|
|
9
|
+
if ! ls .claude/prds/*.md >/dev/null 2>&1; then
|
|
10
|
+
echo "📁 No PRDs found. Create your first PRD with: /pm:prd-new <feature-name>"
|
|
11
|
+
exit 0
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
# Initialize counters
|
|
15
|
+
backlog_count=0
|
|
16
|
+
in_progress_count=0
|
|
17
|
+
implemented_count=0
|
|
18
|
+
total_count=0
|
|
19
|
+
|
|
20
|
+
echo "Getting PRDs..."
|
|
21
|
+
echo ""
|
|
22
|
+
echo ""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
echo "📋 PRD List"
|
|
26
|
+
echo "==========="
|
|
27
|
+
echo ""
|
|
28
|
+
|
|
29
|
+
# Display by status groups
|
|
30
|
+
echo "🔍 Backlog PRDs:"
|
|
31
|
+
for file in .claude/prds/*.md; do
|
|
32
|
+
[ -f "$file" ] || continue
|
|
33
|
+
status=$(grep "^status:" "$file" | head -1 | sed 's/^status: *//')
|
|
34
|
+
if [ "$status" = "backlog" ] || [ "$status" = "draft" ] || [ -z "$status" ]; then
|
|
35
|
+
name=$(grep "^name:" "$file" | head -1 | sed 's/^name: *//')
|
|
36
|
+
desc=$(grep "^description:" "$file" | head -1 | sed 's/^description: *//')
|
|
37
|
+
[ -z "$name" ] && name=$(basename "$file" .md)
|
|
38
|
+
[ -z "$desc" ] && desc="No description"
|
|
39
|
+
# echo " 📋 $name - $desc"
|
|
40
|
+
echo " 📋 $file - $desc"
|
|
41
|
+
((backlog_count++))
|
|
42
|
+
fi
|
|
43
|
+
((total_count++))
|
|
44
|
+
done
|
|
45
|
+
[ $backlog_count -eq 0 ] && echo " (none)"
|
|
46
|
+
|
|
47
|
+
echo ""
|
|
48
|
+
echo "🔄 In-Progress PRDs:"
|
|
49
|
+
for file in .claude/prds/*.md; do
|
|
50
|
+
[ -f "$file" ] || continue
|
|
51
|
+
status=$(grep "^status:" "$file" | head -1 | sed 's/^status: *//')
|
|
52
|
+
if [ "$status" = "in-progress" ] || [ "$status" = "active" ]; then
|
|
53
|
+
name=$(grep "^name:" "$file" | head -1 | sed 's/^name: *//')
|
|
54
|
+
desc=$(grep "^description:" "$file" | head -1 | sed 's/^description: *//')
|
|
55
|
+
[ -z "$name" ] && name=$(basename "$file" .md)
|
|
56
|
+
[ -z "$desc" ] && desc="No description"
|
|
57
|
+
# echo " 📋 $name - $desc"
|
|
58
|
+
echo " 📋 $file - $desc"
|
|
59
|
+
((in_progress_count++))
|
|
60
|
+
fi
|
|
61
|
+
done
|
|
62
|
+
[ $in_progress_count -eq 0 ] && echo " (none)"
|
|
63
|
+
|
|
64
|
+
echo ""
|
|
65
|
+
echo "✅ Implemented PRDs:"
|
|
66
|
+
for file in .claude/prds/*.md; do
|
|
67
|
+
[ -f "$file" ] || continue
|
|
68
|
+
status=$(grep "^status:" "$file" | head -1 | sed 's/^status: *//')
|
|
69
|
+
if [ "$status" = "implemented" ] || [ "$status" = "completed" ] || [ "$status" = "done" ]; then
|
|
70
|
+
name=$(grep "^name:" "$file" | head -1 | sed 's/^name: *//')
|
|
71
|
+
desc=$(grep "^description:" "$file" | head -1 | sed 's/^description: *//')
|
|
72
|
+
[ -z "$name" ] && name=$(basename "$file" .md)
|
|
73
|
+
[ -z "$desc" ] && desc="No description"
|
|
74
|
+
# echo " 📋 $name - $desc"
|
|
75
|
+
echo " 📋 $file - $desc"
|
|
76
|
+
((implemented_count++))
|
|
77
|
+
fi
|
|
78
|
+
done
|
|
79
|
+
[ $implemented_count -eq 0 ] && echo " (none)"
|
|
80
|
+
|
|
81
|
+
# Display summary
|
|
82
|
+
echo ""
|
|
83
|
+
echo "📊 PRD Summary"
|
|
84
|
+
echo " Total PRDs: $total_count"
|
|
85
|
+
echo " Backlog: $backlog_count"
|
|
86
|
+
echo " In-Progress: $in_progress_count"
|
|
87
|
+
echo " Implemented: $implemented_count"
|
|
88
|
+
|
|
89
|
+
exit 0
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
echo "📄 PRD Status Report"
|
|
4
|
+
echo "===================="
|
|
5
|
+
echo ""
|
|
6
|
+
|
|
7
|
+
if [ ! -d ".claude/prds" ]; then
|
|
8
|
+
echo "No PRD directory found."
|
|
9
|
+
exit 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
total=$(ls .claude/prds/*.md 2>/dev/null | wc -l)
|
|
13
|
+
[ $total -eq 0 ] && echo "No PRDs found." && exit 0
|
|
14
|
+
|
|
15
|
+
# Count by status
|
|
16
|
+
backlog=0
|
|
17
|
+
in_progress=0
|
|
18
|
+
implemented=0
|
|
19
|
+
|
|
20
|
+
for file in .claude/prds/*.md; do
|
|
21
|
+
[ -f "$file" ] || continue
|
|
22
|
+
status=$(grep "^status:" "$file" | head -1 | sed 's/^status: *//')
|
|
23
|
+
|
|
24
|
+
case "$status" in
|
|
25
|
+
backlog|draft|"") ((backlog++)) ;;
|
|
26
|
+
in-progress|active) ((in_progress++)) ;;
|
|
27
|
+
implemented|completed|done) ((implemented++)) ;;
|
|
28
|
+
*) ((backlog++)) ;;
|
|
29
|
+
esac
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
echo "Getting status..."
|
|
33
|
+
echo ""
|
|
34
|
+
echo ""
|
|
35
|
+
|
|
36
|
+
# Display chart
|
|
37
|
+
echo "📊 Distribution:"
|
|
38
|
+
echo "================"
|
|
39
|
+
|
|
40
|
+
echo ""
|
|
41
|
+
echo " Backlog: $(printf '%-3d' $backlog) [$(printf '%0.s█' $(seq 1 $((backlog*20/total))))]"
|
|
42
|
+
echo " In Progress: $(printf '%-3d' $in_progress) [$(printf '%0.s█' $(seq 1 $((in_progress*20/total))))]"
|
|
43
|
+
echo " Implemented: $(printf '%-3d' $implemented) [$(printf '%0.s█' $(seq 1 $((implemented*20/total))))]"
|
|
44
|
+
echo ""
|
|
45
|
+
echo " Total PRDs: $total"
|
|
46
|
+
|
|
47
|
+
# Recent activity
|
|
48
|
+
echo ""
|
|
49
|
+
echo "📅 Recent PRDs (last 5 modified):"
|
|
50
|
+
ls -t .claude/prds/*.md 2>/dev/null | head -5 | while read file; do
|
|
51
|
+
name=$(grep "^name:" "$file" | head -1 | sed 's/^name: *//')
|
|
52
|
+
[ -z "$name" ] && name=$(basename "$file" .md)
|
|
53
|
+
echo " • $name"
|
|
54
|
+
done
|
|
55
|
+
|
|
56
|
+
# Suggestions
|
|
57
|
+
echo ""
|
|
58
|
+
echo "💡 Next Actions:"
|
|
59
|
+
[ $backlog -gt 0 ] && echo " • Parse backlog PRDs to epics: /pm:prd-parse <name>"
|
|
60
|
+
[ $in_progress -gt 0 ] && echo " • Check progress on active PRDs: /pm:epic-status <name>"
|
|
61
|
+
[ $total -eq 0 ] && echo " • Create your first PRD: /pm:prd-new <name>"
|
|
62
|
+
|
|
63
|
+
exit 0
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
query="$1"
|
|
4
|
+
|
|
5
|
+
if [ -z "$query" ]; then
|
|
6
|
+
echo "❌ Please provide a search query"
|
|
7
|
+
echo "Usage: /pm:search <query>"
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
echo "Searching for '$query'..."
|
|
12
|
+
echo ""
|
|
13
|
+
echo ""
|
|
14
|
+
|
|
15
|
+
echo "🔍 Search results for: '$query'"
|
|
16
|
+
echo "================================"
|
|
17
|
+
echo ""
|
|
18
|
+
|
|
19
|
+
# Search in PRDs
|
|
20
|
+
if [ -d ".claude/prds" ]; then
|
|
21
|
+
echo "📄 PRDs:"
|
|
22
|
+
results=$(grep -l -i "$query" .claude/prds/*.md 2>/dev/null)
|
|
23
|
+
if [ -n "$results" ]; then
|
|
24
|
+
for file in $results; do
|
|
25
|
+
name=$(basename "$file" .md)
|
|
26
|
+
matches=$(grep -c -i "$query" "$file")
|
|
27
|
+
echo " • $name ($matches matches)"
|
|
28
|
+
done
|
|
29
|
+
else
|
|
30
|
+
echo " No matches"
|
|
31
|
+
fi
|
|
32
|
+
echo ""
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Search in Epics
|
|
36
|
+
if [ -d ".claude/epics" ]; then
|
|
37
|
+
echo "📚 Epics:"
|
|
38
|
+
results=$(find .claude/epics -name "epic.md" -exec grep -l -i "$query" {} \; 2>/dev/null)
|
|
39
|
+
if [ -n "$results" ]; then
|
|
40
|
+
for file in $results; do
|
|
41
|
+
epic_name=$(basename $(dirname "$file"))
|
|
42
|
+
matches=$(grep -c -i "$query" "$file")
|
|
43
|
+
echo " • $epic_name ($matches matches)"
|
|
44
|
+
done
|
|
45
|
+
else
|
|
46
|
+
echo " No matches"
|
|
47
|
+
fi
|
|
48
|
+
echo ""
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Search in Tasks
|
|
52
|
+
if [ -d ".claude/epics" ]; then
|
|
53
|
+
echo "📝 Tasks:"
|
|
54
|
+
results=$(find .claude/epics -name "[0-9]*.md" -exec grep -l -i "$query" {} \; 2>/dev/null | head -10)
|
|
55
|
+
if [ -n "$results" ]; then
|
|
56
|
+
for file in $results; do
|
|
57
|
+
epic_name=$(basename $(dirname "$file"))
|
|
58
|
+
task_num=$(basename "$file" .md)
|
|
59
|
+
echo " • Task #$task_num in $epic_name"
|
|
60
|
+
done
|
|
61
|
+
else
|
|
62
|
+
echo " No matches"
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Summary
|
|
67
|
+
total=$(find .claude -name "*.md" -exec grep -l -i "$query" {} \; 2>/dev/null | wc -l)
|
|
68
|
+
echo ""
|
|
69
|
+
echo "📊 Total files with matches: $total"
|
|
70
|
+
|
|
71
|
+
exit 0
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
echo "📅 Daily Standup - $(date '+%Y-%m-%d')"
|
|
4
|
+
echo "================================"
|
|
5
|
+
echo ""
|
|
6
|
+
|
|
7
|
+
today=$(date '+%Y-%m-%d')
|
|
8
|
+
|
|
9
|
+
echo "Getting status..."
|
|
10
|
+
echo ""
|
|
11
|
+
echo ""
|
|
12
|
+
|
|
13
|
+
echo "📝 Today's Activity:"
|
|
14
|
+
echo "===================="
|
|
15
|
+
echo ""
|
|
16
|
+
|
|
17
|
+
# Find files modified today
|
|
18
|
+
recent_files=$(find .claude -name "*.md" -mtime -1 2>/dev/null)
|
|
19
|
+
|
|
20
|
+
if [ -n "$recent_files" ]; then
|
|
21
|
+
# Count by type
|
|
22
|
+
prd_count=$(echo "$recent_files" | grep -c "/prds/" || echo 0)
|
|
23
|
+
epic_count=$(echo "$recent_files" | grep -c "/epic.md" || echo 0)
|
|
24
|
+
task_count=$(echo "$recent_files" | grep -c "/[0-9]*.md" || echo 0)
|
|
25
|
+
update_count=$(echo "$recent_files" | grep -c "/updates/" || echo 0)
|
|
26
|
+
|
|
27
|
+
[ $prd_count -gt 0 ] && echo " • Modified $prd_count PRD(s)"
|
|
28
|
+
[ $epic_count -gt 0 ] && echo " • Updated $epic_count epic(s)"
|
|
29
|
+
[ $task_count -gt 0 ] && echo " • Worked on $task_count task(s)"
|
|
30
|
+
[ $update_count -gt 0 ] && echo " • Posted $update_count progress update(s)"
|
|
31
|
+
else
|
|
32
|
+
echo " No activity recorded today"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
echo ""
|
|
36
|
+
echo "🔄 Currently In Progress:"
|
|
37
|
+
# Show active work items
|
|
38
|
+
for updates_dir in .claude/epics/*/updates/*/; do
|
|
39
|
+
[ -d "$updates_dir" ] || continue
|
|
40
|
+
if [ -f "$updates_dir/progress.md" ]; then
|
|
41
|
+
issue_num=$(basename "$updates_dir")
|
|
42
|
+
epic_name=$(basename $(dirname $(dirname "$updates_dir")))
|
|
43
|
+
completion=$(grep "^completion:" "$updates_dir/progress.md" | head -1 | sed 's/^completion: *//')
|
|
44
|
+
echo " • Issue #$issue_num ($epic_name) - ${completion:-0%} complete"
|
|
45
|
+
fi
|
|
46
|
+
done
|
|
47
|
+
|
|
48
|
+
echo ""
|
|
49
|
+
echo "⏭️ Next Available Tasks:"
|
|
50
|
+
# Show top 3 available tasks
|
|
51
|
+
count=0
|
|
52
|
+
for epic_dir in .claude/epics/*/; do
|
|
53
|
+
[ -d "$epic_dir" ] || continue
|
|
54
|
+
for task_file in "$epic_dir"/[0-9]*.md; do
|
|
55
|
+
[ -f "$task_file" ] || continue
|
|
56
|
+
status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
|
57
|
+
if [ "$status" != "open" ] && [ -n "$status" ]; then
|
|
58
|
+
continue
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Extract dependencies from task file
|
|
62
|
+
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
|
63
|
+
if [ -n "$deps_line" ]; then
|
|
64
|
+
deps=$(echo "$deps_line" | sed 's/^depends_on: *//')
|
|
65
|
+
deps=$(echo "$deps" | sed 's/^\[//' | sed 's/\]$//')
|
|
66
|
+
# Trim whitespace and handle empty cases
|
|
67
|
+
deps=$(echo "$deps" | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
|
68
|
+
[ -z "$deps" ] && deps=""
|
|
69
|
+
else
|
|
70
|
+
deps=""
|
|
71
|
+
fi
|
|
72
|
+
if [ -z "$deps" ] || [ "$deps" = "depends_on:" ]; then
|
|
73
|
+
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
|
74
|
+
task_num=$(basename "$task_file" .md)
|
|
75
|
+
echo " • #$task_num - $task_name"
|
|
76
|
+
((count++))
|
|
77
|
+
[ $count -ge 3 ] && break 2
|
|
78
|
+
fi
|
|
79
|
+
done
|
|
80
|
+
done
|
|
81
|
+
|
|
82
|
+
echo ""
|
|
83
|
+
echo "📊 Quick Stats:"
|
|
84
|
+
total_tasks=$(find .claude/epics -name "[0-9]*.md" 2>/dev/null | wc -l)
|
|
85
|
+
open_tasks=$(find .claude/epics -name "[0-9]*.md" -exec grep -l "^status: *open" {} \; 2>/dev/null | wc -l)
|
|
86
|
+
closed_tasks=$(find .claude/epics -name "[0-9]*.md" -exec grep -l "^status: *closed" {} \; 2>/dev/null | wc -l)
|
|
87
|
+
echo " Tasks: $open_tasks open, $closed_tasks closed, $total_tasks total"
|
|
88
|
+
|
|
89
|
+
exit 0
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
echo "Getting status..."
|
|
4
|
+
echo ""
|
|
5
|
+
echo ""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
echo "📊 Project Status"
|
|
9
|
+
echo "================"
|
|
10
|
+
echo ""
|
|
11
|
+
|
|
12
|
+
echo "📄 PRDs:"
|
|
13
|
+
if [ -d ".claude/prds" ]; then
|
|
14
|
+
total=$(ls .claude/prds/*.md 2>/dev/null | wc -l)
|
|
15
|
+
echo " Total: $total"
|
|
16
|
+
else
|
|
17
|
+
echo " No PRDs found"
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
echo ""
|
|
21
|
+
echo "📚 Epics:"
|
|
22
|
+
if [ -d ".claude/epics" ]; then
|
|
23
|
+
total=$(ls -d .claude/epics/*/ 2>/dev/null | wc -l)
|
|
24
|
+
echo " Total: $total"
|
|
25
|
+
else
|
|
26
|
+
echo " No epics found"
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
echo ""
|
|
30
|
+
echo "📝 Tasks:"
|
|
31
|
+
if [ -d ".claude/epics" ]; then
|
|
32
|
+
total=$(find .claude/epics -name "[0-9]*.md" 2>/dev/null | wc -l)
|
|
33
|
+
open=$(find .claude/epics -name "[0-9]*.md" -exec grep -l "^status: *open" {} \; 2>/dev/null | wc -l)
|
|
34
|
+
closed=$(find .claude/epics -name "[0-9]*.md" -exec grep -l "^status: *closed" {} \; 2>/dev/null | wc -l)
|
|
35
|
+
echo " Open: $open"
|
|
36
|
+
echo " Closed: $closed"
|
|
37
|
+
echo " Total: $total"
|
|
38
|
+
else
|
|
39
|
+
echo " No tasks found"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
exit 0
|