@e0ipso/ai-task-manager 1.26.3 → 1.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/package.json +1 -1
- package/templates/ai-task-manager/config/scripts/check-task-dependencies.cjs +212 -274
- package/templates/ai-task-manager/config/scripts/find-root.cjs +10 -0
- package/templates/ai-task-manager/config/scripts/get-next-plan-id.cjs +22 -59
- package/templates/ai-task-manager/config/scripts/get-next-task-id.cjs +29 -48
- package/templates/ai-task-manager/config/scripts/shared-utils.cjs +332 -85
- package/templates/ai-task-manager/config/scripts/validate-plan-blueprint.cjs +80 -188
- package/templates/assistant/commands/tasks/create-plan.md +16 -4
- package/templates/assistant/commands/tasks/execute-blueprint.md +17 -4
- package/templates/assistant/commands/tasks/execute-task.md +16 -5
- package/templates/assistant/commands/tasks/full-workflow.md +20 -7
- package/templates/assistant/commands/tasks/generate-tasks.md +15 -2
- package/templates/assistant/commands/tasks/refine-plan.md +16 -5
package/package.json
CHANGED
|
@@ -9,323 +9,261 @@
|
|
|
9
9
|
|
|
10
10
|
const fs = require('fs-extra');
|
|
11
11
|
const path = require('path');
|
|
12
|
-
const {
|
|
13
|
-
|
|
12
|
+
const {
|
|
13
|
+
resolvePlan,
|
|
14
|
+
parseFrontmatter
|
|
15
|
+
} = require('./shared-utils.cjs');
|
|
14
16
|
|
|
15
17
|
// Chalk instance - loaded dynamically to handle ESM module
|
|
16
18
|
let chalkInstance = null;
|
|
17
19
|
|
|
18
20
|
// Initialize chalk instance dynamically
|
|
19
|
-
async function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
async function _initChalk() {
|
|
22
|
+
if (chalkInstance) return chalkInstance;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const {
|
|
26
|
+
default: chalk
|
|
27
|
+
} = await import('chalk');
|
|
28
|
+
chalkInstance = chalk;
|
|
29
|
+
} catch (_error) {
|
|
30
|
+
// Chalk not available, will fall back to plain console output
|
|
31
|
+
chalkInstance = null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return chalkInstance;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
// Color functions for output
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
const _printError = (message, chalk) => {
|
|
39
|
+
const formattedMessage = chalk?.red(`ERROR: ${message}`) || `ERROR: ${message}`;
|
|
40
|
+
console.error(formattedMessage);
|
|
37
41
|
};
|
|
38
42
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
const _printSuccess = (message, chalk) => {
|
|
44
|
+
const formattedMessage = chalk?.green(`✓ ${message}`) || `✓ ${message}`;
|
|
45
|
+
console.log(formattedMessage);
|
|
42
46
|
};
|
|
43
47
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
const _printWarning = (message, chalk) => {
|
|
49
|
+
const formattedMessage = chalk?.yellow(`⚠ ${message}`) || `⚠ ${message}`;
|
|
50
|
+
console.log(formattedMessage);
|
|
47
51
|
};
|
|
48
52
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// Function to find plan directory
|
|
54
|
-
const findPlanDirectory = (planId) => {
|
|
55
|
-
const searchLocations = [
|
|
56
|
-
'.ai/task-manager/plans',
|
|
57
|
-
'.ai/task-manager/archive'
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
// Generate ID variations to try (exact, padded, unpadded)
|
|
61
|
-
const idVariations = [
|
|
62
|
-
planId, // Try exact match first
|
|
63
|
-
planId.padStart(2, '0'), // Try padded version (3 → 03)
|
|
64
|
-
planId.replace(/^0+/, '') || '0' // Try unpadded version (03 → 3)
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
// Remove duplicates from variations array
|
|
68
|
-
const uniqueVariations = [...new Set(idVariations)];
|
|
69
|
-
|
|
70
|
-
// Search for each variation in each location
|
|
71
|
-
for (const id of uniqueVariations) {
|
|
72
|
-
for (const location of searchLocations) {
|
|
73
|
-
try {
|
|
74
|
-
const findCommand = `find ${location} -type d -name "${id}--*" 2>/dev/null || true`;
|
|
75
|
-
const result = execSync(findCommand, { encoding: 'utf8' }).trim();
|
|
76
|
-
const directories = result.split('\n').filter(dir => dir.length > 0);
|
|
77
|
-
|
|
78
|
-
if (directories.length > 0) {
|
|
79
|
-
return directories[0]; // Early return on first match
|
|
80
|
-
}
|
|
81
|
-
} catch (error) {
|
|
82
|
-
// Continue trying other variations/locations
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return null; // No matches found
|
|
53
|
+
const _printInfo = (message) => {
|
|
54
|
+
console.log(message);
|
|
89
55
|
};
|
|
90
56
|
|
|
91
57
|
// Function to find task file with padded/unpadded ID handling
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (!fs.existsSync(taskDir)) {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
58
|
+
const _findTaskFile = (planDir, taskId) => {
|
|
59
|
+
const taskDir = path.join(planDir, 'tasks');
|
|
98
60
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
61
|
+
if (!fs.existsSync(taskDir)) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const variations = [
|
|
66
|
+
taskId,
|
|
67
|
+
taskId.padStart(2, '0'),
|
|
68
|
+
taskId.replace(/^0+/, '') || '0'
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
const uniqueVariations = [...new Set(variations)];
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const files = fs.readdirSync(taskDir);
|
|
75
|
+
const found = uniqueVariations.reduce((acc, v) => {
|
|
76
|
+
if (acc) return acc;
|
|
77
|
+
const match = files.find(f => f.startsWith(`${v}--`) && f.endsWith('.md'));
|
|
78
|
+
return match ? path.join(taskDir, match) : null;
|
|
79
|
+
}, null);
|
|
80
|
+
return found;
|
|
81
|
+
} catch (err) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
105
85
|
|
|
106
|
-
if (files.length > 0) {
|
|
107
|
-
return path.join(taskDir, files[0]);
|
|
108
|
-
}
|
|
109
86
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
87
|
+
// Function to extract dependencies from frontmatter
|
|
88
|
+
const _extractDependencies = (frontmatter) => {
|
|
89
|
+
const lines = frontmatter.split('\n');
|
|
90
|
+
const dependencies = [];
|
|
91
|
+
let inDependenciesSection = false;
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < lines.length; i++) {
|
|
94
|
+
const line = lines[i];
|
|
95
|
+
|
|
96
|
+
// Check for dependencies line
|
|
97
|
+
if (line.match(/^dependencies:/)) {
|
|
98
|
+
inDependenciesSection = true;
|
|
99
|
+
|
|
100
|
+
// Check if dependencies are on the same line (array syntax)
|
|
101
|
+
const arrayMatch = line.match(/\[(.*)\]/);
|
|
102
|
+
if (arrayMatch) {
|
|
103
|
+
const deps = arrayMatch[1]
|
|
104
|
+
.split(',')
|
|
105
|
+
.map(dep => dep.trim().replace(/['"]/g, ''))
|
|
106
|
+
.filter(dep => dep.length > 0);
|
|
107
|
+
dependencies.push(...deps);
|
|
108
|
+
inDependenciesSection = false;
|
|
109
|
+
}
|
|
110
|
+
continue;
|
|
122
111
|
}
|
|
123
112
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
pattern = `${unpaddedTaskId}--*.md`;
|
|
128
|
-
files = fs.readdirSync(taskDir).filter(file => {
|
|
129
|
-
const regex = new RegExp(`^${unpaddedTaskId}--.*\\.md$`);
|
|
130
|
-
return regex.test(file);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
if (files.length > 0) {
|
|
134
|
-
return path.join(taskDir, files[0]);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Try with zero-padding of unpadded version
|
|
138
|
-
const repaddedTaskId = unpaddedTaskId.padStart(2, '0');
|
|
139
|
-
pattern = `${repaddedTaskId}--*.md`;
|
|
140
|
-
files = fs.readdirSync(taskDir).filter(file => {
|
|
141
|
-
const regex = new RegExp(`^${repaddedTaskId}--.*\\.md$`);
|
|
142
|
-
return regex.test(file);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
if (files.length > 0) {
|
|
146
|
-
return path.join(taskDir, files[0]);
|
|
147
|
-
}
|
|
113
|
+
// If we're in dependencies section and hit a non-indented line that's not a list item, exit
|
|
114
|
+
if (inDependenciesSection && line.match(/^[^ ]/) && !line.match(/^[ \t]*-/)) {
|
|
115
|
+
inDependenciesSection = false;
|
|
148
116
|
}
|
|
149
117
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const lines = frontmatter.split('\n');
|
|
157
|
-
const dependencies = [];
|
|
158
|
-
let inDependenciesSection = false;
|
|
159
|
-
|
|
160
|
-
for (let i = 0; i < lines.length; i++) {
|
|
161
|
-
const line = lines[i];
|
|
162
|
-
|
|
163
|
-
// Check for dependencies line
|
|
164
|
-
if (line.match(/^dependencies:/)) {
|
|
165
|
-
inDependenciesSection = true;
|
|
166
|
-
|
|
167
|
-
// Check if dependencies are on the same line (array syntax)
|
|
168
|
-
const arrayMatch = line.match(/\[(.*)\]/);
|
|
169
|
-
if (arrayMatch) {
|
|
170
|
-
const deps = arrayMatch[1]
|
|
171
|
-
.split(',')
|
|
172
|
-
.map(dep => dep.trim().replace(/['"]/g, ''))
|
|
173
|
-
.filter(dep => dep.length > 0);
|
|
174
|
-
dependencies.push(...deps);
|
|
175
|
-
inDependenciesSection = false;
|
|
176
|
-
}
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// If we're in dependencies section and hit a non-indented line that's not a list item, exit
|
|
181
|
-
if (inDependenciesSection && line.match(/^[^ ]/) && !line.match(/^[ \t]*-/)) {
|
|
182
|
-
inDependenciesSection = false;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Parse list format dependencies
|
|
186
|
-
if (inDependenciesSection && line.match(/^[ \t]*-/)) {
|
|
187
|
-
const dep = line.replace(/^[ \t]*-[ \t]*/, '').replace(/[ \t]*$/, '').replace(/['"]/g, '');
|
|
188
|
-
if (dep.length > 0) {
|
|
189
|
-
dependencies.push(dep);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
118
|
+
// Parse list format dependencies
|
|
119
|
+
if (inDependenciesSection && line.match(/^[ \t]*-/)) {
|
|
120
|
+
const dep = line.replace(/^[ \t]*-[ \t]*/, '').replace(/[ \t]*$/, '').replace(/['"]/g, '');
|
|
121
|
+
if (dep.length > 0) {
|
|
122
|
+
dependencies.push(dep);
|
|
123
|
+
}
|
|
192
124
|
}
|
|
125
|
+
}
|
|
193
126
|
|
|
194
|
-
|
|
127
|
+
return dependencies;
|
|
195
128
|
};
|
|
196
129
|
|
|
197
130
|
// Function to extract status from frontmatter
|
|
198
|
-
const
|
|
199
|
-
|
|
131
|
+
const _extractStatus = (frontmatter) => {
|
|
132
|
+
const lines = frontmatter.split('\n');
|
|
200
133
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
134
|
+
for (const line of lines) {
|
|
135
|
+
if (line.match(/^status:/)) {
|
|
136
|
+
return line.replace(/^status:[ \t]*/, '').replace(/^["']/, '').replace(/["']$/, '').trim();
|
|
205
137
|
}
|
|
138
|
+
}
|
|
206
139
|
|
|
207
|
-
|
|
140
|
+
return null;
|
|
208
141
|
};
|
|
209
142
|
|
|
210
143
|
// Main function
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
144
|
+
const _main = async (startPath = process.cwd()) => {
|
|
145
|
+
// Initialize chalk
|
|
146
|
+
const chalk = await _initChalk();
|
|
147
|
+
|
|
148
|
+
// Check arguments
|
|
149
|
+
if (process.argv.length !== 4) {
|
|
150
|
+
_printError('Invalid number of arguments', chalk);
|
|
151
|
+
console.log('Usage: node check-task-dependencies.cjs <plan-id-or-path> <task-id>');
|
|
152
|
+
console.log('Example: node check-task-dependencies.cjs 16 03');
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const inputId = process.argv[2];
|
|
157
|
+
const taskId = process.argv[3];
|
|
158
|
+
|
|
159
|
+
const resolved = resolvePlan(inputId, startPath);
|
|
160
|
+
|
|
161
|
+
if (!resolved) {
|
|
162
|
+
_printError(`Plan "${inputId}" not found or invalid`, chalk);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const {
|
|
167
|
+
planDir,
|
|
168
|
+
planId
|
|
169
|
+
} = resolved;
|
|
170
|
+
_printInfo(`Found plan directory: ${planDir}`);
|
|
171
|
+
|
|
172
|
+
// Find task file
|
|
173
|
+
const taskFile = _findTaskFile(planDir, taskId);
|
|
174
|
+
|
|
175
|
+
if (!taskFile || !fs.existsSync(taskFile)) {
|
|
176
|
+
_printError(`Task with ID ${taskId} not found in plan ${planId}`, chalk);
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
_printInfo(`Checking task: ${path.basename(taskFile)}`);
|
|
181
|
+
console.log('');
|
|
182
|
+
|
|
183
|
+
// Read and parse task file
|
|
184
|
+
const taskContent = fs.readFileSync(taskFile, 'utf8');
|
|
185
|
+
const frontmatter = parseFrontmatter(taskContent);
|
|
186
|
+
const dependencies = _extractDependencies(frontmatter);
|
|
187
|
+
|
|
188
|
+
// Check if there are any dependencies
|
|
189
|
+
if (dependencies.length === 0) {
|
|
190
|
+
_printSuccess('Task has no dependencies - ready to execute!', chalk);
|
|
191
|
+
process.exit(0);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Display dependencies
|
|
195
|
+
_printInfo('Task dependencies found:');
|
|
196
|
+
dependencies.forEach(dep => {
|
|
197
|
+
console.log(` - Task ${dep}`);
|
|
198
|
+
});
|
|
199
|
+
console.log('');
|
|
200
|
+
|
|
201
|
+
// Check each dependency
|
|
202
|
+
let allResolved = true;
|
|
203
|
+
let unresolvedDeps = [];
|
|
204
|
+
let resolvedCount = 0;
|
|
205
|
+
const totalDeps = dependencies.length;
|
|
206
|
+
|
|
207
|
+
_printInfo('Checking dependency status...');
|
|
208
|
+
console.log('');
|
|
209
|
+
|
|
210
|
+
for (const depId of dependencies) {
|
|
211
|
+
// Find dependency task file
|
|
212
|
+
const depFile = _findTaskFile(planDir, depId);
|
|
213
|
+
|
|
214
|
+
if (!depFile || !fs.existsSync(depFile)) {
|
|
215
|
+
_printError(`Dependency task ${depId} not found`, chalk);
|
|
216
|
+
allResolved = false;
|
|
217
|
+
unresolvedDeps.push(`${depId} (not found)`);
|
|
218
|
+
continue;
|
|
242
219
|
}
|
|
243
220
|
|
|
244
|
-
|
|
245
|
-
|
|
221
|
+
// Extract status from dependency task
|
|
222
|
+
const depContent = fs.readFileSync(depFile, 'utf8');
|
|
223
|
+
const depFrontmatter = parseFrontmatter(depContent);
|
|
224
|
+
const status = _extractStatus(depFrontmatter);
|
|
246
225
|
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
// Check if there are any dependencies
|
|
253
|
-
if (dependencies.length === 0) {
|
|
254
|
-
printSuccess('Task has no dependencies - ready to execute!', chalk);
|
|
255
|
-
process.exit(0);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Display dependencies
|
|
259
|
-
printInfo('Task dependencies found:');
|
|
260
|
-
dependencies.forEach(dep => {
|
|
261
|
-
console.log(` - Task ${dep}`);
|
|
262
|
-
});
|
|
263
|
-
console.log('');
|
|
264
|
-
|
|
265
|
-
// Check each dependency
|
|
266
|
-
let allResolved = true;
|
|
267
|
-
let unresolvedDeps = [];
|
|
268
|
-
let resolvedCount = 0;
|
|
269
|
-
const totalDeps = dependencies.length;
|
|
270
|
-
|
|
271
|
-
printInfo('Checking dependency status...');
|
|
272
|
-
console.log('');
|
|
273
|
-
|
|
274
|
-
for (const depId of dependencies) {
|
|
275
|
-
// Find dependency task file
|
|
276
|
-
const depFile = findTaskFile(planDir, depId);
|
|
277
|
-
|
|
278
|
-
if (!depFile || !fs.existsSync(depFile)) {
|
|
279
|
-
printError(`Dependency task ${depId} not found`, chalk);
|
|
280
|
-
allResolved = false;
|
|
281
|
-
unresolvedDeps.push(`${depId} (not found)`);
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Extract status from dependency task
|
|
286
|
-
const depContent = fs.readFileSync(depFile, 'utf8');
|
|
287
|
-
const depFrontmatter = parseFrontmatter(depContent);
|
|
288
|
-
const status = extractStatus(depFrontmatter);
|
|
289
|
-
|
|
290
|
-
// Check if status is completed
|
|
291
|
-
if (status === 'completed') {
|
|
292
|
-
printSuccess(`Task ${depId} - Status: completed ✓`, chalk);
|
|
293
|
-
resolvedCount++;
|
|
294
|
-
} else {
|
|
295
|
-
printWarning(`Task ${depId} - Status: ${status || 'unknown'} ✗`, chalk);
|
|
296
|
-
allResolved = false;
|
|
297
|
-
unresolvedDeps.push(`${depId} (${status || 'unknown'})`);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
console.log('');
|
|
302
|
-
printInfo('=========================================');
|
|
303
|
-
printInfo('Dependency Check Summary');
|
|
304
|
-
printInfo('=========================================');
|
|
305
|
-
printInfo(`Total dependencies: ${totalDeps}`);
|
|
306
|
-
printInfo(`Resolved: ${resolvedCount}`);
|
|
307
|
-
printInfo(`Unresolved: ${totalDeps - resolvedCount}`);
|
|
308
|
-
console.log('');
|
|
309
|
-
|
|
310
|
-
if (allResolved) {
|
|
311
|
-
printSuccess(`All dependencies are resolved! Task ${taskId} is ready to execute.`, chalk);
|
|
312
|
-
process.exit(0);
|
|
226
|
+
// Check if status is completed
|
|
227
|
+
if (status === 'completed') {
|
|
228
|
+
_printSuccess(`Task ${depId} - Status: completed ✓`, chalk);
|
|
229
|
+
resolvedCount++;
|
|
313
230
|
} else {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
});
|
|
318
|
-
printInfo('Please complete the dependencies before executing this task.');
|
|
319
|
-
process.exit(1);
|
|
231
|
+
_printWarning(`Task ${depId} - Status: ${status || 'unknown'} ✗`, chalk);
|
|
232
|
+
allResolved = false;
|
|
233
|
+
unresolvedDeps.push(`${depId} (${status || 'unknown'})`);
|
|
320
234
|
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
console.log('');
|
|
238
|
+
_printInfo('=========================================');
|
|
239
|
+
_printInfo('Dependency Check Summary');
|
|
240
|
+
_printInfo('=========================================');
|
|
241
|
+
_printInfo(`Total dependencies: ${totalDeps}`);
|
|
242
|
+
_printInfo(`Resolved: ${resolvedCount}`);
|
|
243
|
+
_printInfo(`Unresolved: ${totalDeps - resolvedCount}`);
|
|
244
|
+
console.log('');
|
|
245
|
+
|
|
246
|
+
if (allResolved) {
|
|
247
|
+
_printSuccess(`All dependencies are resolved! Task ${taskId} is ready to execute.`, chalk);
|
|
248
|
+
process.exit(0);
|
|
249
|
+
} else {
|
|
250
|
+
_printError(`Task ${taskId} has unresolved dependencies:`, chalk);
|
|
251
|
+
unresolvedDeps.forEach(dep => {
|
|
252
|
+
console.log(dep);
|
|
253
|
+
});
|
|
254
|
+
_printInfo('Please complete the dependencies before executing this task.');
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
321
257
|
};
|
|
322
258
|
|
|
323
259
|
// Run the script
|
|
324
260
|
if (require.main === module) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
261
|
+
_main().catch((error) => {
|
|
262
|
+
console.error('Script execution failed:', error);
|
|
263
|
+
process.exit(1);
|
|
264
|
+
});
|
|
329
265
|
}
|
|
330
266
|
|
|
331
|
-
module.exports = {
|
|
267
|
+
module.exports = {
|
|
268
|
+
_main
|
|
269
|
+
};
|
|
@@ -2,85 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const { findTaskManagerRoot,
|
|
5
|
+
const { findTaskManagerRoot, getAllPlans } = require('./shared-utils.cjs');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Error logging utility
|
|
9
|
+
* @private
|
|
9
10
|
* @param {string} message - Error message
|
|
10
11
|
* @param {...any} args - Additional arguments to log
|
|
11
12
|
*/
|
|
12
|
-
function
|
|
13
|
+
function _errorLog(message, ...args) {
|
|
13
14
|
console.error(`[ERROR] ${message}`, ...args);
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Get the next available plan ID by scanning existing plan files
|
|
19
|
+
* @private
|
|
18
20
|
* @returns {number} Next available plan ID
|
|
19
21
|
*/
|
|
20
|
-
function
|
|
22
|
+
function _getNextPlanId() {
|
|
21
23
|
const taskManagerRoot = findTaskManagerRoot();
|
|
22
24
|
|
|
23
25
|
if (!taskManagerRoot) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
_errorLog('No .ai/task-manager/plans directory found in current directory or any parent directory.');
|
|
27
|
+
_errorLog('');
|
|
28
|
+
_errorLog('Please ensure you are in a project with task manager initialized, or navigate to the correct');
|
|
29
|
+
_errorLog('project directory. The task manager looks for the .ai/task-manager/plans structure starting');
|
|
30
|
+
_errorLog('from the current working directory and traversing upward through parent directories.');
|
|
31
|
+
_errorLog('');
|
|
32
|
+
_errorLog(`Current working directory: ${process.cwd()}`);
|
|
31
33
|
process.exit(1);
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
let maxId = 0;
|
|
38
|
-
|
|
39
|
-
// Scan both plans and archive directories
|
|
40
|
-
[plansDir, archiveDir].forEach(dir => {
|
|
41
|
-
if (!fs.existsSync(dir)) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
47
|
-
|
|
48
|
-
entries.forEach(entry => {
|
|
49
|
-
if (entry.isDirectory() && entry.name.match(/^\d+--/)) {
|
|
50
|
-
// This is a plan directory, look for plan files inside
|
|
51
|
-
const planDirPath = path.join(dir, entry.name);
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
const planDirEntries = fs.readdirSync(planDirPath, { withFileTypes: true });
|
|
55
|
-
|
|
56
|
-
planDirEntries.forEach(planEntry => {
|
|
57
|
-
if (planEntry.isFile() && planEntry.name.match(/^plan-\d+--.*\.md$/)) {
|
|
58
|
-
const filePath = path.join(planDirPath, planEntry.name);
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
62
|
-
const frontmatterId = extractIdFromFrontmatter(content, filePath);
|
|
63
|
-
|
|
64
|
-
if (frontmatterId !== null && frontmatterId > maxId) {
|
|
65
|
-
maxId = frontmatterId;
|
|
66
|
-
}
|
|
67
|
-
} catch (err) {
|
|
68
|
-
errorLog(`Failed to read file ${filePath}: ${err.message}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
} catch (err) {
|
|
73
|
-
errorLog(`Failed to read plan directory ${planDirPath}: ${err.message}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
} catch (err) {
|
|
78
|
-
errorLog(`Failed to read directory ${dir}: ${err.message}`);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
36
|
+
const plans = getAllPlans(taskManagerRoot);
|
|
37
|
+
const maxId = plans.reduce((max, p) => Math.max(max, p.id), 0);
|
|
81
38
|
|
|
82
39
|
return maxId + 1;
|
|
83
40
|
}
|
|
84
41
|
|
|
85
|
-
// Output the next plan ID
|
|
86
|
-
|
|
42
|
+
// Output the next plan ID if run directly
|
|
43
|
+
if (require.main === module) {
|
|
44
|
+
console.log(_getNextPlanId());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
_getNextPlanId
|
|
49
|
+
};
|