@e0ipso/ai-task-manager 1.18.5 → 1.18.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e0ipso/ai-task-manager",
3
- "version": "1.18.5",
3
+ "version": "1.18.7",
4
4
  "description": "Task management for AI coding assistants",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -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);
@@ -2,7 +2,8 @@
2
2
  id: [PLAN-ID]
3
3
  summary: "[Brief one-line description of what this plan accomplishes]"
4
4
  created: [YYYY-MM-DD]
5
- approval_method: [auto|manual] # Optional: Workflow approval mode (auto=automated, manual=requires review)
5
+ approval_method_plan: [auto|manual] # Workflow approval for plan review (default: manual)
6
+ approval_method_tasks: [auto|manual] # Workflow approval for task generation review (default: manual)
6
7
  ---
7
8
 
8
9
  # Plan: [Descriptive Plan Title]
@@ -88,14 +88,18 @@ Structure your response as follows:
88
88
  - If context is insufficient: List specific clarifying questions
89
89
  - If context is sufficient: Provide the comprehensive plan using the structure above. Use the information in @TASK_MANAGER.md for the directory structure and additional information about plans.
90
90
 
91
- **Output Behavior:**
91
+ **Output Behavior: CRITICAL - Structured Output for Command Coordination**
92
92
 
93
- Be extremely concise but helpful:
94
- - Tell the user that you are done
95
- - Instruct them to review the plan document with the file path
96
- - Example output: "Plan created. Please review: `.ai/task-manager/plans/40--plan-name/plan-40--plan-name.md`"
93
+ Always end your output with a standardized summary in this exact format:
97
94
 
98
- **Note:** When this command is invoked by the full-workflow command, the full-workflow will modify the plan's `approval_method` field after creation to enable automated execution.
95
+ ```
96
+ ---
97
+ Plan Summary:
98
+ - Plan ID: [numeric-id]
99
+ - Plan File: [full-path-to-plan-file]
100
+ ```
101
+
102
+ This structured output enables automated workflow coordination and must be included even when running standalone.
99
103
 
100
104
  ###### Plan Template
101
105
 
@@ -114,11 +118,12 @@ Example:
114
118
  id: 1
115
119
  summary: "Implement a comprehensive CI/CD pipeline using GitHub Actions for automated linting, testing, semantic versioning, and NPM publishing"
116
120
  created: 2025-09-01
117
- approval_method: "manual"
121
+ approval_method_plan: "manual"
122
+ approval_method_tasks: "manual"
118
123
  ---
119
124
  ```
120
125
 
121
- **Important**: Always set `approval_method` to "manual" when creating a plan. The full-workflow command will modify this field to "auto" after creation if running in automated mode.
126
+ **Important**: Always set both `approval_method_plan` and `approval_method_tasks` to "manual" when creating a plan. The full-workflow command will modify these fields to "auto" after creation if running in automated mode.
122
127
 
123
128
  The schema for this frontmatter is:
124
129
  ```json
@@ -139,10 +144,15 @@ The schema for this frontmatter is:
139
144
  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
140
145
  "description": "Creation date in YYYY-MM-DD format"
141
146
  },
142
- "approval_method": {
147
+ "approval_method_plan": {
148
+ "type": "string",
149
+ "enum": ["auto", "manual"],
150
+ "description": "Workflow approval mode for plan review: auto for automated workflows, manual for standalone execution"
151
+ },
152
+ "approval_method_tasks": {
143
153
  "type": "string",
144
154
  "enum": ["auto", "manual"],
145
- "description": "Workflow approval mode: auto for automated workflows, manual for standalone execution"
155
+ "description": "Workflow approval mode for task generation review: auto when tasks auto-generated in workflow, manual for standalone execution"
146
156
  }
147
157
  },
148
158
  "additionalProperties": false
