specweave 0.26.2 → 0.26.4
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.md +172 -1413
- package/dist/src/cli/commands/plan/plan-orchestrator.js +2 -2
- package/dist/src/cli/commands/plan/plan-orchestrator.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js +147 -55
- package/dist/src/cli/helpers/issue-tracker/github-multi-repo.js.map +1 -1
- package/dist/src/core/increment/completion-validator.d.ts +4 -0
- package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
- package/dist/src/core/increment/completion-validator.js +36 -0
- package/dist/src/core/increment/completion-validator.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +47 -13
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/us-sync-throttle.d.ts +113 -0
- package/dist/src/core/us-sync-throttle.d.ts.map +1 -0
- package/dist/src/core/us-sync-throttle.js +195 -0
- package/dist/src/core/us-sync-throttle.js.map +1 -0
- package/dist/src/utils/external-tool-drift-detector.d.ts +76 -0
- package/dist/src/utils/external-tool-drift-detector.d.ts.map +1 -0
- package/dist/src/utils/external-tool-drift-detector.js +235 -0
- package/dist/src/utils/external-tool-drift-detector.js.map +1 -0
- package/package.json +4 -4
- package/plugins/specweave/hooks/post-task-completion.sh +6 -6
- package/plugins/specweave/hooks/pre-increment-start.sh +6 -1
- package/plugins/specweave/lib/hooks/us-completion-orchestrator.js +62 -89
- package/plugins/specweave/lib/hooks/us-completion-orchestrator.ts +215 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-release/hooks/post-task-completion.sh +5 -1
- package/plugins/specweave/agents/pm/AGENT.md.bak +0 -1893
- package/plugins/specweave/hooks/docs-changed.sh.backup +0 -79
- package/plugins/specweave/hooks/human-input-required.sh.backup +0 -75
- package/plugins/specweave/hooks/lib/migrate-increment-work.sh.bak +0 -245
- package/plugins/specweave/hooks/lib/sync-spec-content.sh.bak +0 -149
- package/plugins/specweave/hooks/lib/validate-spec-status.sh.bak +0 -163
- package/plugins/specweave/hooks/post-first-increment.sh.backup +0 -61
- package/plugins/specweave/hooks/post-first-increment.sh.bak +0 -61
- package/plugins/specweave/hooks/post-increment-change.sh.backup +0 -98
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +0 -231
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +0 -1048
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +0 -147
- package/plugins/specweave/hooks/post-spec-update.sh.backup +0 -158
- package/plugins/specweave/hooks/post-spec-update.sh.bak +0 -158
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +0 -179
- package/plugins/specweave/hooks/post-user-story-complete.sh.bak +0 -179
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +0 -83
- package/plugins/specweave/hooks/pre-command-deduplication.sh.bak +0 -83
- package/plugins/specweave/hooks/pre-implementation.sh.backup +0 -67
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +0 -194
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +0 -133
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +0 -386
- package/plugins/specweave/hooks/user-prompt-submit.sh.bak +0 -386
- package/plugins/specweave/lib/hooks/auto-transition.js.bak +0 -50
- package/plugins/specweave/lib/hooks/auto-transition.ts.bak +0 -84
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.d.ts.bak +0 -89
- package/plugins/specweave/lib/hooks/git-diff-analyzer.js.bak +0 -142
- package/plugins/specweave/lib/hooks/git-diff-analyzer.ts.bak +0 -269
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/invoke-translator-skill.d.ts.bak +0 -60
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js.bak +0 -155
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts.bak +0 -264
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/prepare-reflection-context.d.ts.bak +0 -42
- package/plugins/specweave/lib/hooks/prepare-reflection-context.js.bak +0 -110
- package/plugins/specweave/lib/hooks/prepare-reflection-context.ts.bak +0 -178
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-config-loader.d.ts.bak +0 -45
- package/plugins/specweave/lib/hooks/reflection-config-loader.js.bak +0 -92
- package/plugins/specweave/lib/hooks/reflection-config-loader.ts.bak +0 -156
- package/plugins/specweave/lib/hooks/reflection-parser.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-parser.d.ts.bak +0 -33
- package/plugins/specweave/lib/hooks/reflection-parser.js.bak +0 -301
- package/plugins/specweave/lib/hooks/reflection-parser.ts.bak +0 -484
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.d.ts.bak +0 -56
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.js.bak +0 -182
- package/plugins/specweave/lib/hooks/reflection-prompt-builder.ts.bak +0 -306
- package/plugins/specweave/lib/hooks/reflection-storage.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/reflection-storage.d.ts.bak +0 -64
- package/plugins/specweave/lib/hooks/reflection-storage.js.bak +0 -231
- package/plugins/specweave/lib/hooks/reflection-storage.ts.bak +0 -369
- package/plugins/specweave/lib/hooks/run-self-reflection.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/run-self-reflection.d.ts.bak +0 -43
- package/plugins/specweave/lib/hooks/run-self-reflection.js.bak +0 -132
- package/plugins/specweave/lib/hooks/run-self-reflection.ts.bak +0 -258
- package/plugins/specweave/lib/hooks/sync-cache.js.bak +0 -294
- package/plugins/specweave/lib/hooks/sync-living-docs.d.js.bak +0 -1
- package/plugins/specweave/lib/hooks/sync-living-docs.d.ts.bak +0 -27
- package/plugins/specweave/lib/hooks/sync-living-docs.js.bak +0 -339
- package/plugins/specweave/lib/hooks/sync-us-tasks.js.bak +0 -476
- package/plugins/specweave/lib/hooks/translate-file.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-file.d.ts.bak +0 -59
- package/plugins/specweave/lib/hooks/translate-file.js.bak +0 -289
- package/plugins/specweave/lib/hooks/translate-file.ts.bak +0 -428
- package/plugins/specweave/lib/hooks/translate-living-docs.d.js.bak +0 -0
- package/plugins/specweave/lib/hooks/translate-living-docs.d.ts.bak +0 -13
- package/plugins/specweave/lib/hooks/translate-living-docs.js.bak +0 -119
- package/plugins/specweave/lib/hooks/translate-living-docs.ts.bak +0 -224
- package/plugins/specweave/lib/hooks/update-ac-status.js.bak +0 -51
- package/plugins/specweave/lib/hooks/update-ac-status.ts.bak +0 -103
- package/plugins/specweave/lib/hooks/update-tasks-md.d.js.bak +0 -1
- package/plugins/specweave/lib/hooks/update-tasks-md.d.ts.bak +0 -29
- package/plugins/specweave/lib/hooks/update-tasks-md.js.bak +0 -296
- package/plugins/specweave/lib/hooks/update-tasks-md.ts.bak +0 -489
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +0 -353
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +0 -172
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +0 -904
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +0 -258
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +0 -172
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -738
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +0 -110
|
@@ -1,489 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* SpecWeave Tasks.md Auto-Updater
|
|
5
|
-
*
|
|
6
|
-
* Automatically updates tasks.md completion status after TodoWrite completes tasks.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* node dist/hooks/lib/update-tasks-md.js <incrementId>
|
|
10
|
-
*
|
|
11
|
-
* Example:
|
|
12
|
-
* node dist/hooks/lib/update-tasks-md.js 0006-llm-native-i18n
|
|
13
|
-
*
|
|
14
|
-
* What it does:
|
|
15
|
-
* 1. Reads tasks.md for the given increment
|
|
16
|
-
* 2. Finds recently completed tasks from TodoWrite
|
|
17
|
-
* 3. Updates "[ ]" to "[x]" for completed tasks
|
|
18
|
-
* 4. Updates "Status: ⏳ Pending" to "Status: [x] Completed"
|
|
19
|
-
* 5. Recalculates progress percentage
|
|
20
|
-
* 6. Writes back to tasks.md
|
|
21
|
-
*
|
|
22
|
-
* @author SpecWeave Team
|
|
23
|
-
* @version 1.0.0
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
import fs from 'fs-extra';
|
|
27
|
-
import path from 'path';
|
|
28
|
-
|
|
29
|
-
interface TaskMatch {
|
|
30
|
-
taskId: string;
|
|
31
|
-
lineNumber: number;
|
|
32
|
-
currentStatus: 'pending' | 'in_progress' | 'completed';
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
interface TaskConsistencyFix {
|
|
36
|
-
taskId: string;
|
|
37
|
-
lineNumber: number;
|
|
38
|
-
action: 'add-complete-marker' | 'remove-complete-marker';
|
|
39
|
-
currentLine: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Main function - update tasks.md for given increment
|
|
44
|
-
*/
|
|
45
|
-
async function updateTasksMd(incrementId: string): Promise<void> {
|
|
46
|
-
try {
|
|
47
|
-
console.log(`\n🔄 Updating tasks.md for increment: ${incrementId}`);
|
|
48
|
-
|
|
49
|
-
// 1. Validate increment exists
|
|
50
|
-
const incrementDir = path.join(process.cwd(), '.specweave', 'increments', incrementId);
|
|
51
|
-
if (!fs.existsSync(incrementDir)) {
|
|
52
|
-
console.error(`❌ Increment directory not found: ${incrementDir}`);
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const tasksPath = path.join(incrementDir, 'tasks.md');
|
|
57
|
-
if (!fs.existsSync(tasksPath)) {
|
|
58
|
-
console.error(`❌ tasks.md not found: ${tasksPath}`);
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// 2. Read tasks.md
|
|
63
|
-
const originalContent = await fs.readFile(tasksPath, 'utf-8');
|
|
64
|
-
const lines = originalContent.split('\n');
|
|
65
|
-
|
|
66
|
-
console.log(`📖 Read tasks.md (${lines.length} lines)`);
|
|
67
|
-
|
|
68
|
-
// 3. Parse task completion status
|
|
69
|
-
const tasks = parseTaskStatus(lines);
|
|
70
|
-
console.log(`📋 Found ${tasks.length} tasks`);
|
|
71
|
-
|
|
72
|
-
// 4. Get recently completed tasks and consistency fixes
|
|
73
|
-
const { completedTasks, fixes } = detectCompletedTasks(lines);
|
|
74
|
-
|
|
75
|
-
// 4a. Apply consistency fixes FIRST (if any)
|
|
76
|
-
let updatedContent = originalContent;
|
|
77
|
-
let autoFixedCount = 0;
|
|
78
|
-
|
|
79
|
-
if (fixes.length > 0) {
|
|
80
|
-
console.log(`🔧 Auto-fixing ${fixes.length} task consistency issue(s)...`);
|
|
81
|
-
updatedContent = applyConsistencyFixes(originalContent, fixes);
|
|
82
|
-
autoFixedCount = fixes.length;
|
|
83
|
-
console.log('✅ Task consistency auto-fixed');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (completedTasks.length === 0 && fixes.length === 0) {
|
|
87
|
-
console.log('✅ No new task completions or consistency fixes needed');
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (completedTasks.length > 0) {
|
|
92
|
-
console.log(`🎯 Detected ${completedTasks.length} completed task(s):`, completedTasks);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// 5. Update task status in content
|
|
96
|
-
|
|
97
|
-
for (const taskId of completedTasks) {
|
|
98
|
-
updatedContent = markTaskComplete(updatedContent, taskId);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// 6. Recalculate progress
|
|
102
|
-
const updatedLines = updatedContent.split('\n');
|
|
103
|
-
const totalTasks = countTotalTasks(updatedLines);
|
|
104
|
-
const completedCount = countCompletedTasks(updatedLines);
|
|
105
|
-
const progress = Math.round((completedCount / totalTasks) * 100);
|
|
106
|
-
|
|
107
|
-
console.log(`📊 Progress: ${completedCount}/${totalTasks} (${progress}%)`);
|
|
108
|
-
|
|
109
|
-
// 7. Update header with new progress
|
|
110
|
-
updatedContent = updateProgressHeader(updatedContent, completedCount, totalTasks, progress);
|
|
111
|
-
|
|
112
|
-
// 8. Write back to tasks.md
|
|
113
|
-
await fs.writeFile(tasksPath, updatedContent, 'utf-8');
|
|
114
|
-
|
|
115
|
-
console.log(`✅ Updated ${tasksPath}`);
|
|
116
|
-
if (autoFixedCount > 0) {
|
|
117
|
-
console.log(`🔧 Auto-fixed ${autoFixedCount} consistency issue(s)`);
|
|
118
|
-
}
|
|
119
|
-
console.log(` Completed: ${completedCount}/${totalTasks}`);
|
|
120
|
-
console.log(` Progress: ${progress}%\n`);
|
|
121
|
-
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.error('❌ Error updating tasks.md:', error);
|
|
124
|
-
process.exit(1);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Parse task status from lines
|
|
130
|
-
*/
|
|
131
|
-
function parseTaskStatus(lines: string[]): TaskMatch[] {
|
|
132
|
-
const tasks: TaskMatch[] = [];
|
|
133
|
-
const taskPattern = /^###\s+(T-?\d+[-A-Z]*):?\s+(.+)/; // Matches "### T-001: Task Name" or "### T-001-DISCIPLINE:"
|
|
134
|
-
|
|
135
|
-
lines.forEach((line, index) => {
|
|
136
|
-
const match = line.match(taskPattern);
|
|
137
|
-
if (match) {
|
|
138
|
-
const taskId = match[1];
|
|
139
|
-
|
|
140
|
-
// Look ahead for status line
|
|
141
|
-
let status: 'pending' | 'in_progress' | 'completed' = 'pending';
|
|
142
|
-
|
|
143
|
-
for (let i = index + 1; i < Math.min(index + 5, lines.length); i++) {
|
|
144
|
-
const nextLine = lines[i];
|
|
145
|
-
if (nextLine.includes('**Status**:')) {
|
|
146
|
-
if (nextLine.includes('[x] Completed')) {
|
|
147
|
-
status = 'completed';
|
|
148
|
-
} else if (nextLine.includes('⏳ Pending') || nextLine.includes('[ ] Pending')) {
|
|
149
|
-
status = 'pending';
|
|
150
|
-
} else if (nextLine.includes('🔄 In Progress') || nextLine.includes('in_progress')) {
|
|
151
|
-
status = 'in_progress';
|
|
152
|
-
}
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
tasks.push({
|
|
158
|
-
taskId,
|
|
159
|
-
lineNumber: index,
|
|
160
|
-
currentStatus: status,
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
return tasks;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Detect which tasks are completed (STRICT VALIDATION)
|
|
170
|
-
*
|
|
171
|
-
* Detection strategies (ALL must be true):
|
|
172
|
-
* 1. Task header has "✅ COMPLETE" marker AND
|
|
173
|
-
* all implementation checkboxes are marked [x]
|
|
174
|
-
* 2. OR: Task header has "Status: [x] Completed" (legacy format)
|
|
175
|
-
*
|
|
176
|
-
* This prevents inconsistencies where header says COMPLETE but checkboxes
|
|
177
|
-
* are unchecked. Both must match for a task to be considered complete.
|
|
178
|
-
*
|
|
179
|
-
* @see .specweave/increments/0037/reports/ULTRATHINK-COMPLETE-MARKER-VS-CHECKBOXES.md
|
|
180
|
-
*/
|
|
181
|
-
function detectCompletedTasks(lines: string[]): { completedTasks: string[]; fixes: TaskConsistencyFix[] } {
|
|
182
|
-
const completedTasks: string[] = [];
|
|
183
|
-
const fixes: TaskConsistencyFix[] = [];
|
|
184
|
-
const warnings: string[] = [];
|
|
185
|
-
const taskPattern = /^###\s+(T-\d+[-A-Z]*):?\s+(.+)/;
|
|
186
|
-
|
|
187
|
-
for (let i = 0; i < lines.length; i++) {
|
|
188
|
-
const line = lines[i];
|
|
189
|
-
const taskMatch = line.match(taskPattern);
|
|
190
|
-
|
|
191
|
-
if (!taskMatch) continue;
|
|
192
|
-
|
|
193
|
-
const taskId = taskMatch[1];
|
|
194
|
-
const taskTitle = taskMatch[2];
|
|
195
|
-
const hasCompleteMarker = taskTitle.includes('✅ COMPLETE');
|
|
196
|
-
|
|
197
|
-
// Get implementation section
|
|
198
|
-
const taskEndIndex = findNextTaskStart(lines, i + 1);
|
|
199
|
-
const implementationSection = findImplementationSection(lines, i, taskEndIndex);
|
|
200
|
-
|
|
201
|
-
let allCheckboxesComplete = false;
|
|
202
|
-
if (implementationSection) {
|
|
203
|
-
allCheckboxesComplete = checkAllCheckboxesComplete(implementationSection);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// STRICT VALIDATION: Require BOTH header AND checkboxes to match
|
|
207
|
-
if (hasCompleteMarker && implementationSection) {
|
|
208
|
-
if (allCheckboxesComplete) {
|
|
209
|
-
// ✅ CONSISTENT: Header says COMPLETE and all checkboxes checked
|
|
210
|
-
if (!completedTasks.includes(taskId)) {
|
|
211
|
-
completedTasks.push(taskId);
|
|
212
|
-
}
|
|
213
|
-
} else {
|
|
214
|
-
// ⚠️ INCONSISTENT: Header says COMPLETE but checkboxes incomplete - AUTO-FIX
|
|
215
|
-
fixes.push({
|
|
216
|
-
taskId,
|
|
217
|
-
lineNumber: i,
|
|
218
|
-
action: 'remove-complete-marker',
|
|
219
|
-
currentLine: line
|
|
220
|
-
});
|
|
221
|
-
warnings.push(`${taskId}: Header has ✅ COMPLETE but not all checkboxes checked`);
|
|
222
|
-
}
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// If no implementation section, remove COMPLETE marker (can't verify)
|
|
227
|
-
if (hasCompleteMarker && !implementationSection) {
|
|
228
|
-
fixes.push({
|
|
229
|
-
taskId,
|
|
230
|
-
lineNumber: i,
|
|
231
|
-
action: 'remove-complete-marker',
|
|
232
|
-
currentLine: line
|
|
233
|
-
});
|
|
234
|
-
warnings.push(`${taskId}: Header has ✅ COMPLETE but no implementation section to verify`);
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Warn if checkboxes all complete but header missing marker - AUTO-FIX
|
|
239
|
-
if (!hasCompleteMarker && implementationSection && allCheckboxesComplete) {
|
|
240
|
-
fixes.push({
|
|
241
|
-
taskId,
|
|
242
|
-
lineNumber: i,
|
|
243
|
-
action: 'add-complete-marker',
|
|
244
|
-
currentLine: line
|
|
245
|
-
});
|
|
246
|
-
warnings.push(`${taskId}: All checkboxes checked but header missing ✅ COMPLETE`);
|
|
247
|
-
// Still count as complete (checkboxes are source of truth for work done)
|
|
248
|
-
if (!completedTasks.includes(taskId)) {
|
|
249
|
-
completedTasks.push(taskId);
|
|
250
|
-
}
|
|
251
|
-
continue;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Strategy 2: Check for "Status: [x] Completed" (legacy format)
|
|
255
|
-
for (let j = i + 1; j < Math.min(i + 10, taskEndIndex); j++) {
|
|
256
|
-
const statusLine = lines[j];
|
|
257
|
-
if (statusLine.includes('**Status**:') && statusLine.includes('[x] Completed')) {
|
|
258
|
-
if (!completedTasks.includes(taskId)) {
|
|
259
|
-
completedTasks.push(taskId);
|
|
260
|
-
}
|
|
261
|
-
break;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Report warnings if any
|
|
267
|
-
if (warnings.length > 0) {
|
|
268
|
-
console.warn('\n⚠️ Task Consistency Warnings:');
|
|
269
|
-
warnings.forEach(w => console.warn(` ${w}`));
|
|
270
|
-
console.warn('');
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return { completedTasks, fixes };
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Apply task consistency fixes to content
|
|
278
|
-
*/
|
|
279
|
-
function applyConsistencyFixes(content: string, fixes: TaskConsistencyFix[]): string {
|
|
280
|
-
const lines = content.split('\n');
|
|
281
|
-
|
|
282
|
-
// Apply fixes (process in reverse order to preserve line numbers)
|
|
283
|
-
for (const fix of fixes.reverse()) {
|
|
284
|
-
const line = lines[fix.lineNumber];
|
|
285
|
-
|
|
286
|
-
if (fix.action === 'remove-complete-marker') {
|
|
287
|
-
// Remove ✅ COMPLETE from header
|
|
288
|
-
const fixed = line.replace(/\s*✅\s*COMPLETE\s*/g, '');
|
|
289
|
-
lines[fix.lineNumber] = fixed;
|
|
290
|
-
} else if (fix.action === 'add-complete-marker') {
|
|
291
|
-
// Add ✅ COMPLETE to header (before any trailing spaces)
|
|
292
|
-
const fixed = line.trim() + ' ✅ COMPLETE';
|
|
293
|
-
lines[fix.lineNumber] = fixed;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return lines.join('\n');
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Find the next task header start index
|
|
302
|
-
*/
|
|
303
|
-
function findNextTaskStart(lines: string[], startIndex: number): number {
|
|
304
|
-
const taskPattern = /^###\s+T-\d+/;
|
|
305
|
-
|
|
306
|
-
for (let i = startIndex; i < lines.length; i++) {
|
|
307
|
-
if (taskPattern.test(lines[i])) {
|
|
308
|
-
return i;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return lines.length;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Find the Implementation section within a task
|
|
317
|
-
*/
|
|
318
|
-
function findImplementationSection(lines: string[], taskStartIndex: number, taskEndIndex: number): string[] | null {
|
|
319
|
-
let inImplementation = false;
|
|
320
|
-
const implementationLines: string[] = [];
|
|
321
|
-
|
|
322
|
-
for (let i = taskStartIndex; i < taskEndIndex; i++) {
|
|
323
|
-
const line = lines[i];
|
|
324
|
-
|
|
325
|
-
if (line.includes('**Implementation**:')) {
|
|
326
|
-
inImplementation = true;
|
|
327
|
-
continue;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
if (inImplementation) {
|
|
331
|
-
// Stop at next section header (**, ---, or ###)
|
|
332
|
-
if (line.trim().startsWith('**') && !line.startsWith('- [')) {
|
|
333
|
-
break;
|
|
334
|
-
}
|
|
335
|
-
if (line.trim().startsWith('---')) {
|
|
336
|
-
break;
|
|
337
|
-
}
|
|
338
|
-
if (line.trim().startsWith('###')) {
|
|
339
|
-
break;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
implementationLines.push(line);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
return implementationLines.length > 0 ? implementationLines : null;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Check if all checkboxes in implementation section are complete
|
|
351
|
-
*/
|
|
352
|
-
function checkAllCheckboxesComplete(implementationLines: string[]): boolean {
|
|
353
|
-
const checkboxes = implementationLines.filter(line => line.includes('- ['));
|
|
354
|
-
|
|
355
|
-
if (checkboxes.length === 0) {
|
|
356
|
-
return false; // No checkboxes = can't determine completion
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// All checkboxes must be [x], none can be [ ]
|
|
360
|
-
const allComplete = checkboxes.every(line => line.includes('- [x]'));
|
|
361
|
-
const noneIncomplete = checkboxes.every(line => !line.includes('- [ ]'));
|
|
362
|
-
|
|
363
|
-
return allComplete && noneIncomplete;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Mark a specific task as complete
|
|
368
|
-
*/
|
|
369
|
-
function markTaskComplete(content: string, taskId: string): string {
|
|
370
|
-
let updated = content;
|
|
371
|
-
|
|
372
|
-
// Pattern: "**Status**: [ ] Pending" or "**Status**: ⏳ Pending"
|
|
373
|
-
const statusPattern = new RegExp(
|
|
374
|
-
`(###\\s+${taskId.replace(/[-]/g, '\\-')}[^\\n]*[\\s\\S]*?\\*\\*Status\\*\\*:)\\s*\\[?\\s*\\]?\\s*⏳?\\s*Pending`,
|
|
375
|
-
'i'
|
|
376
|
-
);
|
|
377
|
-
|
|
378
|
-
updated = updated.replace(statusPattern, '$1 [x] Completed');
|
|
379
|
-
|
|
380
|
-
return updated;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Count total tasks
|
|
385
|
-
*/
|
|
386
|
-
function countTotalTasks(lines: string[]): number {
|
|
387
|
-
let count = 0;
|
|
388
|
-
const taskPattern = /^###\s+(T-?\d+[-A-Z]*):?\s+/;
|
|
389
|
-
|
|
390
|
-
for (const line of lines) {
|
|
391
|
-
if (taskPattern.test(line)) {
|
|
392
|
-
count++;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
return count;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Count completed tasks
|
|
401
|
-
*
|
|
402
|
-
* Recognizes multiple completion indicators:
|
|
403
|
-
* 1. "✅ COMPLETE" marker in task header
|
|
404
|
-
* 2. "**Status**: [x] Completed" line
|
|
405
|
-
* 3. All implementation checkboxes marked [x]
|
|
406
|
-
*/
|
|
407
|
-
function countCompletedTasks(lines: string[]): number {
|
|
408
|
-
let count = 0;
|
|
409
|
-
const taskPattern = /^###\s+(T-?\d+[-A-Z]*):?\s+(.+)/;
|
|
410
|
-
|
|
411
|
-
for (let i = 0; i < lines.length; i++) {
|
|
412
|
-
const line = lines[i];
|
|
413
|
-
const taskMatch = line.match(taskPattern);
|
|
414
|
-
|
|
415
|
-
if (taskMatch) {
|
|
416
|
-
const taskTitle = taskMatch[2];
|
|
417
|
-
|
|
418
|
-
// Strategy 1: Check for ✅ COMPLETE marker in header
|
|
419
|
-
if (taskTitle.includes('✅ COMPLETE')) {
|
|
420
|
-
count++;
|
|
421
|
-
continue;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Strategy 2: Check for Status: [x] Completed
|
|
425
|
-
let found = false;
|
|
426
|
-
for (let j = i + 1; j < Math.min(i + 10, lines.length); j++) {
|
|
427
|
-
const nextLine = lines[j];
|
|
428
|
-
if (nextLine.includes('**Status**:') && nextLine.includes('[x] Completed')) {
|
|
429
|
-
count++;
|
|
430
|
-
found = true;
|
|
431
|
-
break;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
if (found) continue;
|
|
436
|
-
|
|
437
|
-
// Strategy 3: Check if all implementation checkboxes are [x]
|
|
438
|
-
const taskEndIndex = findNextTaskStart(lines, i + 1);
|
|
439
|
-
const implementationSection = findImplementationSection(lines, i, taskEndIndex);
|
|
440
|
-
|
|
441
|
-
if (implementationSection) {
|
|
442
|
-
const allCheckboxesComplete = checkAllCheckboxesComplete(implementationSection);
|
|
443
|
-
if (allCheckboxesComplete) {
|
|
444
|
-
count++;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
return count;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Update progress header
|
|
455
|
-
*/
|
|
456
|
-
function updateProgressHeader(content: string, completed: number, total: number, progress: number): string {
|
|
457
|
-
let updated = content;
|
|
458
|
-
|
|
459
|
-
// Update "**Completed**: X"
|
|
460
|
-
updated = updated.replace(/\*\*Completed\*\*:\s*\d+/, `**Completed**: ${completed}`);
|
|
461
|
-
|
|
462
|
-
// Update "**Progress**: X%"
|
|
463
|
-
updated = updated.replace(/\*\*Progress\*\*:\s*\d+%/, `**Progress**: ${progress}%`);
|
|
464
|
-
|
|
465
|
-
// Update "**Total Tasks**: X"
|
|
466
|
-
updated = updated.replace(/\*\*Total Tasks\*\*:\s*\d+/, `**Total Tasks**: ${total}`);
|
|
467
|
-
|
|
468
|
-
return updated;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// CLI entry point
|
|
472
|
-
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
473
|
-
|
|
474
|
-
if (isMainModule) {
|
|
475
|
-
const incrementId = process.argv[2];
|
|
476
|
-
|
|
477
|
-
if (!incrementId) {
|
|
478
|
-
console.error('❌ Usage: update-tasks-md <incrementId>');
|
|
479
|
-
console.error(' Example: update-tasks-md 0006-llm-native-i18n');
|
|
480
|
-
process.exit(1);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
updateTasksMd(incrementId).catch((error) => {
|
|
484
|
-
console.error('❌ Fatal error:', error);
|
|
485
|
-
process.exit(1);
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
export { updateTasksMd };
|