@e0ipso/ai-task-manager 1.18.6 → 1.19.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/dist/cli.js +17 -63
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +80 -83
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/ai-task-manager/config/scripts/get-approval-methods.cjs +229 -0
- package/templates/ai-task-manager/config/scripts/validate-plan-blueprint.cjs +294 -0
- package/templates/assistant/commands/tasks/execute-blueprint.md +12 -20
- package/templates/assistant/commands/tasks/generate-tasks.md +3 -4
- package/dist/logger.d.ts +0 -70
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -185
- package/dist/logger.js.map +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
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
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Find the task manager root directory by traversing up from current working directory
|
|
31
|
+
* @returns {string|null} Path to task manager root or null if not found
|
|
32
|
+
*/
|
|
33
|
+
function findTaskManagerRoot() {
|
|
34
|
+
let currentPath = process.cwd();
|
|
35
|
+
const filesystemRoot = path.parse(currentPath).root;
|
|
36
|
+
|
|
37
|
+
debugLog(`Starting search for task manager root from: ${currentPath}`);
|
|
38
|
+
|
|
39
|
+
while (currentPath !== filesystemRoot) {
|
|
40
|
+
const taskManagerPlansPath = path.join(currentPath, '.ai', 'task-manager', 'plans');
|
|
41
|
+
debugLog(`Checking for task manager at: ${taskManagerPlansPath}`);
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
if (fs.existsSync(taskManagerPlansPath)) {
|
|
45
|
+
const stats = fs.lstatSync(taskManagerPlansPath);
|
|
46
|
+
if (stats.isDirectory()) {
|
|
47
|
+
const taskManagerRoot = path.join(currentPath, '.ai', 'task-manager');
|
|
48
|
+
debugLog(`Found valid task manager root at: ${taskManagerRoot}`);
|
|
49
|
+
return taskManagerRoot;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
} catch (err) {
|
|
53
|
+
debugLog(`Filesystem error checking ${taskManagerPlansPath}: ${err.message}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const parentPath = path.dirname(currentPath);
|
|
57
|
+
if (parentPath === currentPath) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
currentPath = parentPath;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
debugLog(`Task manager root not found in any parent directory`);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Find plan file by ID in plans or archive directories
|
|
70
|
+
* @param {string} taskManagerRoot - Path to task manager root
|
|
71
|
+
* @param {string} planId - Plan ID to find
|
|
72
|
+
* @returns {string|null} Path to plan file or null if not found
|
|
73
|
+
*/
|
|
74
|
+
function findPlanFile(taskManagerRoot, planId) {
|
|
75
|
+
const plansDir = path.join(taskManagerRoot, 'plans');
|
|
76
|
+
const archiveDir = path.join(taskManagerRoot, 'archive');
|
|
77
|
+
|
|
78
|
+
debugLog(`Searching for plan ${planId} in ${plansDir} and ${archiveDir}`);
|
|
79
|
+
|
|
80
|
+
for (const dir of [plansDir, archiveDir]) {
|
|
81
|
+
if (!fs.existsSync(dir)) {
|
|
82
|
+
debugLog(`Directory does not exist: ${dir}`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
88
|
+
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
if (entry.isDirectory() && entry.name.match(/^\d+--/)) {
|
|
91
|
+
// Check if directory matches plan ID
|
|
92
|
+
const dirMatch = entry.name.match(/^(\d+)--/);
|
|
93
|
+
if (dirMatch && dirMatch[1] === planId) {
|
|
94
|
+
const planDirPath = path.join(dir, entry.name);
|
|
95
|
+
debugLog(`Found plan directory: ${planDirPath}`);
|
|
96
|
+
|
|
97
|
+
// Look for plan file inside directory
|
|
98
|
+
try {
|
|
99
|
+
const planDirEntries = fs.readdirSync(planDirPath, { withFileTypes: true });
|
|
100
|
+
|
|
101
|
+
for (const planEntry of planDirEntries) {
|
|
102
|
+
if (planEntry.isFile() && planEntry.name.match(/^plan-\d+--.*\.md$/)) {
|
|
103
|
+
const planFilePath = path.join(planDirPath, planEntry.name);
|
|
104
|
+
debugLog(`Found plan file: ${planFilePath}`);
|
|
105
|
+
return planFilePath;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch (err) {
|
|
109
|
+
debugLog(`Failed to read plan directory ${planDirPath}: ${err.message}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
} else if (entry.isFile() && entry.name.match(/^plan-\d+--.*\.md$/)) {
|
|
113
|
+
// Legacy: direct plan file in plans/archive directory
|
|
114
|
+
const filenameMatch = entry.name.match(/^plan-(\d+)--/);
|
|
115
|
+
if (filenameMatch && filenameMatch[1] === planId) {
|
|
116
|
+
const planFilePath = path.join(dir, entry.name);
|
|
117
|
+
debugLog(`Found legacy plan file: ${planFilePath}`);
|
|
118
|
+
return planFilePath;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch (err) {
|
|
123
|
+
errorLog(`Failed to read directory ${dir}: ${err.message}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Extract a field value from YAML frontmatter
|
|
132
|
+
* @param {string} frontmatter - YAML frontmatter text
|
|
133
|
+
* @param {string} fieldName - Field name to extract
|
|
134
|
+
* @param {string} defaultValue - Default value if field not found
|
|
135
|
+
* @returns {string} Field value or default
|
|
136
|
+
*/
|
|
137
|
+
function extractField(frontmatter, fieldName, defaultValue = 'manual') {
|
|
138
|
+
debugLog(`Extracting field: ${fieldName}`);
|
|
139
|
+
|
|
140
|
+
// Pattern to match field with various formatting:
|
|
141
|
+
// - field: value
|
|
142
|
+
// - field: "value"
|
|
143
|
+
// - field: 'value'
|
|
144
|
+
// - "field": value
|
|
145
|
+
// - field : value (extra spaces)
|
|
146
|
+
const regex = new RegExp(`^\\s*["']?${fieldName}["']?\\s*:\\s*(.+)$`, 'm');
|
|
147
|
+
const match = frontmatter.match(regex);
|
|
148
|
+
|
|
149
|
+
if (!match) {
|
|
150
|
+
debugLog(`Field ${fieldName} not found, using default: ${defaultValue}`);
|
|
151
|
+
return defaultValue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Clean up value: remove quotes and trim
|
|
155
|
+
let value = match[1].trim();
|
|
156
|
+
value = value.replace(/^['"]|['"]$/g, '');
|
|
157
|
+
|
|
158
|
+
debugLog(`Extracted ${fieldName}: ${value}`);
|
|
159
|
+
return value || defaultValue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Main function to get approval methods from plan file
|
|
164
|
+
*/
|
|
165
|
+
function main() {
|
|
166
|
+
// Get plan ID from command line
|
|
167
|
+
const planId = process.argv[2];
|
|
168
|
+
if (!planId) {
|
|
169
|
+
errorLog('Error: Plan ID is required');
|
|
170
|
+
console.error('Usage: node get-approval-methods.cjs <plan-id>');
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
debugLog(`Looking for plan ID: ${planId}`);
|
|
175
|
+
|
|
176
|
+
// Find task manager root
|
|
177
|
+
const taskManagerRoot = findTaskManagerRoot();
|
|
178
|
+
if (!taskManagerRoot) {
|
|
179
|
+
errorLog('No .ai/task-manager directory found in current directory or any parent directory.');
|
|
180
|
+
errorLog('Please ensure you are in a project with task manager initialized.');
|
|
181
|
+
errorLog(`Current working directory: ${process.cwd()}`);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Find plan file
|
|
186
|
+
const planFile = findPlanFile(taskManagerRoot, planId);
|
|
187
|
+
if (!planFile) {
|
|
188
|
+
errorLog(`Plan file for ID ${planId} not found in plans or archive directories.`);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
debugLog(`Reading plan file: ${planFile}`);
|
|
193
|
+
|
|
194
|
+
// Read plan file
|
|
195
|
+
let content;
|
|
196
|
+
try {
|
|
197
|
+
content = fs.readFileSync(planFile, 'utf8');
|
|
198
|
+
} catch (err) {
|
|
199
|
+
errorLog(`Failed to read plan file ${planFile}: ${err.message}`);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Extract YAML frontmatter
|
|
204
|
+
const frontmatterRegex = /^---\s*\r?\n([\s\S]*?)\r?\n---/;
|
|
205
|
+
const match = content.match(frontmatterRegex);
|
|
206
|
+
|
|
207
|
+
if (!match) {
|
|
208
|
+
errorLog('No YAML frontmatter found in plan file');
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const frontmatter = match[1];
|
|
213
|
+
debugLog(`Found frontmatter:\n${frontmatter}`);
|
|
214
|
+
|
|
215
|
+
// Extract approval method fields
|
|
216
|
+
const approvalMethodPlan = extractField(frontmatter, 'approval_method_plan');
|
|
217
|
+
const approvalMethodTasks = extractField(frontmatter, 'approval_method_tasks');
|
|
218
|
+
|
|
219
|
+
// Output JSON
|
|
220
|
+
const result = {
|
|
221
|
+
approval_method_plan: approvalMethodPlan,
|
|
222
|
+
approval_method_tasks: approvalMethodTasks
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
console.log(JSON.stringify(result, null, 2));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Run main function
|
|
229
|
+
main();
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
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
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Find the task manager root directory by traversing up from current working directory
|
|
31
|
+
* @returns {string|null} Path to task manager root or null if not found
|
|
32
|
+
*/
|
|
33
|
+
function findTaskManagerRoot() {
|
|
34
|
+
let currentPath = process.cwd();
|
|
35
|
+
const filesystemRoot = path.parse(currentPath).root;
|
|
36
|
+
|
|
37
|
+
debugLog(`Starting search for task manager root from: ${currentPath}`);
|
|
38
|
+
debugLog(`Filesystem root: ${filesystemRoot}`);
|
|
39
|
+
|
|
40
|
+
while (currentPath !== filesystemRoot) {
|
|
41
|
+
const taskManagerPlansPath = path.join(currentPath, '.ai', 'task-manager', 'plans');
|
|
42
|
+
debugLog(`Checking for task manager at: ${taskManagerPlansPath}`);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
if (fs.existsSync(taskManagerPlansPath)) {
|
|
46
|
+
const stats = fs.lstatSync(taskManagerPlansPath);
|
|
47
|
+
if (stats.isDirectory()) {
|
|
48
|
+
const taskManagerRoot = path.join(currentPath, '.ai', 'task-manager');
|
|
49
|
+
debugLog(`Found valid task manager root at: ${taskManagerRoot}`);
|
|
50
|
+
return taskManagerRoot;
|
|
51
|
+
} else {
|
|
52
|
+
debugLog(`Path exists but is not a directory: ${taskManagerPlansPath}`);
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
debugLog(`Task manager path does not exist: ${taskManagerPlansPath}`);
|
|
56
|
+
}
|
|
57
|
+
} catch (err) {
|
|
58
|
+
if (err.code === 'EPERM' || err.code === 'EACCES') {
|
|
59
|
+
const warningMsg = `Warning: Permission denied accessing ${taskManagerPlansPath}`;
|
|
60
|
+
console.warn(warningMsg);
|
|
61
|
+
debugLog(`Permission error: ${err.message}`);
|
|
62
|
+
} else {
|
|
63
|
+
debugLog(`Filesystem error checking ${taskManagerPlansPath}: ${err.message}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const parentPath = path.dirname(currentPath);
|
|
68
|
+
|
|
69
|
+
if (parentPath === currentPath) {
|
|
70
|
+
debugLog(`Reached filesystem root, stopping traversal`);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
currentPath = parentPath;
|
|
75
|
+
debugLog(`Moving up to parent directory: ${currentPath}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
debugLog(`Task manager root not found in any parent directory`);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Find plan file and directory for a given plan ID
|
|
84
|
+
* @param {string|number} planId - Plan ID to search for
|
|
85
|
+
* @returns {Object|null} Object with planFile and planDir, or null if not found
|
|
86
|
+
*/
|
|
87
|
+
function findPlanById(planId) {
|
|
88
|
+
const taskManagerRoot = findTaskManagerRoot();
|
|
89
|
+
|
|
90
|
+
if (!taskManagerRoot) {
|
|
91
|
+
errorLog('No .ai/task-manager directory found in current directory or any parent directory.');
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
debugLog(`Task manager root found: ${taskManagerRoot}`);
|
|
96
|
+
|
|
97
|
+
const plansDir = path.join(taskManagerRoot, 'plans');
|
|
98
|
+
const archiveDir = path.join(taskManagerRoot, 'archive');
|
|
99
|
+
|
|
100
|
+
debugLog(`Searching for plan ID ${planId} in: ${plansDir}, ${archiveDir}`);
|
|
101
|
+
|
|
102
|
+
// Search both plans and archive directories
|
|
103
|
+
for (const dir of [plansDir, archiveDir]) {
|
|
104
|
+
if (!fs.existsSync(dir)) {
|
|
105
|
+
debugLog(`Directory does not exist: ${dir}`);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
111
|
+
debugLog(`Found ${entries.length} entries in ${dir}`);
|
|
112
|
+
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
// Match directory pattern: [plan-id]--*
|
|
115
|
+
if (entry.isDirectory() && entry.name.match(new RegExp(`^${planId}--`))) {
|
|
116
|
+
const planDirPath = path.join(dir, entry.name);
|
|
117
|
+
debugLog(`Found matching plan directory: ${planDirPath}`);
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const planDirEntries = fs.readdirSync(planDirPath, { withFileTypes: true });
|
|
121
|
+
|
|
122
|
+
// Look for plan file: plan-[plan-id]--*.md
|
|
123
|
+
for (const planEntry of planDirEntries) {
|
|
124
|
+
if (planEntry.isFile() && planEntry.name.match(new RegExp(`^plan-${planId}--.*\\.md$`))) {
|
|
125
|
+
const planFilePath = path.join(planDirPath, planEntry.name);
|
|
126
|
+
debugLog(`Found plan file: ${planFilePath}`);
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
planFile: planFilePath,
|
|
130
|
+
planDir: planDirPath
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
debugLog(`No plan file found in directory: ${planDirPath}`);
|
|
136
|
+
} catch (err) {
|
|
137
|
+
errorLog(`Failed to read plan directory ${planDirPath}: ${err.message}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} catch (err) {
|
|
142
|
+
errorLog(`Failed to read directory ${dir}: ${err.message}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
debugLog(`Plan ID ${planId} not found in any directory`);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Count task files in a plan's tasks directory
|
|
152
|
+
* @param {string} planDir - Plan directory path
|
|
153
|
+
* @returns {number} Number of task files found
|
|
154
|
+
*/
|
|
155
|
+
function countTasks(planDir) {
|
|
156
|
+
const tasksDir = path.join(planDir, 'tasks');
|
|
157
|
+
|
|
158
|
+
if (!fs.existsSync(tasksDir)) {
|
|
159
|
+
debugLog(`Tasks directory does not exist: ${tasksDir}`);
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const stats = fs.lstatSync(tasksDir);
|
|
165
|
+
if (!stats.isDirectory()) {
|
|
166
|
+
debugLog(`Tasks path exists but is not a directory: ${tasksDir}`);
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const files = fs.readdirSync(tasksDir).filter(f => f.endsWith('.md'));
|
|
171
|
+
debugLog(`Found ${files.length} task files in ${tasksDir}`);
|
|
172
|
+
return files.length;
|
|
173
|
+
} catch (err) {
|
|
174
|
+
errorLog(`Failed to read tasks directory ${tasksDir}: ${err.message}`);
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Check if execution blueprint section exists in plan file
|
|
181
|
+
* @param {string} planFile - Path to plan file
|
|
182
|
+
* @returns {boolean} True if blueprint section exists, false otherwise
|
|
183
|
+
*/
|
|
184
|
+
function checkBlueprintExists(planFile) {
|
|
185
|
+
try {
|
|
186
|
+
const planContent = fs.readFileSync(planFile, 'utf8');
|
|
187
|
+
const blueprintExists = /^## Execution Blueprint/m.test(planContent);
|
|
188
|
+
debugLog(`Blueprint section ${blueprintExists ? 'found' : 'not found'} in ${planFile}`);
|
|
189
|
+
return blueprintExists;
|
|
190
|
+
} catch (err) {
|
|
191
|
+
errorLog(`Failed to read plan file ${planFile}: ${err.message}`);
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* List available plans for error messaging
|
|
198
|
+
* @returns {string[]} Array of plan directory names
|
|
199
|
+
*/
|
|
200
|
+
function listAvailablePlans() {
|
|
201
|
+
const taskManagerRoot = findTaskManagerRoot();
|
|
202
|
+
|
|
203
|
+
if (!taskManagerRoot) {
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const plansDir = path.join(taskManagerRoot, 'plans');
|
|
208
|
+
const archiveDir = path.join(taskManagerRoot, 'archive');
|
|
209
|
+
const plans = [];
|
|
210
|
+
|
|
211
|
+
for (const dir of [plansDir, archiveDir]) {
|
|
212
|
+
if (!fs.existsSync(dir)) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
218
|
+
for (const entry of entries) {
|
|
219
|
+
if (entry.isDirectory() && entry.name.match(/^\d+--/)) {
|
|
220
|
+
plans.push(entry.name);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} catch (err) {
|
|
224
|
+
// Silently continue
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return plans.sort((a, b) => {
|
|
229
|
+
const aId = parseInt(a.match(/^(\d+)--/)[1], 10);
|
|
230
|
+
const bId = parseInt(b.match(/^(\d+)--/)[1], 10);
|
|
231
|
+
return aId - bId;
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Validate plan blueprint and output JSON
|
|
237
|
+
* @param {string|number} planId - Plan ID to validate
|
|
238
|
+
*/
|
|
239
|
+
function validatePlanBlueprint(planId) {
|
|
240
|
+
if (!planId) {
|
|
241
|
+
errorLog('Plan ID is required');
|
|
242
|
+
errorLog('');
|
|
243
|
+
errorLog('Usage: node validate-plan-blueprint.cjs <plan-id>');
|
|
244
|
+
errorLog('');
|
|
245
|
+
errorLog('Example:');
|
|
246
|
+
errorLog(' node validate-plan-blueprint.cjs 47');
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
debugLog(`Validating plan blueprint for ID: ${planId}`);
|
|
251
|
+
|
|
252
|
+
const planInfo = findPlanById(planId);
|
|
253
|
+
|
|
254
|
+
if (!planInfo) {
|
|
255
|
+
errorLog(`Plan ID ${planId} not found`);
|
|
256
|
+
errorLog('');
|
|
257
|
+
|
|
258
|
+
const availablePlans = listAvailablePlans();
|
|
259
|
+
if (availablePlans.length > 0) {
|
|
260
|
+
errorLog('Available plans:');
|
|
261
|
+
availablePlans.forEach(plan => {
|
|
262
|
+
errorLog(` ${plan}`);
|
|
263
|
+
});
|
|
264
|
+
} else {
|
|
265
|
+
errorLog('No plans found in .ai/task-manager/{plans,archive}/');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
errorLog('');
|
|
269
|
+
errorLog('Please verify:');
|
|
270
|
+
errorLog(' 1. You are in the correct project directory');
|
|
271
|
+
errorLog(' 2. The plan exists in .ai/task-manager/plans/ or .ai/task-manager/archive/');
|
|
272
|
+
errorLog(' 3. The plan directory follows the naming pattern: [plan-id]--[name]');
|
|
273
|
+
errorLog(' 4. The plan file follows the naming pattern: plan-[plan-id]--[name].md');
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const { planFile, planDir } = planInfo;
|
|
278
|
+
const taskCount = countTasks(planDir);
|
|
279
|
+
const blueprintExists = checkBlueprintExists(planFile);
|
|
280
|
+
|
|
281
|
+
const result = {
|
|
282
|
+
planFile,
|
|
283
|
+
planDir,
|
|
284
|
+
taskCount,
|
|
285
|
+
blueprintExists
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
debugLog('Validation complete:', result);
|
|
289
|
+
console.log(JSON.stringify(result, null, 2));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Main execution
|
|
293
|
+
const planId = process.argv[2];
|
|
294
|
+
validatePlanBlueprint(planId);
|
|
@@ -45,22 +45,15 @@ Before proceeding with execution, validate that tasks exist and the execution bl
|
|
|
45
45
|
|
|
46
46
|
**Validation Steps:**
|
|
47
47
|
|
|
48
|
-
1. **Locate the plan document**:
|
|
49
48
|
```bash
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
TASK_COUNT=${#TASK_FILES[@]}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
3. **Check for execution blueprint section**:
|
|
62
|
-
```bash
|
|
63
|
-
BLUEPRINT_EXISTS=$(grep -q "^## Execution Blueprint" "$PLAN_FILE" && echo "yes" || echo "no")
|
|
49
|
+
# Validate plan exists and check for tasks/blueprint
|
|
50
|
+
VALIDATION=$(node .ai/task-manager/config/scripts/validate-plan-blueprint.cjs $1)
|
|
51
|
+
|
|
52
|
+
# Parse validation results
|
|
53
|
+
PLAN_FILE=$(echo "$VALIDATION" | grep -o '"planFile": "[^"]*"' | cut -d'"' -f4)
|
|
54
|
+
PLAN_DIR=$(echo "$VALIDATION" | grep -o '"planDir": "[^"]*"' | cut -d'"' -f4)
|
|
55
|
+
TASK_COUNT=$(echo "$VALIDATION" | grep -o '"taskCount": [0-9]*' | awk '{print $2}')
|
|
56
|
+
BLUEPRINT_EXISTS=$(echo "$VALIDATION" | grep -o '"blueprintExists": [a-z]*' | awk '{print $2}')
|
|
64
57
|
```
|
|
65
58
|
|
|
66
59
|
4. **Automatic task generation**:
|
|
@@ -154,12 +147,11 @@ Read and execute .ai/task-manager/config/hooks/POST_ERROR_DETECTION.md
|
|
|
154
147
|
First, extract both approval method fields from the plan document:
|
|
155
148
|
|
|
156
149
|
```bash
|
|
157
|
-
#
|
|
158
|
-
|
|
150
|
+
# Extract approval methods from plan metadata
|
|
151
|
+
APPROVAL_METHODS=$(node .ai/task-manager/config/scripts/get-approval-methods.cjs $1)
|
|
159
152
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
APPROVAL_METHOD_TASKS=$(sed -n '/^---$/,/^---$/p' "$PLAN_FILE" | grep '^approval_method_tasks:' | sed 's/approval_method_tasks: *//;s/"//g' | tr -d " '")
|
|
153
|
+
APPROVAL_METHOD_PLAN=$(echo "$APPROVAL_METHODS" | grep -o '"approval_method_plan": "[^"]*"' | cut -d'"' -f4)
|
|
154
|
+
APPROVAL_METHOD_TASKS=$(echo "$APPROVAL_METHODS" | grep -o '"approval_method_tasks": "[^"]*"' | cut -d'"' -f4)
|
|
163
155
|
|
|
164
156
|
# Defaults to "manual" if fields don't exist
|
|
165
157
|
APPROVAL_METHOD_PLAN=${APPROVAL_METHOD_PLAN:-manual}
|
|
@@ -303,11 +303,10 @@ Read and run the .ai/task-manager/config/hooks/POST_TASK_GENERATION_ALL.md
|
|
|
303
303
|
First, extract the approval_method from the plan document:
|
|
304
304
|
|
|
305
305
|
```bash
|
|
306
|
-
#
|
|
307
|
-
|
|
306
|
+
# Extract approval method from plan metadata
|
|
307
|
+
APPROVAL_METHODS=$(node .ai/task-manager/config/scripts/get-approval-methods.cjs $1)
|
|
308
308
|
|
|
309
|
-
|
|
310
|
-
APPROVAL_METHOD_TASKS=$(sed -n '/^---$/,/^---$/p' "$PLAN_FILE" | grep '^approval_method_tasks:' | sed 's/approval_method_tasks: *//;s/"//g' | tr -d " '")
|
|
309
|
+
APPROVAL_METHOD_TASKS=$(echo "$APPROVAL_METHODS" | grep -o '"approval_method_tasks": "[^"]*"' | cut -d'"' -f4)
|
|
311
310
|
|
|
312
311
|
# Default to "manual" if field doesn't exist (backward compatibility)
|
|
313
312
|
APPROVAL_METHOD_TASKS=${APPROVAL_METHOD_TASKS:-manual}
|
package/dist/logger.d.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple Logging Utility
|
|
3
|
-
*
|
|
4
|
-
* This file provides a simple logging interface for the CLI
|
|
5
|
-
* Handles different log levels and formatted output with optional color support
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Get chalk instance, initializing if necessary
|
|
9
|
-
*/
|
|
10
|
-
export declare function getChalk(): Promise<any | null>;
|
|
11
|
-
/**
|
|
12
|
-
* Debug mode flag - can be set externally
|
|
13
|
-
*/
|
|
14
|
-
export declare let isDebugMode: boolean;
|
|
15
|
-
/**
|
|
16
|
-
* Enable or disable debug mode
|
|
17
|
-
*/
|
|
18
|
-
export declare function setDebugMode(enabled: boolean): void;
|
|
19
|
-
/**
|
|
20
|
-
* Log an informational message
|
|
21
|
-
*/
|
|
22
|
-
export declare function info(message: string): Promise<void>;
|
|
23
|
-
/**
|
|
24
|
-
* Log a success message
|
|
25
|
-
*/
|
|
26
|
-
export declare function success(message: string): Promise<void>;
|
|
27
|
-
/**
|
|
28
|
-
* Log an error message
|
|
29
|
-
*/
|
|
30
|
-
export declare function error(message: string): Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
* Log a warning message
|
|
33
|
-
*/
|
|
34
|
-
export declare function warning(message: string): Promise<void>;
|
|
35
|
-
/**
|
|
36
|
-
* Log a debug message (only shown in debug mode)
|
|
37
|
-
*/
|
|
38
|
-
export declare function debug(message: string): Promise<void>;
|
|
39
|
-
/**
|
|
40
|
-
* Synchronous versions for cases where async is not suitable
|
|
41
|
-
* These will only use colors if chalk was previously initialized
|
|
42
|
-
*/
|
|
43
|
-
export declare const sync: {
|
|
44
|
-
/**
|
|
45
|
-
* Log an informational message (sync)
|
|
46
|
-
*/
|
|
47
|
-
info(message: string): void;
|
|
48
|
-
/**
|
|
49
|
-
* Log a success message (sync)
|
|
50
|
-
*/
|
|
51
|
-
success(message: string): void;
|
|
52
|
-
/**
|
|
53
|
-
* Log an error message (sync)
|
|
54
|
-
*/
|
|
55
|
-
error(message: string): void;
|
|
56
|
-
/**
|
|
57
|
-
* Log a warning message (sync)
|
|
58
|
-
*/
|
|
59
|
-
warning(message: string): void;
|
|
60
|
-
/**
|
|
61
|
-
* Log a debug message (sync, only shown in debug mode)
|
|
62
|
-
*/
|
|
63
|
-
debug(message: string): void;
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* Initialize the logger - call this early in your application
|
|
67
|
-
* This pre-loads chalk to avoid delays on first use
|
|
68
|
-
*/
|
|
69
|
-
export declare function initLogger(): Promise<void>;
|
|
70
|
-
//# sourceMappingURL=logger.d.ts.map
|
package/dist/logger.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH;;GAEG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAGpD;AAED;;GAEG;AACH,eAAO,IAAI,WAAW,SAAQ,CAAC;AAE/B;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEnD;AAED;;GAEG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIzD;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5D;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI1D;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5D;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM1D;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI;IACf;;OAEG;kBACW,MAAM,GAAG,IAAI;IAK3B;;OAEG;qBACc,MAAM,GAAG,IAAI;IAK9B;;OAEG;mBACY,MAAM,GAAG,IAAI;IAK5B;;OAEG;qBACc,MAAM,GAAG,IAAI;IAK9B;;OAEG;mBACY,MAAM,GAAG,IAAI;CAM7B,CAAC;AAEF;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAEhD"}
|