@e0ipso/ai-task-manager 1.9.1 → 1.10.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/package.json +1 -1
- package/templates/ai-task-manager/config/scripts/get-next-plan-id.cjs +350 -43
- package/templates/assistant/commands/tasks/create-plan.md +2 -0
- package/templates/assistant/commands/tasks/fix-broken-tests.md +39 -0
- package/templates/assistant/commands/tasks/generate-tasks.md +4 -0
package/package.json
CHANGED
|
@@ -3,64 +3,233 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
|
+
// Enable debug logging via environment variable
|
|
7
|
+
const DEBUG = process.env.DEBUG === 'true';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Debug logging utility
|
|
11
|
+
* @param {string} message - Debug message
|
|
12
|
+
* @param {...any} args - Additional arguments to log
|
|
13
|
+
*/
|
|
14
|
+
function debugLog(message, ...args) {
|
|
15
|
+
if (DEBUG) {
|
|
16
|
+
console.error(`[DEBUG] ${message}`, ...args);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Error logging utility
|
|
22
|
+
* @param {string} message - Error message
|
|
23
|
+
* @param {...any} args - Additional arguments to log
|
|
24
|
+
*/
|
|
25
|
+
function errorLog(message, ...args) {
|
|
26
|
+
console.error(`[ERROR] ${message}`, ...args);
|
|
27
|
+
}
|
|
28
|
+
|
|
6
29
|
/**
|
|
7
|
-
* Find the task manager root directory by traversing up from
|
|
30
|
+
* Find the task manager root directory by traversing up from current working directory
|
|
8
31
|
* @returns {string|null} Path to task manager root or null if not found
|
|
9
32
|
*/
|
|
10
33
|
function findTaskManagerRoot() {
|
|
34
|
+
// Start from the actual current working directory, not process.cwd()
|
|
35
|
+
// This ensures we start from the correct context where the script is being executed
|
|
11
36
|
let currentPath = process.cwd();
|
|
12
|
-
const
|
|
37
|
+
const filesystemRoot = path.parse(currentPath).root;
|
|
38
|
+
|
|
39
|
+
debugLog(`Starting search for task manager root from: ${currentPath}`);
|
|
40
|
+
debugLog(`Filesystem root: ${filesystemRoot}`);
|
|
41
|
+
|
|
42
|
+
// Traverse upward through parent directories until we reach the filesystem root
|
|
43
|
+
while (currentPath !== filesystemRoot) {
|
|
44
|
+
const taskManagerPlansPath = path.join(currentPath, '.ai', 'task-manager', 'plans');
|
|
45
|
+
debugLog(`Checking for task manager at: ${taskManagerPlansPath}`);
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
// Check if this is a valid task manager directory
|
|
49
|
+
if (fs.existsSync(taskManagerPlansPath)) {
|
|
50
|
+
// Verify it's a directory, not a file
|
|
51
|
+
const stats = fs.lstatSync(taskManagerPlansPath);
|
|
52
|
+
if (stats.isDirectory()) {
|
|
53
|
+
const taskManagerRoot = path.join(currentPath, '.ai', 'task-manager');
|
|
54
|
+
debugLog(`Found valid task manager root at: ${taskManagerRoot}`);
|
|
55
|
+
return taskManagerRoot;
|
|
56
|
+
} else {
|
|
57
|
+
debugLog(`Path exists but is not a directory: ${taskManagerPlansPath}`);
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
debugLog(`Task manager path does not exist: ${taskManagerPlansPath}`);
|
|
61
|
+
}
|
|
62
|
+
} catch (err) {
|
|
63
|
+
// Handle permission errors or other filesystem issues gracefully
|
|
64
|
+
// Continue searching in parent directories
|
|
65
|
+
if (err.code === 'EPERM' || err.code === 'EACCES') {
|
|
66
|
+
const warningMsg = `Warning: Permission denied accessing ${taskManagerPlansPath}`;
|
|
67
|
+
console.warn(warningMsg);
|
|
68
|
+
debugLog(`Permission error: ${err.message}`);
|
|
69
|
+
} else {
|
|
70
|
+
debugLog(`Filesystem error checking ${taskManagerPlansPath}: ${err.message}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Move up to parent directory
|
|
75
|
+
const parentPath = path.dirname(currentPath);
|
|
13
76
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
77
|
+
// Safety check: if path.dirname returns the same path, we've reached the root
|
|
78
|
+
if (parentPath === currentPath) {
|
|
79
|
+
debugLog(`Reached filesystem root, stopping traversal`);
|
|
80
|
+
break;
|
|
18
81
|
}
|
|
19
|
-
|
|
82
|
+
|
|
83
|
+
currentPath = parentPath;
|
|
84
|
+
debugLog(`Moving up to parent directory: ${currentPath}`);
|
|
20
85
|
}
|
|
21
86
|
|
|
22
|
-
// Check root
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
87
|
+
// Check the filesystem root as the final attempt
|
|
88
|
+
try {
|
|
89
|
+
const rootTaskManagerPlans = path.join(filesystemRoot, '.ai', 'task-manager', 'plans');
|
|
90
|
+
debugLog(`Final check at filesystem root: ${rootTaskManagerPlans}`);
|
|
91
|
+
|
|
92
|
+
if (fs.existsSync(rootTaskManagerPlans)) {
|
|
93
|
+
const stats = fs.lstatSync(rootTaskManagerPlans);
|
|
94
|
+
if (stats.isDirectory()) {
|
|
95
|
+
const taskManagerRoot = path.join(filesystemRoot, '.ai', 'task-manager');
|
|
96
|
+
debugLog(`Found task manager root at filesystem root: ${taskManagerRoot}`);
|
|
97
|
+
return taskManagerRoot;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} catch (err) {
|
|
101
|
+
debugLog(`Error checking filesystem root: ${err.message}`);
|
|
26
102
|
}
|
|
27
103
|
|
|
104
|
+
debugLog(`Task manager root not found in any parent directory`);
|
|
28
105
|
return null;
|
|
29
106
|
}
|
|
30
107
|
|
|
31
108
|
/**
|
|
32
|
-
* Parse YAML frontmatter for ID with
|
|
109
|
+
* Parse YAML frontmatter for ID with comprehensive error handling and debug logging
|
|
33
110
|
* @param {string} content - File content
|
|
111
|
+
* @param {string} [filePath] - Optional file path for error context
|
|
34
112
|
* @returns {number|null} Extracted ID or null
|
|
35
113
|
*/
|
|
36
|
-
function extractIdFromFrontmatter(content) {
|
|
37
|
-
|
|
38
|
-
|
|
114
|
+
function extractIdFromFrontmatter(content, filePath = 'unknown') {
|
|
115
|
+
debugLog(`Attempting to extract ID from frontmatter in: ${filePath}`);
|
|
116
|
+
|
|
117
|
+
// Check for frontmatter block existence
|
|
118
|
+
const frontmatterMatch = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
|
|
119
|
+
if (!frontmatterMatch) {
|
|
120
|
+
debugLog(`No frontmatter block found in: ${filePath}`);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
39
123
|
|
|
40
124
|
const frontmatterText = frontmatterMatch[1];
|
|
125
|
+
debugLog(`Found frontmatter block in ${filePath}:\n${frontmatterText}`);
|
|
41
126
|
|
|
42
|
-
//
|
|
43
|
-
// id: 5
|
|
44
|
-
// id: "5"
|
|
45
|
-
// id: '5'
|
|
46
|
-
// "id": 5
|
|
47
|
-
// 'id': 5
|
|
48
|
-
// id : 5
|
|
127
|
+
// Enhanced patterns to handle various YAML formats and edge cases:
|
|
128
|
+
// - id: 5 (simple numeric)
|
|
129
|
+
// - id: "5" (double quoted)
|
|
130
|
+
// - id: '5' (single quoted)
|
|
131
|
+
// - "id": 5 (quoted key)
|
|
132
|
+
// - 'id': 5 (single quoted key)
|
|
133
|
+
// - id : 5 (extra spaces)
|
|
134
|
+
// - id: 05 (zero-padded)
|
|
135
|
+
// - id: +5 (explicit positive)
|
|
136
|
+
// - Mixed quotes: 'id': "5" (different quote types)
|
|
49
137
|
const patterns = [
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
138
|
+
// Most flexible pattern - handles quoted/unquoted keys and values with optional spaces
|
|
139
|
+
{
|
|
140
|
+
regex: /^\s*["']?id["']?\s*:\s*["']?([+-]?\d+)["']?\s*(?:#.*)?$/mi,
|
|
141
|
+
description: 'Flexible pattern with optional quotes and comments'
|
|
142
|
+
},
|
|
143
|
+
// Simple numeric with optional whitespace and comments
|
|
144
|
+
{
|
|
145
|
+
regex: /^\s*id\s*:\s*([+-]?\d+)\s*(?:#.*)?$/mi,
|
|
146
|
+
description: 'Simple numeric with optional comments'
|
|
147
|
+
},
|
|
148
|
+
// Double quoted values
|
|
149
|
+
{
|
|
150
|
+
regex: /^\s*["']?id["']?\s*:\s*"([+-]?\d+)"\s*(?:#.*)?$/mi,
|
|
151
|
+
description: 'Double quoted values'
|
|
152
|
+
},
|
|
153
|
+
// Single quoted values
|
|
154
|
+
{
|
|
155
|
+
regex: /^\s*["']?id["']?\s*:\s*'([+-]?\d+)'\s*(?:#.*)?$/mi,
|
|
156
|
+
description: 'Single quoted values'
|
|
157
|
+
},
|
|
158
|
+
// Mixed quotes - quoted key, unquoted value
|
|
159
|
+
{
|
|
160
|
+
regex: /^\s*["']id["']\s*:\s*([+-]?\d+)\s*(?:#.*)?$/mi,
|
|
161
|
+
description: 'Quoted key, unquoted value'
|
|
162
|
+
},
|
|
163
|
+
// YAML-style with pipe or greater-than indicators (edge case)
|
|
164
|
+
{
|
|
165
|
+
regex: /^\s*id\s*:\s*[|>]\s*([+-]?\d+)\s*$/mi,
|
|
166
|
+
description: 'YAML block scalar indicators'
|
|
167
|
+
}
|
|
54
168
|
];
|
|
55
169
|
|
|
56
|
-
|
|
57
|
-
|
|
170
|
+
// Try each pattern in order
|
|
171
|
+
for (let i = 0; i < patterns.length; i++) {
|
|
172
|
+
const { regex, description } = patterns[i];
|
|
173
|
+
debugLog(`Trying pattern ${i + 1} (${description}) on ${filePath}`);
|
|
174
|
+
|
|
175
|
+
const match = frontmatterText.match(regex);
|
|
58
176
|
if (match) {
|
|
59
|
-
|
|
60
|
-
|
|
177
|
+
debugLog(`Pattern ${i + 1} matched in ${filePath}: "${match[0].trim()}"`);
|
|
178
|
+
|
|
179
|
+
const rawId = match[1];
|
|
180
|
+
const id = parseInt(rawId, 10);
|
|
181
|
+
|
|
182
|
+
// Validate the parsed ID
|
|
183
|
+
if (isNaN(id)) {
|
|
184
|
+
errorLog(`Invalid ID value "${rawId}" in ${filePath} - not a valid number`);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (id < 0) {
|
|
189
|
+
errorLog(`Invalid ID value ${id} in ${filePath} - ID must be non-negative`);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (id > Number.MAX_SAFE_INTEGER) {
|
|
194
|
+
errorLog(`Invalid ID value ${id} in ${filePath} - ID exceeds maximum safe integer`);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
debugLog(`Successfully extracted ID ${id} from ${filePath}`);
|
|
199
|
+
return id;
|
|
200
|
+
} else {
|
|
201
|
+
debugLog(`Pattern ${i + 1} did not match in ${filePath}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// If no patterns matched, try to identify common issues
|
|
206
|
+
debugLog(`All patterns failed for ${filePath}. Analyzing frontmatter for common issues...`);
|
|
207
|
+
|
|
208
|
+
// Check for 'id' field existence (case-insensitive)
|
|
209
|
+
const hasIdField = /^\s*["']?id["']?\s*:/mi.test(frontmatterText);
|
|
210
|
+
if (!hasIdField) {
|
|
211
|
+
debugLog(`No 'id' field found in frontmatter of ${filePath}`);
|
|
212
|
+
} else {
|
|
213
|
+
// ID field exists but didn't match - might be malformed
|
|
214
|
+
const idLineMatch = frontmatterText.match(/^\s*["']?id["']?\s*:.*$/mi);
|
|
215
|
+
if (idLineMatch) {
|
|
216
|
+
const idLine = idLineMatch[0].trim();
|
|
217
|
+
errorLog(`Found malformed ID line in ${filePath}: "${idLine}"`);
|
|
218
|
+
|
|
219
|
+
// Check for common formatting issues
|
|
220
|
+
if (idLine.includes('null') || idLine.includes('undefined')) {
|
|
221
|
+
errorLog(`ID field has null/undefined value in ${filePath}`);
|
|
222
|
+
} else if (idLine.match(/:\s*$/)) {
|
|
223
|
+
errorLog(`ID field has missing value in ${filePath}`);
|
|
224
|
+
} else if (idLine.includes('[') || idLine.includes('{')) {
|
|
225
|
+
errorLog(`ID field appears to be array/object instead of number in ${filePath}`);
|
|
226
|
+
} else {
|
|
227
|
+
errorLog(`ID field has unrecognized format in ${filePath}`);
|
|
228
|
+
}
|
|
61
229
|
}
|
|
62
230
|
}
|
|
63
231
|
|
|
232
|
+
errorLog(`Failed to extract ID from frontmatter in ${filePath}`);
|
|
64
233
|
return null;
|
|
65
234
|
}
|
|
66
235
|
|
|
@@ -72,52 +241,190 @@ function getNextPlanId() {
|
|
|
72
241
|
const taskManagerRoot = findTaskManagerRoot();
|
|
73
242
|
|
|
74
243
|
if (!taskManagerRoot) {
|
|
75
|
-
|
|
76
|
-
|
|
244
|
+
errorLog('No .ai/task-manager/plans directory found in current directory or any parent directory.');
|
|
245
|
+
errorLog('');
|
|
246
|
+
errorLog('Please ensure you are in a project with task manager initialized, or navigate to the correct');
|
|
247
|
+
errorLog('project directory. The task manager looks for the .ai/task-manager/plans structure starting');
|
|
248
|
+
errorLog('from the current working directory and traversing upward through parent directories.');
|
|
249
|
+
errorLog('');
|
|
250
|
+
errorLog(`Current working directory: ${process.cwd()}`);
|
|
77
251
|
process.exit(1);
|
|
78
252
|
}
|
|
79
253
|
|
|
254
|
+
debugLog(`Task manager root found: ${taskManagerRoot}`);
|
|
255
|
+
|
|
80
256
|
const plansDir = path.join(taskManagerRoot, 'plans');
|
|
81
257
|
const archiveDir = path.join(taskManagerRoot, 'archive');
|
|
82
258
|
|
|
259
|
+
debugLog(`Scanning directories: ${plansDir}, ${archiveDir}`);
|
|
260
|
+
|
|
83
261
|
let maxId = 0;
|
|
262
|
+
let filesScanned = 0;
|
|
263
|
+
let errorsEncountered = 0;
|
|
84
264
|
|
|
85
265
|
// Scan both plans and archive directories
|
|
86
266
|
[plansDir, archiveDir].forEach(dir => {
|
|
87
|
-
|
|
267
|
+
const dirName = path.basename(dir);
|
|
268
|
+
debugLog(`Scanning directory: ${dir}`);
|
|
269
|
+
|
|
270
|
+
if (!fs.existsSync(dir)) {
|
|
271
|
+
debugLog(`Directory does not exist: ${dir}`);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
88
274
|
|
|
89
275
|
try {
|
|
90
276
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
277
|
+
debugLog(`Found ${entries.length} entries in ${dir}`);
|
|
91
278
|
|
|
92
279
|
entries.forEach(entry => {
|
|
93
|
-
if (entry.
|
|
280
|
+
if (entry.isDirectory() && entry.name.match(/^\d+--/)) {
|
|
281
|
+
// This is a plan directory, look for plan files inside
|
|
282
|
+
const planDirPath = path.join(dir, entry.name);
|
|
283
|
+
debugLog(`Scanning plan directory: ${planDirPath}`);
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
const planDirEntries = fs.readdirSync(planDirPath, { withFileTypes: true });
|
|
287
|
+
|
|
288
|
+
planDirEntries.forEach(planEntry => {
|
|
289
|
+
if (planEntry.isFile() && planEntry.name.match(/^plan-\d+--.*\.md$/)) {
|
|
290
|
+
filesScanned++;
|
|
291
|
+
const filePath = path.join(planDirPath, planEntry.name);
|
|
292
|
+
debugLog(`Processing plan file: ${filePath}`);
|
|
293
|
+
|
|
294
|
+
// Extract ID from directory name as primary source
|
|
295
|
+
const dirMatch = entry.name.match(/^(\d+)--/);
|
|
296
|
+
let dirId = null;
|
|
297
|
+
if (dirMatch) {
|
|
298
|
+
dirId = parseInt(dirMatch[1], 10);
|
|
299
|
+
if (!isNaN(dirId)) {
|
|
300
|
+
debugLog(`Extracted ID ${dirId} from directory name: ${entry.name}`);
|
|
301
|
+
if (dirId > maxId) {
|
|
302
|
+
maxId = dirId;
|
|
303
|
+
debugLog(`New max ID from directory name: ${maxId}`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Extract ID from filename as secondary source
|
|
309
|
+
const filenameMatch = planEntry.name.match(/^plan-(\d+)--/);
|
|
310
|
+
let filenameId = null;
|
|
311
|
+
if (filenameMatch) {
|
|
312
|
+
filenameId = parseInt(filenameMatch[1], 10);
|
|
313
|
+
if (!isNaN(filenameId)) {
|
|
314
|
+
debugLog(`Extracted ID ${filenameId} from filename: ${planEntry.name}`);
|
|
315
|
+
if (filenameId > maxId) {
|
|
316
|
+
maxId = filenameId;
|
|
317
|
+
debugLog(`New max ID from filename: ${maxId}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Also check frontmatter for most reliable ID
|
|
323
|
+
try {
|
|
324
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
325
|
+
const frontmatterId = extractIdFromFrontmatter(content, filePath);
|
|
326
|
+
|
|
327
|
+
if (frontmatterId !== null) {
|
|
328
|
+
debugLog(`Extracted ID ${frontmatterId} from frontmatter: ${filePath}`);
|
|
329
|
+
if (frontmatterId > maxId) {
|
|
330
|
+
maxId = frontmatterId;
|
|
331
|
+
debugLog(`New max ID from frontmatter: ${maxId}`);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Validate consistency between all sources
|
|
335
|
+
if (dirId !== null && dirId !== frontmatterId) {
|
|
336
|
+
errorLog(`ID mismatch in ${filePath}: directory has ${dirId}, frontmatter has ${frontmatterId}`);
|
|
337
|
+
errorsEncountered++;
|
|
338
|
+
}
|
|
339
|
+
if (filenameId !== null && filenameId !== frontmatterId) {
|
|
340
|
+
errorLog(`ID mismatch in ${filePath}: filename has ${filenameId}, frontmatter has ${frontmatterId}`);
|
|
341
|
+
errorsEncountered++;
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
debugLog(`No ID found in frontmatter: ${filePath}`);
|
|
345
|
+
if (dirId === null && filenameId === null) {
|
|
346
|
+
errorLog(`No valid ID found in directory, filename, or frontmatter: ${filePath}`);
|
|
347
|
+
errorsEncountered++;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
} catch (err) {
|
|
351
|
+
errorLog(`Failed to read file ${filePath}: ${err.message}`);
|
|
352
|
+
errorsEncountered++;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
} catch (err) {
|
|
357
|
+
errorLog(`Failed to read plan directory ${planDirPath}: ${err.message}`);
|
|
358
|
+
errorsEncountered++;
|
|
359
|
+
}
|
|
360
|
+
} else if (entry.isFile() && entry.name.match(/^plan-\d+--.*\.md$/)) {
|
|
361
|
+
// Legacy: direct plan file in plans/archive directory (fallback for old format)
|
|
362
|
+
filesScanned++;
|
|
363
|
+
const filePath = path.join(dir, entry.name);
|
|
364
|
+
debugLog(`Processing legacy plan file: ${filePath}`);
|
|
365
|
+
|
|
94
366
|
// Extract ID from filename as fallback
|
|
95
367
|
const filenameMatch = entry.name.match(/^plan-(\d+)--/);
|
|
368
|
+
let filenameId = null;
|
|
96
369
|
if (filenameMatch) {
|
|
97
|
-
|
|
98
|
-
if (!isNaN(
|
|
370
|
+
filenameId = parseInt(filenameMatch[1], 10);
|
|
371
|
+
if (!isNaN(filenameId)) {
|
|
372
|
+
debugLog(`Extracted ID ${filenameId} from legacy filename: ${entry.name}`);
|
|
373
|
+
if (filenameId > maxId) {
|
|
374
|
+
maxId = filenameId;
|
|
375
|
+
debugLog(`New max ID from legacy filename: ${maxId}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
99
378
|
}
|
|
100
379
|
|
|
101
380
|
// Also check frontmatter for more reliable ID
|
|
102
381
|
try {
|
|
103
|
-
const filePath = path.join(dir, entry.name);
|
|
104
382
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
105
|
-
const
|
|
383
|
+
const frontmatterId = extractIdFromFrontmatter(content, filePath);
|
|
384
|
+
|
|
385
|
+
if (frontmatterId !== null) {
|
|
386
|
+
debugLog(`Extracted ID ${frontmatterId} from legacy frontmatter: ${filePath}`);
|
|
387
|
+
if (frontmatterId > maxId) {
|
|
388
|
+
maxId = frontmatterId;
|
|
389
|
+
debugLog(`New max ID from legacy frontmatter: ${maxId}`);
|
|
390
|
+
}
|
|
106
391
|
|
|
107
|
-
|
|
108
|
-
|
|
392
|
+
// Validate consistency between filename and frontmatter
|
|
393
|
+
if (filenameId !== null && filenameId !== frontmatterId) {
|
|
394
|
+
errorLog(`ID mismatch in legacy ${filePath}: filename has ${filenameId}, frontmatter has ${frontmatterId}`);
|
|
395
|
+
errorsEncountered++;
|
|
396
|
+
}
|
|
397
|
+
} else {
|
|
398
|
+
debugLog(`No ID found in legacy frontmatter: ${filePath}`);
|
|
399
|
+
if (filenameId === null) {
|
|
400
|
+
errorLog(`No valid ID found in legacy filename or frontmatter: ${filePath}`);
|
|
401
|
+
errorsEncountered++;
|
|
402
|
+
}
|
|
109
403
|
}
|
|
110
404
|
} catch (err) {
|
|
111
|
-
|
|
405
|
+
errorLog(`Failed to read legacy file ${filePath}: ${err.message}`);
|
|
406
|
+
errorsEncountered++;
|
|
112
407
|
}
|
|
408
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
409
|
+
debugLog(`Skipping non-plan file: ${entry.name}`);
|
|
410
|
+
} else if (entry.isDirectory()) {
|
|
411
|
+
debugLog(`Skipping non-plan directory: ${entry.name}`);
|
|
113
412
|
}
|
|
114
413
|
});
|
|
115
414
|
} catch (err) {
|
|
116
|
-
|
|
415
|
+
errorLog(`Failed to read directory ${dir}: ${err.message}`);
|
|
416
|
+
errorsEncountered++;
|
|
117
417
|
}
|
|
118
418
|
});
|
|
119
419
|
|
|
120
|
-
|
|
420
|
+
const nextId = maxId + 1;
|
|
421
|
+
debugLog(`Scan complete. Files scanned: ${filesScanned}, Errors: ${errorsEncountered}, Max ID found: ${maxId}, Next ID: ${nextId}`);
|
|
422
|
+
|
|
423
|
+
if (errorsEncountered > 0) {
|
|
424
|
+
errorLog(`Encountered ${errorsEncountered} errors during scan. Next ID calculation may be inaccurate.`);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return nextId;
|
|
121
428
|
}
|
|
122
429
|
|
|
123
430
|
// Output the next plan ID
|
|
@@ -4,6 +4,8 @@ description: Create a comprehensive plan to accomplish the request from the user
|
|
|
4
4
|
---
|
|
5
5
|
# Comprehensive Plan Creation
|
|
6
6
|
|
|
7
|
+
Think harder and use tools.
|
|
8
|
+
|
|
7
9
|
You are a comprehensive task planning assistant. Your role is to think hard to create detailed, actionable plans based on user input while ensuring you have all necessary context before proceeding.
|
|
8
10
|
|
|
9
11
|
Include .ai/task-manager/config/TASK_MANAGER.md for the directory structure of tasks.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
argument-hint: [test-command]
|
|
3
|
+
description: Fix the tests your task execution broke.
|
|
4
|
+
---
|
|
5
|
+
Fix all failing tests in this repository. Think harder and use tools.
|
|
6
|
+
|
|
7
|
+
Execute this command to run the tests:
|
|
8
|
+
|
|
9
|
+
<test-command>
|
|
10
|
+
$1
|
|
11
|
+
</test-command>
|
|
12
|
+
|
|
13
|
+
If the test command is empty, read CLAUDE.md for test execution instructions.
|
|
14
|
+
|
|
15
|
+
⚠️ **CRITICAL INTEGRITY REQUIREMENT** ⚠️
|
|
16
|
+
You MUST fix the actual bugs in the source code. Green tests are worthless if achieved through cheating.
|
|
17
|
+
|
|
18
|
+
**This is CHEATING (absolutely forbidden):**
|
|
19
|
+
- Skipping tests with conditionals
|
|
20
|
+
- Modifying test assertions to pass
|
|
21
|
+
- Adding test-environment-specific code to source
|
|
22
|
+
- Disabling or commenting out tests
|
|
23
|
+
- ANY workaround that doesn't fix the real bug
|
|
24
|
+
|
|
25
|
+
**This is THE RIGHT WAY:**
|
|
26
|
+
- Find the root cause in the source code
|
|
27
|
+
- Fix the actual bug
|
|
28
|
+
- Ensure tests pass because the code truly works
|
|
29
|
+
|
|
30
|
+
**Process:**
|
|
31
|
+
1. Run all tests to identify failures
|
|
32
|
+
2. Fix EVERY failing test iteratively
|
|
33
|
+
3. Verify all tests pass legitimately
|
|
34
|
+
|
|
35
|
+
DO NOT STOP after fixing some tests - fix ALL of them.
|
|
36
|
+
|
|
37
|
+
Remember: The entire point of tests is to ensure code robustness. If you cheat in ANY way, the tests become meaningless and I cannot trust that the code actually works.
|
|
38
|
+
|
|
39
|
+
If you get stuck and cannot fix a test properly, ask for help rather than resorting to shortcuts.
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
argument-hint: [plan-ID]
|
|
3
3
|
description: Generate tasks to implement the plan with the provided ID.
|
|
4
4
|
---
|
|
5
|
+
|
|
5
6
|
# Comprehensive Task List Creation
|
|
7
|
+
|
|
8
|
+
Think harder and use tools.
|
|
9
|
+
|
|
6
10
|
You are a comprehensive task planning assistant. Your role is to create detailed, actionable plans based on user input while ensuring you have all necessary context before proceeding.
|
|
7
11
|
|
|
8
12
|
Include /TASK_MANAGER.md for the directory structure of tasks.
|