@@ -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
- PLAN_FILE=$(find .ai/task-manager/{plans,archive} -name "plan-[0-9][0-9]*--*.md" -type f -exec grep -l "^id: \?$1$" {} \;)
51
- PLAN_DIR=$(dirname "$PLAN_FILE")
52
- ```
53
-
54
- 2. **Check for task files**:
55
- ```bash
56
- setopt null_glob 2>/dev/null || true
57
- TASK_FILES=(${PLAN_DIR}/tasks/*.md)
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**:
@@ -71,7 +64,12 @@ If either `$TASK_COUNT` is 0 or `$BLUEPRINT_EXISTS` is "no":
71
64
  ```
72
65
  /tasks:generate-tasks $1
73
66
  ```
74
- - **CRITICAL**: After task generation completes successfully, you MUST immediately proceed with blueprint execution without waiting for user input. The workflow should continue seamlessly.
67
+ - **NEW STEP**: Immediately after task generation succeeds, set the approval_method_tasks field to auto:
68
+ ```bash
69
+ node .ai/task-manager/config/scripts/set-approval-method.cjs "$PLAN_FILE" auto tasks
70
+ ```
71
+ - This signals that tasks were auto-generated in workflow context and execution should continue without pause.
72
+ - **CRITICAL**: After setting the field, you MUST immediately proceed with blueprint execution without waiting for user input. The workflow should continue seamlessly.
75
73
  - If generation fails: Halt execution with clear error message:
76
74
  ```
77
75
  ❌ Error: Automatic task generation failed.
@@ -146,33 +144,56 @@ Read and execute .ai/task-manager/config/hooks/POST_ERROR_DETECTION.md
146
144
 
147
145
  **Extract approval method from plan metadata:**
148
146
 
149
- First, extract the approval_method from the plan document:
147
+ First, extract both approval method fields from the plan document:
150
148
 
151
149
  ```bash
152
- # Find plan file by ID
153
- PLAN_FILE=$(find .ai/task-manager/{plans,archive} -name "plan-$1--*.md" -type f -exec grep -l "^id: \?$1$" {} \;)
150
+ # Extract approval methods from plan metadata
151
+ APPROVAL_METHODS=$(node .ai/task-manager/config/scripts/get-approval-methods.cjs $1)
154
152
 
155
- # Extract approval_method from YAML frontmatter
156
- APPROVAL_METHOD=$(sed -n '/^---$/,/^---$/p' "$PLAN_FILE" | grep '^approval_method:' | sed 's/approval_method: *//;s/"//g;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)
157
155
 
158
- # Default to "manual" if field doesn't exist (backward compatibility)
159
- APPROVAL_METHOD=${APPROVAL_METHOD:-manual}
156
+ # Defaults to "manual" if fields don't exist
157
+ APPROVAL_METHOD_PLAN=${APPROVAL_METHOD_PLAN:-manual}
158
+ APPROVAL_METHOD_TASKS=${APPROVAL_METHOD_TASKS:-manual}
160
159
  ```
161
160
 
162
- Then adjust output based on the extracted approval method:
161
+ Then adjust output based on the extracted approval methods:
163
162
 
164
- - **If `APPROVAL_METHOD="auto"` (automated workflow mode)**:
165
- - Provide minimal progress updates at phase boundaries
166
- - Do NOT instruct user to review implementation details
163
+ - **If `APPROVAL_METHOD_PLAN="auto"` (automated workflow mode)**:
164
+ - During task auto-generation phase: Provide minimal progress updates
165
+ - Do NOT instruct user to review the plan or tasks being generated
167
166
  - Do NOT add any prompts that would pause execution
167
+
168
+ - **If `APPROVAL_METHOD_TASKS="auto"` (tasks auto-generated in workflow)**:
169
+ - During task execution phase: Provide minimal progress updates at phase boundaries
170
+ - Do NOT instruct user to review implementation details
168
171
  - Example output: "Phase 1/3 completed. Proceeding to Phase 2."
169
172
 
170
- - **If `APPROVAL_METHOD="manual"` or empty (standalone mode)**:
173
+ - **If `APPROVAL_METHOD_PLAN="manual"` or `APPROVAL_METHOD_TASKS="manual"` (standalone mode)**:
171
174
  - Provide detailed execution summary with phase results
172
175
  - List completed tasks and any noteworthy events
173
176
  - Instruct user to review the execution summary in the plan document
174
177
  - Example output: "Execution completed. Review summary: `.ai/task-manager/archive/[plan]/plan-[id].md`"
175
178
 
179
+ **Note**: This command respects both approval method fields:
180
+ - `approval_method_plan`: Used during auto-generation to determine if we're in automated workflow
181
+ - `approval_method_tasks`: Used during execution to determine output verbosity
182
+
183
+ **CRITICAL - Structured Output for Command Coordination:**
184
+
185
+ Always end your output with a standardized summary in this exact format:
186
+
187
+ ```
188
+ ---
189
+ Execution Summary:
190
+ - Plan ID: [numeric-id]
191
+ - Status: Archived
192
+ - Location: .ai/task-manager/archive/[plan-id]--[plan-name]/
193
+ ```
194
+
195
+ This structured output enables automated workflow coordination and must be included even when running standalone.
196
+
176
197
  ## Optimization Guidelines
177
198
 
178
199
  - **Maximize parallelism**: Always run all available tasks in a phase simultaneously
@@ -303,26 +303,39 @@ 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
- # Find plan file by ID
307
- PLAN_FILE=$(find .ai/task-manager/{plans,archive} -name "plan-$1--*.md" -type f -exec grep -l "^id: \?$1$" {} \;)
306
+ # Extract approval method from plan metadata
307
+ APPROVAL_METHODS=$(node .ai/task-manager/config/scripts/get-approval-methods.cjs $1)
308
308
 
309
- # Extract approval_method from YAML frontmatter
310
- APPROVAL_METHOD=$(sed -n '/^---$/,/^---$/p' "$PLAN_FILE" | grep '^approval_method:' | sed 's/approval_method: *//;s/"//g;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
- APPROVAL_METHOD=${APPROVAL_METHOD:-manual}
312
+ APPROVAL_METHOD_TASKS=${APPROVAL_METHOD_TASKS:-manual}
314
313
  ```
315
314
 
316
315
  Then adjust output based on the extracted approval method:
317
316
 
318
- - **If `APPROVAL_METHOD="auto"` (automated workflow mode)**:
317
+ - **If `APPROVAL_METHOD_TASKS="auto"` (automated workflow mode)**:
319
318
  - Simply confirm task generation with task count
320
319
  - Do NOT instruct user to review the tasks
321
320
  - Do NOT add any prompts that would pause execution
322
321
  - Example output: "Tasks generated for plan [id]: [count] tasks created"
323
322
 
324
- - **If `APPROVAL_METHOD="manual"` or empty (standalone mode)**:
323
+ - **If `APPROVAL_METHOD_TASKS="manual"` or empty (standalone mode)**:
325
324
  - Be concise but helpful
326
325
  - Tell the user that you are done
327
326
  - Instruct them to review the tasks with file paths
328
327
  - Example output: "Task generation complete. Review tasks in: `.ai/task-manager/plans/[plan-id]--[name]/tasks/`"
328
+
329
+ **CRITICAL - Structured Output for Command Coordination:**
330
+
331
+ Always end your output with a standardized summary in this exact format:
332
+
333
+ ```
334
+ ---
335
+ Task Generation Summary:
336
+ - Plan ID: [numeric-id]
337
+ - Tasks: [count]
338
+ - Status: Ready for execution
339
+ ```
340
+
341
+ This structured output enables automated workflow coordination and must be included even when running standalone.
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
-
6
- /**
7
- * Update or add approval_method field in a plan file's YAML frontmatter
8
- * @param {string} filePath - Path to the plan file
9
- * @param {string} approvalMethod - Approval method value ('auto' or 'manual')
10
- * @returns {boolean} True if successful, false otherwise
11
- */
12
- function setApprovalMethod(filePath, approvalMethod) {
13
- // Validate inputs
14
- if (!filePath) {
15
- throw new Error('File path is required');
16
- }
17
-
18
- if (!approvalMethod || !['auto', 'manual'].includes(approvalMethod)) {
19
- throw new Error('Approval method must be "auto" or "manual"');
20
- }
21
-
22
- // Check file exists
23
- if (!fs.existsSync(filePath)) {
24
- throw new Error(`File not found: ${filePath}`);
25
- }
26
-
27
- // Read file content
28
- const content = fs.readFileSync(filePath, 'utf8');
29
-
30
- // Parse frontmatter - handle both empty and non-empty frontmatter
31
- const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n([\s\S]*))?$/;
32
- const match = content.match(frontmatterRegex);
33
-
34
- if (!match) {
35
- throw new Error('No frontmatter found in file');
36
- }
37
-
38
- const frontmatterContent = match[1] || '';
39
- const bodyContent = match[2] || '';
40
- const frontmatterLines = frontmatterContent ? frontmatterContent.split('\n') : [];
41
-
42
- // Update or add approval_method field
43
- let approvalMethodFound = false;
44
- const updatedFrontmatter = frontmatterLines.map(line => {
45
- const trimmed = line.trim();
46
- if (trimmed.startsWith('approval_method:')) {
47
- approvalMethodFound = true;
48
- return `approval_method: ${approvalMethod}`;
49
- }
50
- return line;
51
- });
52
-
53
- // Add approval_method if not found
54
- if (!approvalMethodFound) {
55
- updatedFrontmatter.push(`approval_method: ${approvalMethod}`);
56
- }
57
-
58
- // Reconstruct file
59
- const updated = '---\n' + updatedFrontmatter.join('\n') + '\n---\n' + bodyContent;
60
-
61
- // Write back to file
62
- fs.writeFileSync(filePath, updated, 'utf8');
63
-
64
- return true;
65
- }
66
-
67
- // Main execution with error handling
68
- try {
69
- const args = process.argv.slice(2);
70
-
71
- if (args.length < 2) {
72
- console.error('Usage: set-approval-method.cjs <file-path> <approval-method>');
73
- console.error(' file-path: Path to the plan file');
74
- console.error(' approval-method: "auto" or "manual"');
75
- process.exit(1);
76
- }
77
-
78
- const [filePath, approvalMethod] = args;
79
-
80
- // Resolve relative paths
81
- const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(process.cwd(), filePath);
82
-
83
- setApprovalMethod(resolvedPath, approvalMethod);
84
-
85
- console.log(`✓ Successfully set approval_method to "${approvalMethod}" in ${path.basename(resolvedPath)}`);
86
- process.exit(0);
87
- } catch (error) {
88
- console.error(`✗ Error: ${error.message}`);
89
- process.exit(1);
90
- }
@@ -1,190 +0,0 @@
1
- ---
2
- argument-hint: [user-prompt]
3
- description: Execute the full workflow from plan creation to blueprint execution
4
- ---
5
- # Full Workflow Execution
6
-
7
- ## Assistant Configuration
8
-
9
- Before proceeding with this command, you MUST load and respect the assistant's configuration:
10
-
11
- **Run the following scripts:**
12
- ```bash
13
- ASSISTANT=$(node .ai/task-manager/config/scripts/detect-assistant.cjs)
14
- node .ai/task-manager/config/scripts/read-assistant-config.cjs "$ASSISTANT"
15
- ```
16
-
17
- The output above contains your global and project-level configuration rules. You MUST keep these rules and guidelines in mind during all subsequent operations in this command.
18
-
19
- ---
20
-
21
- You are a workflow orchestration assistant. Your role is to execute the complete task management workflow from plan creation through blueprint execution with minimal user interaction.
22
-
23
- ## Instructions
24
-
25
- The user input is:
26
-
27
- <user-input>
28
- $ARGUMENTS
29
- </user-input>
30
-
31
- If no user input is provided, stop immediately and show an error message to the user.
32
-
33
- ### Workflow Execution Process
34
-
35
- Use your internal Todo task tool to track the workflow execution:
36
-
37
- - [ ] Execute /tasks:create-plan
38
- - [ ] Extract plan ID
39
- - [ ] Execute /tasks:generate-tasks
40
- - [ ] Execute /tasks:execute-blueprint
41
- - [ ] Generate execution summary
42
-
43
- #### Step 1: Determine Next Plan ID
44
-
45
- Before creating the plan, determine what the next plan ID will be and store it persistently:
46
-
47
- ```bash
48
- PLAN_ID=$(node .ai/task-manager/config/scripts/get-next-plan-id.cjs)
49
- echo "$PLAN_ID" > /tmp/full-workflow-plan-id-$$.txt
50
- echo "Next plan ID: $PLAN_ID"
51
- ```
52
-
53
- This stores the plan ID in a temporary file that persists across all workflow steps.
54
-
55
- #### Step 2: Execute Plan Creation
56
-
57
- Use the SlashCommand tool to execute plan creation with the user's prompt:
58
-
59
- ```
60
- /tasks:create-plan $ARGUMENTS
61
- ```
62
-
63
- **Important**: The plan creation command may ask clarification questions. Wait for user responses before continuing. This is expected behavior and maintains quality control.
64
-
65
- After plan creation completes, retrieve the plan ID and provide a progress update:
66
-
67
- ```bash
68
- PLAN_ID=$(cat /tmp/full-workflow-plan-id-$$.txt)
69
- echo "Step 1/4: Plan created (ID: $PLAN_ID)"
70
- ```
71
-
72
- **CRITICAL**: Do not wait for user approval or review of the plan. In full-workflow mode, plan validation is automated (Step 3 performs file existence checking only). Proceed immediately to Step 3 without waiting for user input.
73
-
74
- #### Step 3: Validate Plan Creation and Set Approval Method
75
-
76
- Verify the plan was created successfully and set it to automated workflow mode:
77
-
78
- ```bash
79
- # Retrieve the plan ID from temp file
80
- PLAN_ID=$(cat /tmp/full-workflow-plan-id-$$.txt)
81
-
82
- # Find the created plan file
83
- PLAN_FILE=$(find .ai/task-manager/plans -name "plan-[0-9][0-9]*--*.md" -type f -exec grep -l "^id: \?${PLAN_ID}$" {} \;)
84
-
85
- # Verify plan exists
86
- if [ -z "$PLAN_FILE" ]; then
87
- echo "❌ Error: Plan creation failed. Expected plan with ID ${PLAN_ID} not found."
88
- exit 1
89
- fi
90
-
91
- # Set approval_method to auto for automated workflow execution
92
- # This ensures generate-tasks and execute-blueprint run without interruption
93
- node .ai/task-manager/config/scripts/set-approval-method.cjs "$PLAN_FILE" auto
94
- ```
95
-
96
- **Note**: Setting `approval_method: auto` in the plan metadata signals to subordinate commands (generate-tasks, execute-blueprint) that they are running in automated workflow mode and should suppress interactive prompts for plan review. This metadata persists in the plan document and is reliably read by subsequent commands, eliminating dependency on environment variables.
97
-
98
- #### Step 4: Execute Task Generation
99
-
100
- Retrieve the plan ID and use the SlashCommand tool to generate tasks:
101
-
102
- ```bash
103
- PLAN_ID=$(cat /tmp/full-workflow-plan-id-$$.txt)
104
- echo "Generating tasks for plan $PLAN_ID"
105
- ```
106
-
107
- Now use the SlashCommand tool with the plan ID from above:
108
-
109
- ```
110
- /tasks:generate-tasks [plan-id-from-above]
111
- ```
112
-
113
- After task generation completes, provide minimal progress update referencing the plan ID.
114
-
115
- #### Step 5: Execute Blueprint
116
-
117
- Retrieve the plan ID and use the SlashCommand tool to execute the blueprint:
118
-
119
- ```bash
120
- PLAN_ID=$(cat /tmp/full-workflow-plan-id-$$.txt)
121
- echo "Executing blueprint for plan $PLAN_ID"
122
- ```
123
-
124
- Now use the SlashCommand tool with the plan ID from above:
125
-
126
- ```
127
- /tasks:execute-blueprint [plan-id-from-above]
128
- ```
129
-
130
- After blueprint execution completes, provide minimal progress update:
131
- "Step 3/4: Blueprint execution completed"
132
-
133
- Note: The execute-blueprint command automatically archives the plan upon successful completion.
134
-
135
- #### Step 6: Generate Execution Summary
136
-
137
- After all steps complete successfully, retrieve the plan details and generate a summary:
138
-
139
- ```bash
140
- PLAN_ID=$(cat /tmp/full-workflow-plan-id-$$.txt)
141
- PLAN_DIR=$(find .ai/task-manager/archive -type d -name "${PLAN_ID}--*" 2>/dev/null | head -n 1)
142
- PLAN_NAME=$(basename "$PLAN_DIR")
143
-
144
- echo "✅ Full workflow completed successfully!"
145
- echo ""
146
- echo "Plan: $PLAN_NAME"
147
- echo "Location: .ai/task-manager/archive/$PLAN_NAME/"
148
- echo ""
149
- echo "Status: Archived and ready for review"
150
- echo ""
151
- echo "📋 Next Steps:"
152
- echo "- Review the implementation in the archived plan"
153
- echo "- Check the execution summary in the plan document"
154
- echo "- Verify all validation gates passed"
155
- echo ""
156
- echo "Plan document: .ai/task-manager/archive/$PLAN_NAME/plan-$PLAN_NAME.md"
157
-
158
- # Clean up temp file
159
- rm -f /tmp/full-workflow-plan-id-$$.txt
160
- ```
161
-
162
- ### Error Handling
163
-
164
- If any step fails:
165
- 1. Halt execution immediately
166
- 2. Report clear error message indicating which step failed
167
- 3. Preserve all created artifacts (plan, tasks) for manual review
168
- 4. Read the plan ID from temp file if needed: `cat /tmp/full-workflow-plan-id-$$.txt`
169
- 5. Provide guidance for manual continuation:
170
- - If plan creation failed: Review error and retry
171
- - If task generation failed: Run `/tasks:generate-tasks [plan-id]` manually after reviewing plan
172
- - If blueprint execution failed: Review tasks and run `/tasks:execute-blueprint [plan-id]` manually
173
- 6. Clean up temp file: `rm -f /tmp/full-workflow-plan-id-$$.txt`
174
-
175
- ### Output Requirements
176
-
177
- **During Execution:**
178
- - Minimal progress updates at each major step
179
- - Clear indication of current step (1/4, 2/4, etc.)
180
-
181
- **After Completion:**
182
- - Comprehensive summary with plan location
183
- - Status confirmation (Archived)
184
- - Next steps for user review
185
- - Direct link to plan document
186
-
187
- **On Error:**
188
- - Clear error message
189
- - Indication of which step failed
190
- - Manual recovery instructions