claude-autopm 1.20.0 → 1.21.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/README.md +255 -878
- package/autopm/.claude/agents/README.md +1 -1
- package/autopm/.claude/agents/decision-matrices/python-backend-selection.md +25 -25
- package/autopm/.claude/agents/decision-matrices/ui-framework-selection.md +43 -43
- package/autopm/.claude/agents/devops/github-operations-specialist.md +1 -1
- package/autopm/.claude/agents/frameworks/README.md +5 -5
- package/autopm/.claude/agents/frameworks/e2e-test-engineer.md +1 -1
- package/autopm/.claude/agents/frameworks/nats-messaging-expert.md +1 -1
- package/autopm/.claude/agents/frameworks/react-frontend-engineer.md +1 -1
- package/autopm/.claude/agents/frameworks/react-ui-expert.md +3 -3
- package/autopm/.claude/agents/frameworks/tailwindcss-expert.md +3 -3
- package/autopm/.claude/agents/frameworks/ux-design-expert.md +3 -3
- package/autopm/.claude/commands/infrastructure/traefik-setup.md +1 -1
- package/autopm/.claude/commands/playwright/test-scaffold.md +1 -1
- package/autopm/.claude/commands/pm/epic-sync.md +37 -4
- package/autopm/.claude/commands/ui/bootstrap-scaffold.md +6 -5
- package/autopm/.claude/commands/ui/tailwind-system.md +1 -1
- package/autopm/.claude/examples/mcp/playwright-mcp.md +2 -2
- package/autopm/.claude/examples/mcp-servers.example.json +2 -2
- package/autopm/.claude/hooks/docker-first-enforcement.sh +1 -1
- package/autopm/.claude/mcp/playwright-mcp.md +2 -2
- package/autopm/.claude/rules/agent-coordination.md +26 -24
- package/autopm/.claude/rules/docker-first-development.md +1 -1
- package/autopm/.claude/rules/framework-path-rules.md +180 -0
- package/autopm/.claude/rules/infrastructure-pipeline.md +1 -1
- package/autopm/.claude/rules/ui-development-standards.md +1 -1
- package/autopm/.claude/rules/visual-testing.md +3 -3
- package/autopm/.claude/scripts/pm/epic-sync/README.md +208 -0
- package/autopm/.claude/scripts/pm/epic-sync/create-epic-issue.sh +68 -192
- package/autopm/.claude/scripts/pm/epic-sync/create-task-issues.sh +60 -328
- package/autopm/.claude/scripts/pm/epic-sync/update-epic-file.sh +61 -354
- package/autopm/.claude/scripts/pm/epic-sync/update-references.sh +67 -305
- package/autopm/.claude/scripts/pm/epic-sync.sh +137 -0
- package/autopm/.claude/teams.json +3 -5
- package/autopm/.claude/templates/claude-templates/addons/devops-agents.md +2 -2
- package/autopm/.claude/templates/claude-templates/addons/docker-agents.md +4 -4
- package/autopm/.claude/templates/claude-templates/addons/minimal-agents.md +1 -1
- package/autopm/.claude/templates/issue-decomposition/api.yaml +2 -2
- package/autopm/.claude/templates/issue-decomposition/auth.yaml +4 -4
- package/autopm/.claude/templates/issue-decomposition/crud.yaml +3 -3
- package/autopm/.claude/templates/issue-decomposition/default.yaml +1 -1
- package/autopm/.claude/templates/issue-decomposition/ui-feature.yaml +2 -2
- package/package.json +4 -3
- package/scripts/validate-framework-paths.sh +104 -0
|
@@ -1,372 +1,79 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# Update Epic File
|
|
3
|
-
# Updates epic.md with GitHub URL
|
|
2
|
+
# Update Epic File
|
|
3
|
+
# Updates epic.md with GitHub URL and real task issue numbers
|
|
4
4
|
|
|
5
5
|
set -euo pipefail
|
|
6
6
|
|
|
7
|
-
# Load libraries
|
|
8
7
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
source "${SCRIPT_DIR}/../../lib/frontmatter-utils.sh"
|
|
12
|
-
source "${SCRIPT_DIR}/../../lib/validation-utils.sh"
|
|
13
|
-
source "${SCRIPT_DIR}/../../lib/datetime-utils.sh"
|
|
8
|
+
EPIC_NAME="${1:-}"
|
|
9
|
+
EPIC_NUMBER="${2:-}"
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
declare -g temp_dir=""
|
|
21
|
-
declare -g epic_file=""
|
|
22
|
-
|
|
23
|
-
# Main function
|
|
24
|
-
main() {
|
|
25
|
-
print_banner "Epic File Updater" "1.0.0"
|
|
26
|
-
|
|
27
|
-
# Validate inputs
|
|
28
|
-
log_info "Validating inputs: epic=$EPIC_NAME, epic_issue=$EPIC_ISSUE_NUMBER"
|
|
29
|
-
validate_inputs || exit 1
|
|
30
|
-
|
|
31
|
-
# Setup workspace
|
|
32
|
-
setup_workspace
|
|
33
|
-
|
|
34
|
-
# Update epic frontmatter
|
|
35
|
-
with_error_handling "Update epic frontmatter" \
|
|
36
|
-
update_epic_frontmatter
|
|
37
|
-
|
|
38
|
-
# Update Tasks Created section
|
|
39
|
-
with_error_handling "Update Tasks Created section" \
|
|
40
|
-
update_tasks_created_section
|
|
41
|
-
|
|
42
|
-
# Create GitHub mapping file
|
|
43
|
-
with_error_handling "Create GitHub mapping file" \
|
|
44
|
-
create_github_mapping_file
|
|
45
|
-
|
|
46
|
-
# Display results
|
|
47
|
-
display_results
|
|
48
|
-
|
|
49
|
-
log_success "Epic file update completed successfully"
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
# Validate script inputs
|
|
53
|
-
validate_inputs() {
|
|
54
|
-
log_function_entry "validate_inputs"
|
|
55
|
-
|
|
56
|
-
validate_epic_name "$EPIC_NAME" || return 1
|
|
57
|
-
validate_issue_number "$EPIC_ISSUE_NUMBER" || return 1
|
|
58
|
-
validate_epic_structure "$EPIC_NAME" || return 1
|
|
59
|
-
validate_github_auth || return 1
|
|
60
|
-
|
|
61
|
-
epic_file=".claude/epics/$EPIC_NAME/epic.md"
|
|
62
|
-
validate_file_exists "$epic_file" "Epic file" || return 1
|
|
63
|
-
|
|
64
|
-
log_function_exit "validate_inputs"
|
|
65
|
-
return 0
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
# Setup temporary workspace
|
|
69
|
-
setup_workspace() {
|
|
70
|
-
log_function_entry "setup_workspace"
|
|
71
|
-
|
|
72
|
-
temp_dir="/tmp/update-epic-$$"
|
|
73
|
-
|
|
74
|
-
log_info "Creating workspace: $temp_dir"
|
|
75
|
-
mkdir -p "$temp_dir"
|
|
76
|
-
|
|
77
|
-
# Cleanup on exit
|
|
78
|
-
trap "cleanup_workspace" EXIT
|
|
79
|
-
|
|
80
|
-
log_function_exit "setup_workspace"
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
# Cleanup workspace
|
|
84
|
-
cleanup_workspace() {
|
|
85
|
-
if [[ -n "$temp_dir" ]] && [[ -d "$temp_dir" ]]; then
|
|
86
|
-
log_debug "Cleaning up workspace: $temp_dir"
|
|
87
|
-
rm -rf "$temp_dir"
|
|
88
|
-
fi
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
# Update epic frontmatter with GitHub URL and timestamp
|
|
92
|
-
update_epic_frontmatter() {
|
|
93
|
-
log_function_entry "update_epic_frontmatter"
|
|
94
|
-
|
|
95
|
-
# Get repository info
|
|
96
|
-
local repo_info
|
|
97
|
-
repo_info=$(get_repo_info)
|
|
98
|
-
local repo_name
|
|
99
|
-
repo_name=$(echo "$repo_info" | grep -o '"nameWithOwner":"[^"]*"' | cut -d'"' -f4)
|
|
100
|
-
|
|
101
|
-
local epic_url="https://github.com/$repo_name/issues/$EPIC_ISSUE_NUMBER"
|
|
102
|
-
local current_datetime
|
|
103
|
-
current_datetime=$(get_current_datetime)
|
|
104
|
-
|
|
105
|
-
log_info "Updating epic frontmatter"
|
|
106
|
-
log_debug "Repository: $repo_name"
|
|
107
|
-
log_debug "Epic URL: $epic_url"
|
|
108
|
-
log_debug "Timestamp: $current_datetime"
|
|
109
|
-
|
|
110
|
-
# Update frontmatter fields
|
|
111
|
-
update_frontmatter_field "$epic_file" "github" "$epic_url"
|
|
112
|
-
update_frontmatter_field "$epic_file" "updated" "$current_datetime"
|
|
113
|
-
|
|
114
|
-
log_success "Epic frontmatter updated"
|
|
115
|
-
log_function_exit "update_epic_frontmatter"
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
# Update the Tasks Created section with real issue numbers
|
|
119
|
-
update_tasks_created_section() {
|
|
120
|
-
log_function_entry "update_tasks_created_section"
|
|
121
|
-
|
|
122
|
-
local epic_dir=".claude/epics/$EPIC_NAME"
|
|
123
|
-
local tasks_section_file="$temp_dir/tasks-section.md"
|
|
124
|
-
|
|
125
|
-
# Create new Tasks Created section
|
|
126
|
-
cat > "$tasks_section_file" << 'EOF'
|
|
127
|
-
## Tasks Created
|
|
128
|
-
EOF
|
|
129
|
-
|
|
130
|
-
local task_count=0
|
|
131
|
-
|
|
132
|
-
# Add each task with its real issue number
|
|
133
|
-
local task_files=()
|
|
134
|
-
readarray -t task_files < <(find "$epic_dir" -name '[0-9]*.md' -type f | sort -n)
|
|
135
|
-
|
|
136
|
-
for task_file in "${task_files[@]}"; do
|
|
137
|
-
[[ -f "$task_file" ]] || continue
|
|
138
|
-
|
|
139
|
-
# Get issue number (filename without .md)
|
|
140
|
-
local issue_num
|
|
141
|
-
issue_num=$(basename "$task_file" .md)
|
|
142
|
-
|
|
143
|
-
# Get task name from frontmatter
|
|
144
|
-
local task_name
|
|
145
|
-
task_name=$(get_frontmatter_field "$task_file" "name" 2>/dev/null || echo "Unknown Task")
|
|
146
|
-
|
|
147
|
-
# Get parallel status
|
|
148
|
-
local parallel
|
|
149
|
-
parallel=$(get_frontmatter_field "$task_file" "parallel" 2>/dev/null || echo "false")
|
|
150
|
-
|
|
151
|
-
# Add to tasks section
|
|
152
|
-
echo "- [ ] #${issue_num} - ${task_name} (parallel: ${parallel})" >> "$tasks_section_file"
|
|
153
|
-
task_count=$((task_count + 1))
|
|
154
|
-
log_debug "Added task: #$issue_num - $task_name"
|
|
155
|
-
done
|
|
156
|
-
|
|
157
|
-
# Calculate and add summary statistics
|
|
158
|
-
local parallel_count sequential_count
|
|
159
|
-
parallel_count=$(grep -l '^parallel: true' "$epic_dir"/[0-9]*.md 2>/dev/null | wc -l || echo 0)
|
|
160
|
-
sequential_count=$((task_count - parallel_count))
|
|
161
|
-
|
|
162
|
-
cat >> "$tasks_section_file" << EOF
|
|
163
|
-
|
|
164
|
-
Total tasks: ${task_count}
|
|
165
|
-
Parallel tasks: ${parallel_count}
|
|
166
|
-
Sequential tasks: ${sequential_count}
|
|
167
|
-
EOF
|
|
168
|
-
|
|
169
|
-
log_info "Generated tasks section: $task_count tasks ($parallel_count parallel, $sequential_count sequential)"
|
|
170
|
-
|
|
171
|
-
# Replace the Tasks Created section in epic.md
|
|
172
|
-
replace_tasks_created_section "$tasks_section_file"
|
|
173
|
-
|
|
174
|
-
log_success "Tasks Created section updated"
|
|
175
|
-
log_function_exit "update_tasks_created_section"
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
# Replace the Tasks Created section in epic.md
|
|
179
|
-
replace_tasks_created_section() {
|
|
180
|
-
local tasks_section_file="$1"
|
|
181
|
-
|
|
182
|
-
log_function_entry "replace_tasks_created_section"
|
|
183
|
-
|
|
184
|
-
# Create backup
|
|
185
|
-
local backup_file="$epic_file.backup"
|
|
186
|
-
cp "$epic_file" "$backup_file"
|
|
187
|
-
|
|
188
|
-
# Use awk to replace the section
|
|
189
|
-
awk -v tasks_file="$tasks_section_file" '
|
|
190
|
-
/^## Tasks Created/ {
|
|
191
|
-
skip=1
|
|
192
|
-
while ((getline line < tasks_file) > 0) print line
|
|
193
|
-
close(tasks_file)
|
|
194
|
-
next
|
|
195
|
-
}
|
|
196
|
-
/^## / && !/^## Tasks Created/ {
|
|
197
|
-
skip=0
|
|
198
|
-
}
|
|
199
|
-
!skip && !/^## Tasks Created/ {
|
|
200
|
-
print
|
|
201
|
-
}
|
|
202
|
-
' "$backup_file" > "$epic_file"
|
|
203
|
-
|
|
204
|
-
# Clean up backup
|
|
205
|
-
rm "$backup_file"
|
|
206
|
-
|
|
207
|
-
log_debug "Replaced Tasks Created section using awk"
|
|
208
|
-
log_function_exit "replace_tasks_created_section"
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
# Create GitHub mapping file for reference
|
|
212
|
-
create_github_mapping_file() {
|
|
213
|
-
log_function_entry "create_github_mapping_file"
|
|
214
|
-
|
|
215
|
-
local epic_dir=".claude/epics/$EPIC_NAME"
|
|
216
|
-
local mapping_file="$epic_dir/github-mapping.md"
|
|
217
|
-
|
|
218
|
-
# Get repository info
|
|
219
|
-
local repo_info
|
|
220
|
-
repo_info=$(get_repo_info)
|
|
221
|
-
local repo_name
|
|
222
|
-
repo_name=$(echo "$repo_info" | grep -o '"nameWithOwner":"[^"]*"' | cut -d'"' -f4)
|
|
223
|
-
|
|
224
|
-
# Create mapping file
|
|
225
|
-
cat > "$mapping_file" << EOF
|
|
226
|
-
# GitHub Issue Mapping
|
|
227
|
-
|
|
228
|
-
Epic: #${EPIC_ISSUE_NUMBER} - https://github.com/${repo_name}/issues/${EPIC_ISSUE_NUMBER}
|
|
229
|
-
|
|
230
|
-
Tasks:
|
|
231
|
-
EOF
|
|
232
|
-
|
|
233
|
-
# Add each task mapping
|
|
234
|
-
local task_files=()
|
|
235
|
-
readarray -t task_files < <(find "$epic_dir" -name '[0-9]*.md' -type f | sort -n)
|
|
236
|
-
|
|
237
|
-
for task_file in "${task_files[@]}"; do
|
|
238
|
-
[[ -f "$task_file" ]] || continue
|
|
239
|
-
|
|
240
|
-
local issue_num
|
|
241
|
-
issue_num=$(basename "$task_file" .md)
|
|
242
|
-
|
|
243
|
-
local task_name
|
|
244
|
-
task_name=$(get_frontmatter_field "$task_file" "name" 2>/dev/null || echo "Unknown Task")
|
|
245
|
-
|
|
246
|
-
echo "- #${issue_num}: ${task_name} - https://github.com/${repo_name}/issues/${issue_num}" >> "$mapping_file"
|
|
247
|
-
done
|
|
248
|
-
|
|
249
|
-
# Add sync timestamp
|
|
250
|
-
local current_datetime
|
|
251
|
-
current_datetime=$(get_current_datetime)
|
|
252
|
-
|
|
253
|
-
cat >> "$mapping_file" << EOF
|
|
254
|
-
|
|
255
|
-
Synced: ${current_datetime}
|
|
256
|
-
EOF
|
|
257
|
-
|
|
258
|
-
log_info "Created GitHub mapping file: $mapping_file"
|
|
259
|
-
log_function_exit "create_github_mapping_file"
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
# Display update results
|
|
263
|
-
display_results() {
|
|
264
|
-
local epic_dir=".claude/epics/$EPIC_NAME"
|
|
265
|
-
|
|
266
|
-
print_section "✅ Epic File Update Results"
|
|
267
|
-
|
|
268
|
-
echo "Epic: $EPIC_NAME"
|
|
269
|
-
echo "GitHub Issue: #$EPIC_ISSUE_NUMBER"
|
|
11
|
+
if [[ -z "$EPIC_NAME" ]] || [[ -z "$EPIC_NUMBER" ]]; then
|
|
12
|
+
echo "❌ Error: Epic name and epic number required"
|
|
13
|
+
echo "Usage: $0 <epic_name> <epic_number>"
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
270
16
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
updated_field=$(get_frontmatter_field "$epic_file" "updated" 2>/dev/null || echo "")
|
|
17
|
+
EPIC_DIR=".claude/epics/$EPIC_NAME"
|
|
18
|
+
EPIC_FILE="$EPIC_DIR/epic.md"
|
|
19
|
+
MAPPING_FILE="$EPIC_DIR/.task-mapping.txt"
|
|
275
20
|
|
|
276
|
-
|
|
277
|
-
echo "
|
|
278
|
-
|
|
279
|
-
|
|
21
|
+
if [[ ! -f "$EPIC_FILE" ]]; then
|
|
22
|
+
echo "❌ Error: Epic file not found: $EPIC_FILE"
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
280
25
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
26
|
+
# Get repository info
|
|
27
|
+
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null || echo "unknown/repo")
|
|
28
|
+
EPIC_URL="https://github.com/$REPO/issues/$EPIC_NUMBER"
|
|
284
29
|
|
|
285
|
-
|
|
286
|
-
local parallel_count
|
|
287
|
-
parallel_count=$(grep -l '^parallel: true' "$epic_dir"/[0-9]*.md 2>/dev/null | wc -l || echo 0)
|
|
288
|
-
local sequential_count=$((task_count - parallel_count))
|
|
30
|
+
echo "📄 Updating epic file: $EPIC_FILE"
|
|
289
31
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
echo " Total tasks: $task_count"
|
|
293
|
-
echo " Parallel tasks: $parallel_count"
|
|
294
|
-
echo " Sequential tasks: $sequential_count"
|
|
32
|
+
# Create backup
|
|
33
|
+
cp "$EPIC_FILE" "$EPIC_FILE.backup"
|
|
295
34
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
echo "Files Updated:"
|
|
299
|
-
echo " ✅ $epic_file"
|
|
300
|
-
echo " ✅ $epic_dir/github-mapping.md"
|
|
35
|
+
# Update frontmatter
|
|
36
|
+
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
301
37
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
38
|
+
awk -v url="$EPIC_URL" -v ts="$timestamp" '
|
|
39
|
+
BEGIN { in_front=0; front_done=0 }
|
|
40
|
+
/^---$/ {
|
|
41
|
+
if (!front_done) {
|
|
42
|
+
in_front = !in_front
|
|
43
|
+
if (!in_front) front_done=1
|
|
44
|
+
}
|
|
45
|
+
print
|
|
46
|
+
next
|
|
306
47
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
log_function_entry "validate_epic_structure_post_update"
|
|
311
|
-
|
|
312
|
-
# Check that Tasks Created section exists and is properly formatted
|
|
313
|
-
if ! grep -q "^## Tasks Created" "$epic_file"; then
|
|
314
|
-
log_error "Tasks Created section not found after update"
|
|
315
|
-
return 1
|
|
316
|
-
fi
|
|
317
|
-
|
|
318
|
-
# Check that frontmatter has GitHub URL
|
|
319
|
-
local github_url
|
|
320
|
-
github_url=$(get_frontmatter_field "$epic_file" "github" 2>/dev/null || echo "")
|
|
321
|
-
|
|
322
|
-
if [[ -z "$github_url" ]]; then
|
|
323
|
-
log_error "GitHub URL not found in epic frontmatter"
|
|
324
|
-
return 1
|
|
325
|
-
fi
|
|
326
|
-
|
|
327
|
-
# Validate GitHub URL format
|
|
328
|
-
if [[ ! "$github_url" =~ ^https://github\.com/.*/issues/[0-9]+$ ]]; then
|
|
329
|
-
log_error "Invalid GitHub URL format: $github_url"
|
|
330
|
-
return 1
|
|
331
|
-
fi
|
|
332
|
-
|
|
333
|
-
log_debug "Epic structure validation passed"
|
|
334
|
-
log_function_exit "validate_epic_structure_post_update"
|
|
335
|
-
return 0
|
|
48
|
+
in_front && /^github:/ {
|
|
49
|
+
print "github: " url
|
|
50
|
+
next
|
|
336
51
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
local exit_code=$?
|
|
341
|
-
log_error "Script failed with exit code: $exit_code"
|
|
342
|
-
log_error "Epic file update failed for: $EPIC_NAME"
|
|
343
|
-
exit "$exit_code"
|
|
52
|
+
in_front && /^updated:/ {
|
|
53
|
+
print "updated: " ts
|
|
54
|
+
next
|
|
344
55
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
echo " 2. Update Tasks Created section with real issue numbers"
|
|
362
|
-
echo " 3. Create github-mapping.md file for reference"
|
|
363
|
-
echo ""
|
|
364
|
-
echo "Examples:"
|
|
365
|
-
echo " $0 authentication 123"
|
|
366
|
-
echo " $0 user-dashboard 456"
|
|
367
|
-
echo ""
|
|
368
|
-
exit 1
|
|
56
|
+
{ print }
|
|
57
|
+
' "$EPIC_FILE.backup" > "$EPIC_FILE.tmp"
|
|
58
|
+
|
|
59
|
+
# If mapping file exists, update task references in the body
|
|
60
|
+
if [[ -f "$MAPPING_FILE" ]]; then
|
|
61
|
+
echo " Updating task references with real issue numbers..."
|
|
62
|
+
|
|
63
|
+
# Read mapping and update task references
|
|
64
|
+
while read -r old_name new_number; do
|
|
65
|
+
# Update checkbox items like "- [ ] 001" to "- [ ] #2"
|
|
66
|
+
sed -i "s/- \[ \] $old_name\b/- [ ] #$new_number/g" "$EPIC_FILE.tmp"
|
|
67
|
+
sed -i "s/- \[x\] $old_name\b/- [x] #$new_number/g" "$EPIC_FILE.tmp"
|
|
68
|
+
|
|
69
|
+
# Update task links
|
|
70
|
+
sed -i "s/Task $old_name\b/Task #$new_number/g" "$EPIC_FILE.tmp"
|
|
71
|
+
done < "$MAPPING_FILE"
|
|
369
72
|
fi
|
|
370
73
|
|
|
371
|
-
#
|
|
372
|
-
|
|
74
|
+
# Finalize
|
|
75
|
+
mv "$EPIC_FILE.tmp" "$EPIC_FILE"
|
|
76
|
+
rm "$EPIC_FILE.backup"
|
|
77
|
+
|
|
78
|
+
echo "✅ Epic file updated"
|
|
79
|
+
echo " GitHub: $EPIC_URL"
|