@e0ipso/ai-task-manager 1.26.10 → 1.27.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/hooks/POST_EXECUTION.md +19 -0
- package/templates/ai-task-manager/config/hooks/POST_TASK_GENERATION_ALL.md +22 -143
- package/templates/ai-task-manager/config/hooks/PRE_TASK_ASSIGNMENT.md +6 -32
- package/templates/ai-task-manager/config/scripts/check-task-dependencies.cjs +18 -47
- package/templates/ai-task-manager/config/scripts/create-feature-branch.cjs +23 -51
- package/templates/ai-task-manager/config/scripts/extract-task-skills.cjs +84 -0
- package/templates/assistant/commands/tasks/create-plan.md +1 -1
- package/templates/assistant/commands/tasks/execute-blueprint.md +9 -1
- package/templates/assistant/commands/tasks/execute-task.md +1 -1
- package/templates/assistant/commands/tasks/full-workflow.md +8 -1
- package/templates/assistant/commands/tasks/generate-tasks.md +1 -1
- package/templates/assistant/commands/tasks/refine-plan.md +1 -1
package/package.json
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# POST_EXECUTION Hook
|
|
2
|
+
|
|
3
|
+
## Validation Gates
|
|
4
|
+
|
|
5
|
+
Before marking the blueprint as complete, verify:
|
|
6
|
+
|
|
7
|
+
- [ ] All linting rules must pass without errors. If no linter is configured, skip this step
|
|
8
|
+
- [ ] All tests must pass successfully. If no test suite is configured, skip this step
|
|
9
|
+
- [ ] Verify all tasks in the plan have `status: "completed"` in their frontmatter
|
|
10
|
+
- [ ] Verify that the AGENTS.md documentation or related documentes are still correct after this plan execution
|
|
11
|
+
|
|
12
|
+
## Failure Behavior
|
|
13
|
+
|
|
14
|
+
If any validation gate fails:
|
|
15
|
+
|
|
16
|
+
- **Halt execution immediately** - do not proceed to summary generation or archival
|
|
17
|
+
- **Leave plan in `plans/` directory** for debugging and correction
|
|
18
|
+
- **Document the failure** in the plan file with details about which gate failed
|
|
19
|
+
- **Provide actionable next steps** for resolving the failure
|
|
@@ -1,162 +1,41 @@
|
|
|
1
1
|
# POST_TASK_GENERATION_ALL Hook
|
|
2
2
|
|
|
3
|
-
After all tasks have been generated
|
|
3
|
+
After all tasks have been generated, perform these two steps:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- [ ] Update plan document with Blueprint information
|
|
5
|
+
## 1. Review Task Complexity
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
For each generated task, do a quick sanity check:
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
- **Too complex?** If a task spans 3+ technologies or requires 3+ skills, split it.
|
|
10
|
+
- **Too vague?** If acceptance criteria are unclear, sharpen them.
|
|
11
|
+
- **Too trivial?** If two tasks could be one without adding complexity, merge them.
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|-----------|-----|-----|-----|-----|------|
|
|
14
|
-
| **Technical** | Basic ops | Single tech | 2-3 techs | Multiple complex | Cutting-edge |
|
|
15
|
-
| **Decision** | No decisions | 1-2 minor | Trade-offs | Interdependent | Novel solutions |
|
|
16
|
-
| **Integration** | Single file | 2-3 files | Multi-module | Many systems | 15+ services |
|
|
17
|
-
| **Scope** | Atomic action | Small feature | Complete feature | Major feature | Entire subsystem |
|
|
18
|
-
| **Uncertainty** | Crystal clear | Minor ambiguity | Some clarification | Research required | Experimental |
|
|
13
|
+
Target: every task should be completable with 1-2 skills and have clear acceptance criteria.
|
|
19
14
|
|
|
20
|
-
|
|
15
|
+
## 2. Update Plan with Blueprint
|
|
21
16
|
|
|
22
|
-
|
|
17
|
+
After finalizing tasks, append to the plan document:
|
|
23
18
|
|
|
24
|
-
|
|
25
|
-
- Composite ≥6: Consider decomposition
|
|
26
|
-
- Any dimension ≥8: Mandatory decomposition
|
|
27
|
-
- Multiple dimensions ≥6: High priority
|
|
19
|
+
### Dependency Diagram
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
| Driver | Pattern | Strategy |
|
|
31
|
-
|--------|---------|----------|
|
|
32
|
-
| Technical | Technology Layering | Split by tech boundaries |
|
|
33
|
-
| Decision | Decision-Implementation | Separate analysis from execution |
|
|
34
|
-
| Integration | Integration Isolation | Core feature + integrations |
|
|
35
|
-
| Scope | Functional | Split by user workflows |
|
|
36
|
-
| Uncertainty | Research-Implementation | Prototype then implement |
|
|
37
|
-
|
|
38
|
-
### AIDVR Process
|
|
39
|
-
1. **Assess**: Confirm need (score >5)
|
|
40
|
-
2. **Identify**: Find natural breakpoints
|
|
41
|
-
3. **Decompose**: Apply pattern
|
|
42
|
-
4. **Validate**: Check criteria
|
|
43
|
-
5. **Reconstruct**: Update dependencies
|
|
44
|
-
|
|
45
|
-
### Safety Controls
|
|
46
|
-
|
|
47
|
-
**Limits:**
|
|
48
|
-
- Max 3 decomposition rounds per task
|
|
49
|
-
- No decomposition if score ≤3
|
|
50
|
-
- Min 2-hour work per subtask
|
|
51
|
-
- Stop if complexity not decreasing
|
|
52
|
-
|
|
53
|
-
**Stop Conditions:**
|
|
54
|
-
1. Atomic boundary reached
|
|
55
|
-
2. <1 skill per subtask
|
|
56
|
-
3. Overhead > benefit
|
|
57
|
-
4. Resource fragmentation
|
|
58
|
-
5. <2 hour granularity
|
|
59
|
-
6. 3 iterations reached
|
|
60
|
-
7. Score ≤3
|
|
61
|
-
8. No complexity reduction
|
|
62
|
-
|
|
63
|
-
### Validation Checklist
|
|
64
|
-
|
|
65
|
-
**Per Subtask:**
|
|
66
|
-
- [ ] Complexity ≤5 (target ≤4)
|
|
67
|
-
- [ ] Skills ≤2
|
|
68
|
-
- [ ] Clear acceptance criteria
|
|
69
|
-
- [ ] Dependencies acyclic
|
|
70
|
-
- [ ] Score ≥2 (min viability)
|
|
71
|
-
|
|
72
|
-
**Decomposition Quality:**
|
|
73
|
-
- [ ] Coverage: All requirements included
|
|
74
|
-
- [ ] Coherence: Single purpose per task
|
|
75
|
-
- [ ] Consistency: Lower scores than parent
|
|
76
|
-
- [ ] Coordination: Integration plan exists
|
|
77
|
-
|
|
78
|
-
### Error Handling
|
|
79
|
-
|
|
80
|
-
| Issue | Detection | Resolution |
|
|
81
|
-
|-------|-----------|------------|
|
|
82
|
-
| Infinite loop | No reduction after 2 rounds | Stop, mark needs-clarification |
|
|
83
|
-
| Circular dependency | Task reaches itself | Break shortest cycle |
|
|
84
|
-
| Over-decomposition | Score <2 or <2hrs | Merge with sibling |
|
|
85
|
-
| Orphaned task | Missing dependencies | Create or remove dependency |
|
|
86
|
-
| Scope creep | Subtasks > original | Remove excess scope |
|
|
87
|
-
| Skill conflicts | >2 skills needed | Decompose by skill boundary |
|
|
88
|
-
| High complexity | >7 after max rounds | Escalate with documentation |
|
|
89
|
-
|
|
90
|
-
### Documentation Format
|
|
91
|
-
|
|
92
|
-
In `complexity_notes`:
|
|
93
|
-
```
|
|
94
|
-
Original: 8.2 → Round 1 → [4.1, 3.8, 4.5] → PASSED
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**Quality Gates Before Proceeding:**
|
|
98
|
-
- All tasks ≤5 complexity or escalated
|
|
99
|
-
- No unresolved errors
|
|
100
|
-
- Iterations documented
|
|
101
|
-
- Validation complete
|
|
102
|
-
|
|
103
|
-
## Update plan document with Blueprint information
|
|
104
|
-
|
|
105
|
-
After creating all tasks with their dependencies, update the original plan document with two critical sections: a task dependency visualization and a phase-based execution blueprint.
|
|
106
|
-
|
|
107
|
-
### Section 1: Dependency Visualization
|
|
108
|
-
|
|
109
|
-
If any tasks have dependencies, create a Mermaid diagram showing the dependency graph:
|
|
21
|
+
If tasks have dependencies, add a Mermaid graph:
|
|
110
22
|
|
|
111
23
|
```mermaid
|
|
112
24
|
graph TD
|
|
113
|
-
001[Task 001:
|
|
114
|
-
001 --> 003[Task 003: Data Models]
|
|
115
|
-
002 --> 004[Task 004: Frontend Integration]
|
|
116
|
-
003 --> 004
|
|
25
|
+
001[Task 001: Description] --> 002[Task 002: Description]
|
|
117
26
|
```
|
|
118
27
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
### Section 2: Phase-Based Execution Blueprint
|
|
122
|
-
|
|
123
|
-
#### Core Concept
|
|
124
|
-
The execution blueprint organizes tasks into sequential phases where:
|
|
125
|
-
- **Within a phase**: All tasks execute in parallel
|
|
126
|
-
- **Between phases**: Execution is strictly sequential
|
|
127
|
-
- **Phase progression**: Requires all tasks in current phase to complete AND validation gates to pass
|
|
128
|
-
|
|
129
|
-
#### Phase Definition Rules
|
|
130
|
-
1. **Phase 1**: Contains all tasks with zero dependencies
|
|
131
|
-
2. **Phase N**: Contains tasks whose dependencies are ALL satisfied by tasks in phases 1 through N-1
|
|
132
|
-
3. **Parallelism Priority**: Maximize the number of tasks that can run simultaneously in each phase
|
|
133
|
-
4. **Completeness**: Every task must be assigned to exactly one phase
|
|
134
|
-
|
|
135
|
-
#### Blueprint Structure
|
|
136
|
-
|
|
137
|
-
Use the template in .ai/task-manager/config/templates/BLUEPRINT_TEMPLATE.md for the execution blueprint structure.
|
|
138
|
-
|
|
139
|
-
### Validation Requirements
|
|
140
|
-
|
|
141
|
-
#### Phase Transition Rules
|
|
142
|
-
1. All tasks in the current phase must have status: "completed"
|
|
143
|
-
2. All validation gates defined in `/config/hooks/POST_PHASE.md` for the current phase must pass
|
|
144
|
-
3. No task in a future phase can begin until these conditions are met
|
|
28
|
+
Verify there are no circular dependencies.
|
|
145
29
|
|
|
146
|
-
|
|
147
|
-
Before finalizing, ensure:
|
|
148
|
-
- [ ] Every task appears in exactly one phase
|
|
149
|
-
- [ ] No task appears in a phase before all its dependencies
|
|
150
|
-
- [ ] Phase 1 contains only tasks with no dependencies
|
|
151
|
-
- [ ] Each phase maximizes parallel execution opportunities
|
|
152
|
-
- [ ] All phases reference their validation gates
|
|
153
|
-
- [ ] The execution summary accurately reflects the blueprint
|
|
30
|
+
### Execution Phases
|
|
154
31
|
|
|
155
|
-
|
|
32
|
+
Group tasks into phases:
|
|
33
|
+
- **Phase 1**: Tasks with no dependencies (run in parallel)
|
|
34
|
+
- **Phase N**: Tasks whose dependencies are all in earlier phases
|
|
156
35
|
|
|
157
|
-
|
|
36
|
+
Use the template in `.ai/task-manager/config/templates/BLUEPRINT_TEMPLATE.md` for structure.
|
|
158
37
|
|
|
159
|
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
-
|
|
38
|
+
Before finalizing, verify:
|
|
39
|
+
- Every task is in exactly one phase
|
|
40
|
+
- No task runs before its dependencies complete
|
|
41
|
+
- Phase 1 has only zero-dependency tasks
|
|
@@ -11,19 +11,13 @@ This hook executes before task assignment to determine the most appropriate agen
|
|
|
11
11
|
- Select the most appropriate sub-agent (if any are available). If no sub-agent is appropriate, use the general-purpose one.
|
|
12
12
|
- Consider task-specific requirements from the task document
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
[IMPORTANT] Only for assistants that support assistant skills: Claude
|
|
17
|
-
</summary>
|
|
18
|
-
|
|
19
|
-
Analyze the set of tasks skills in order to engage any relevant assistant skills as necessary (either global or project skills).
|
|
20
|
-
</details>
|
|
14
|
+
[IMPORTANT] Analyze the set of tasks skills in order to engage any relevant assistant skills as necessary (either global
|
|
15
|
+
or project skills).
|
|
21
16
|
|
|
22
17
|
|
|
23
18
|
## Available Sub-Agents
|
|
24
|
-
Analyze the sub-agents available in your current assistant's agents directory. If none are available
|
|
25
|
-
|
|
26
|
-
agent.
|
|
19
|
+
Analyze the sub-agents available in your current assistant's agents directory. If none are available or the available
|
|
20
|
+
ones do not match the task's requirements, then use a generic agent.
|
|
27
21
|
|
|
28
22
|
## Matching Criteria
|
|
29
23
|
Select agents based on:
|
|
@@ -38,27 +32,7 @@ Read task skills and select appropriate task-specific agent:
|
|
|
38
32
|
|
|
39
33
|
```bash
|
|
40
34
|
# Extract skills from task frontmatter
|
|
41
|
-
TASK_SKILLS=$(
|
|
42
|
-
/^---$/ { if (++delim == 2) exit }
|
|
43
|
-
/^skills:/ {
|
|
44
|
-
in_skills = 1
|
|
45
|
-
# Check if skills are on the same line
|
|
46
|
-
if (match($0, /\[.*\]/)) {
|
|
47
|
-
gsub(/^skills:[ \t]*\[/, "")
|
|
48
|
-
gsub(/\].*$/, "")
|
|
49
|
-
gsub(/[ \t]/, "")
|
|
50
|
-
print
|
|
51
|
-
in_skills = 0
|
|
52
|
-
}
|
|
53
|
-
next
|
|
54
|
-
}
|
|
55
|
-
in_skills && /^[^ ]/ { in_skills = 0 }
|
|
56
|
-
in_skills && /^[ \t]*-/ {
|
|
57
|
-
gsub(/^[ \t]*-[ \t]*/, "")
|
|
58
|
-
gsub(/^"/, ""); gsub(/"$/, "")
|
|
59
|
-
print
|
|
60
|
-
}
|
|
61
|
-
' "$TASK_FILE" | tr ',' '\n' | sed 's/^[ \t]*//;s/[ \t]*$//' | grep -v '^$')
|
|
35
|
+
TASK_SKILLS=$(node "$root/config/scripts/extract-task-skills.cjs" "$TASK_FILE")
|
|
62
36
|
|
|
63
37
|
echo "Task skills required: $TASK_SKILLS"
|
|
64
38
|
|
|
@@ -75,4 +49,4 @@ done
|
|
|
75
49
|
if [ "$AGENT_FOUND" = false ]; then
|
|
76
50
|
echo "Using general-purpose agent for task execution"
|
|
77
51
|
fi
|
|
78
|
-
```
|
|
52
|
+
```
|
|
@@ -7,47 +7,24 @@
|
|
|
7
7
|
* Returns: 0 if all dependencies are resolved, 1 if not
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
const fs = require('fs
|
|
10
|
+
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const {
|
|
13
13
|
resolvePlan,
|
|
14
14
|
parseFrontmatter
|
|
15
15
|
} = require('./shared-utils.cjs');
|
|
16
16
|
|
|
17
|
-
// Chalk instance - loaded dynamically to handle ESM module
|
|
18
|
-
let chalkInstance = null;
|
|
19
|
-
|
|
20
|
-
// Initialize chalk instance dynamically
|
|
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;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
17
|
// Color functions for output
|
|
38
|
-
const _printError = (message
|
|
39
|
-
|
|
40
|
-
console.error(formattedMessage);
|
|
18
|
+
const _printError = (message) => {
|
|
19
|
+
console.error(`ERROR: ${message}`);
|
|
41
20
|
};
|
|
42
21
|
|
|
43
|
-
const _printSuccess = (message
|
|
44
|
-
|
|
45
|
-
console.log(formattedMessage);
|
|
22
|
+
const _printSuccess = (message) => {
|
|
23
|
+
console.log(`✓ ${message}`);
|
|
46
24
|
};
|
|
47
25
|
|
|
48
|
-
const _printWarning = (message
|
|
49
|
-
|
|
50
|
-
console.log(formattedMessage);
|
|
26
|
+
const _printWarning = (message) => {
|
|
27
|
+
console.log(`⚠ ${message}`);
|
|
51
28
|
};
|
|
52
29
|
|
|
53
30
|
const _printInfo = (message) => {
|
|
@@ -141,13 +118,10 @@ const _extractStatus = (frontmatter) => {
|
|
|
141
118
|
};
|
|
142
119
|
|
|
143
120
|
// Main function
|
|
144
|
-
const _main =
|
|
145
|
-
// Initialize chalk
|
|
146
|
-
const chalk = await _initChalk();
|
|
147
|
-
|
|
121
|
+
const _main = (startPath = process.cwd()) => {
|
|
148
122
|
// Check arguments
|
|
149
123
|
if (process.argv.length !== 4) {
|
|
150
|
-
_printError('Invalid number of arguments'
|
|
124
|
+
_printError('Invalid number of arguments');
|
|
151
125
|
console.log('Usage: node check-task-dependencies.cjs <plan-id-or-path> <task-id>');
|
|
152
126
|
console.log('Example: node check-task-dependencies.cjs 16 03');
|
|
153
127
|
process.exit(1);
|
|
@@ -159,7 +133,7 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
159
133
|
const resolved = resolvePlan(inputId, startPath);
|
|
160
134
|
|
|
161
135
|
if (!resolved) {
|
|
162
|
-
_printError(`Plan "${inputId}" not found or invalid
|
|
136
|
+
_printError(`Plan "${inputId}" not found or invalid`);
|
|
163
137
|
process.exit(1);
|
|
164
138
|
}
|
|
165
139
|
|
|
@@ -173,7 +147,7 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
173
147
|
const taskFile = _findTaskFile(planDir, taskId);
|
|
174
148
|
|
|
175
149
|
if (!taskFile || !fs.existsSync(taskFile)) {
|
|
176
|
-
_printError(`Task with ID ${taskId} not found in plan ${planId}
|
|
150
|
+
_printError(`Task with ID ${taskId} not found in plan ${planId}`);
|
|
177
151
|
process.exit(1);
|
|
178
152
|
}
|
|
179
153
|
|
|
@@ -187,7 +161,7 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
187
161
|
|
|
188
162
|
// Check if there are any dependencies
|
|
189
163
|
if (dependencies.length === 0) {
|
|
190
|
-
_printSuccess('Task has no dependencies - ready to execute!'
|
|
164
|
+
_printSuccess('Task has no dependencies - ready to execute!');
|
|
191
165
|
process.exit(0);
|
|
192
166
|
}
|
|
193
167
|
|
|
@@ -212,7 +186,7 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
212
186
|
const depFile = _findTaskFile(planDir, depId);
|
|
213
187
|
|
|
214
188
|
if (!depFile || !fs.existsSync(depFile)) {
|
|
215
|
-
_printError(`Dependency task ${depId} not found
|
|
189
|
+
_printError(`Dependency task ${depId} not found`);
|
|
216
190
|
allResolved = false;
|
|
217
191
|
unresolvedDeps.push(`${depId} (not found)`);
|
|
218
192
|
continue;
|
|
@@ -225,10 +199,10 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
225
199
|
|
|
226
200
|
// Check if status is completed
|
|
227
201
|
if (status === 'completed') {
|
|
228
|
-
_printSuccess(`Task ${depId} - Status: completed
|
|
202
|
+
_printSuccess(`Task ${depId} - Status: completed ✓`);
|
|
229
203
|
resolvedCount++;
|
|
230
204
|
} else {
|
|
231
|
-
_printWarning(`Task ${depId} - Status: ${status || 'unknown'}
|
|
205
|
+
_printWarning(`Task ${depId} - Status: ${status || 'unknown'} ✗`);
|
|
232
206
|
allResolved = false;
|
|
233
207
|
unresolvedDeps.push(`${depId} (${status || 'unknown'})`);
|
|
234
208
|
}
|
|
@@ -244,10 +218,10 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
244
218
|
console.log('');
|
|
245
219
|
|
|
246
220
|
if (allResolved) {
|
|
247
|
-
_printSuccess(`All dependencies are resolved! Task ${taskId} is ready to execute
|
|
221
|
+
_printSuccess(`All dependencies are resolved! Task ${taskId} is ready to execute.`);
|
|
248
222
|
process.exit(0);
|
|
249
223
|
} else {
|
|
250
|
-
_printError(`Task ${taskId} has unresolved dependencies
|
|
224
|
+
_printError(`Task ${taskId} has unresolved dependencies:`);
|
|
251
225
|
unresolvedDeps.forEach(dep => {
|
|
252
226
|
console.log(dep);
|
|
253
227
|
});
|
|
@@ -258,10 +232,7 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
258
232
|
|
|
259
233
|
// Run the script
|
|
260
234
|
if (require.main === module) {
|
|
261
|
-
_main()
|
|
262
|
-
console.error('Script execution failed:', error);
|
|
263
|
-
process.exit(1);
|
|
264
|
-
});
|
|
235
|
+
_main();
|
|
265
236
|
}
|
|
266
237
|
|
|
267
238
|
module.exports = {
|
|
@@ -15,43 +15,21 @@ const fs = require('fs');
|
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const { resolvePlan } = require('./shared-utils.cjs');
|
|
17
17
|
|
|
18
|
-
// Chalk instance - loaded dynamically to handle ESM module
|
|
19
|
-
let chalkInstance = null;
|
|
20
|
-
|
|
21
|
-
// Initialize chalk instance dynamically
|
|
22
|
-
async function _initChalk() {
|
|
23
|
-
if (chalkInstance) return chalkInstance;
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const { default: chalk } = await import('chalk');
|
|
27
|
-
chalkInstance = chalk;
|
|
28
|
-
} catch (_error) {
|
|
29
|
-
// Chalk not available, will fall back to plain console output
|
|
30
|
-
chalkInstance = null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return chalkInstance;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
18
|
// Color functions for output
|
|
37
|
-
const _printError = (message
|
|
38
|
-
|
|
39
|
-
console.error(formattedMessage);
|
|
19
|
+
const _printError = (message) => {
|
|
20
|
+
console.error(`ERROR: ${message}`);
|
|
40
21
|
};
|
|
41
22
|
|
|
42
|
-
const _printSuccess = (message
|
|
43
|
-
|
|
44
|
-
console.log(formattedMessage);
|
|
23
|
+
const _printSuccess = (message) => {
|
|
24
|
+
console.log(`✓ ${message}`);
|
|
45
25
|
};
|
|
46
26
|
|
|
47
|
-
const _printWarning = (message
|
|
48
|
-
|
|
49
|
-
console.log(formattedMessage);
|
|
27
|
+
const _printWarning = (message) => {
|
|
28
|
+
console.log(`⚠ ${message}`);
|
|
50
29
|
};
|
|
51
30
|
|
|
52
|
-
const _printInfo = (message
|
|
53
|
-
|
|
54
|
-
console.log(formattedMessage);
|
|
31
|
+
const _printInfo = (message) => {
|
|
32
|
+
console.log(message);
|
|
55
33
|
};
|
|
56
34
|
|
|
57
35
|
/**
|
|
@@ -141,13 +119,10 @@ const _extractPlanName = (planDir) => {
|
|
|
141
119
|
};
|
|
142
120
|
|
|
143
121
|
// Main function
|
|
144
|
-
const _main =
|
|
145
|
-
// Initialize chalk
|
|
146
|
-
const chalk = await _initChalk();
|
|
147
|
-
|
|
122
|
+
const _main = (startPath = process.cwd()) => {
|
|
148
123
|
// Check arguments
|
|
149
124
|
if (process.argv.length < 3) {
|
|
150
|
-
_printError('Missing plan ID argument'
|
|
125
|
+
_printError('Missing plan ID argument');
|
|
151
126
|
console.log('Usage: node create-feature-branch.cjs <plan-id-or-path>');
|
|
152
127
|
console.log('Example: node create-feature-branch.cjs 58');
|
|
153
128
|
process.exit(1);
|
|
@@ -157,7 +132,7 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
157
132
|
|
|
158
133
|
// Step 1: Check if this is a git repository
|
|
159
134
|
if (!_isGitRepo()) {
|
|
160
|
-
_printError('Not a git repository'
|
|
135
|
+
_printError('Not a git repository');
|
|
161
136
|
process.exit(1);
|
|
162
137
|
}
|
|
163
138
|
|
|
@@ -165,31 +140,31 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
165
140
|
const resolved = resolvePlan(inputId, startPath);
|
|
166
141
|
|
|
167
142
|
if (!resolved) {
|
|
168
|
-
_printError(`Plan "${inputId}" not found or invalid
|
|
143
|
+
_printError(`Plan "${inputId}" not found or invalid`);
|
|
169
144
|
process.exit(1);
|
|
170
145
|
}
|
|
171
146
|
|
|
172
147
|
const { planDir, planId } = resolved;
|
|
173
|
-
_printInfo(`Found plan: ${path.basename(planDir)}
|
|
148
|
+
_printInfo(`Found plan: ${path.basename(planDir)}`);
|
|
174
149
|
|
|
175
150
|
// Step 3: Check current branch
|
|
176
151
|
const currentBranch = _getCurrentBranch();
|
|
177
152
|
|
|
178
153
|
if (!currentBranch) {
|
|
179
|
-
_printError('Could not determine current git branch'
|
|
154
|
+
_printError('Could not determine current git branch');
|
|
180
155
|
process.exit(1);
|
|
181
156
|
}
|
|
182
157
|
|
|
183
158
|
if (currentBranch !== 'main' && currentBranch !== 'master') {
|
|
184
|
-
_printWarning(`Not on main/master branch (current: ${currentBranch})
|
|
185
|
-
_printInfo('Proceeding without creating a new branch'
|
|
159
|
+
_printWarning(`Not on main/master branch (current: ${currentBranch})`);
|
|
160
|
+
_printInfo('Proceeding without creating a new branch');
|
|
186
161
|
process.exit(0);
|
|
187
162
|
}
|
|
188
163
|
|
|
189
164
|
// Step 4: Check for uncommitted changes
|
|
190
165
|
if (_hasUncommittedChanges()) {
|
|
191
|
-
_printError('Uncommitted changes detected in working tree'
|
|
192
|
-
_printInfo('Please commit or stash your changes before creating a feature branch'
|
|
166
|
+
_printError('Uncommitted changes detected in working tree');
|
|
167
|
+
_printInfo('Please commit or stash your changes before creating a feature branch');
|
|
193
168
|
process.exit(1);
|
|
194
169
|
}
|
|
195
170
|
|
|
@@ -200,8 +175,8 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
200
175
|
|
|
201
176
|
// Step 6: Check if branch already exists
|
|
202
177
|
if (_branchExists(branchName)) {
|
|
203
|
-
_printWarning(`Branch "${branchName}" already exists
|
|
204
|
-
_printInfo('Proceeding with existing branch'
|
|
178
|
+
_printWarning(`Branch "${branchName}" already exists`);
|
|
179
|
+
_printInfo('Proceeding with existing branch');
|
|
205
180
|
process.exit(0);
|
|
206
181
|
}
|
|
207
182
|
|
|
@@ -209,20 +184,17 @@ const _main = async (startPath = process.cwd()) => {
|
|
|
209
184
|
const createResult = _execGit(`git checkout -b "${branchName}"`);
|
|
210
185
|
|
|
211
186
|
if (createResult === null) {
|
|
212
|
-
_printError(`Failed to create branch "${branchName}"
|
|
187
|
+
_printError(`Failed to create branch "${branchName}"`);
|
|
213
188
|
process.exit(1);
|
|
214
189
|
}
|
|
215
190
|
|
|
216
|
-
_printSuccess(`Created and switched to branch: ${branchName}
|
|
191
|
+
_printSuccess(`Created and switched to branch: ${branchName}`);
|
|
217
192
|
process.exit(0);
|
|
218
193
|
};
|
|
219
194
|
|
|
220
195
|
// Run the script
|
|
221
196
|
if (require.main === module) {
|
|
222
|
-
_main()
|
|
223
|
-
console.error('Script execution failed:', error);
|
|
224
|
-
process.exit(1);
|
|
225
|
-
});
|
|
197
|
+
_main();
|
|
226
198
|
}
|
|
227
199
|
|
|
228
200
|
module.exports = {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extract skills from a task file's YAML frontmatter.
|
|
5
|
+
*
|
|
6
|
+
* Usage: node extract-task-skills.cjs <task-file>
|
|
7
|
+
* Output: One skill per line, trimmed, empty lines removed.
|
|
8
|
+
*
|
|
9
|
+
* Supports both inline array and block list formats:
|
|
10
|
+
* skills: [skill-a, skill-b]
|
|
11
|
+
* skills:
|
|
12
|
+
* - skill-a
|
|
13
|
+
* - "skill-b"
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const taskFile = process.argv[2];
|
|
22
|
+
if (!taskFile) {
|
|
23
|
+
console.error('Usage: node extract-task-skills.cjs <task-file>');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const content = fs.readFileSync(path.resolve(taskFile), 'utf8');
|
|
28
|
+
const lines = content.split('\n');
|
|
29
|
+
|
|
30
|
+
let inFrontmatter = false;
|
|
31
|
+
let frontmatterClosed = false;
|
|
32
|
+
let inSkills = false;
|
|
33
|
+
const skills = [];
|
|
34
|
+
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
if (frontmatterClosed) break;
|
|
37
|
+
|
|
38
|
+
if (line.trim() === '---') {
|
|
39
|
+
if (!inFrontmatter) {
|
|
40
|
+
inFrontmatter = true;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// Second delimiter – end of frontmatter
|
|
44
|
+
frontmatterClosed = true;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!inFrontmatter) continue;
|
|
49
|
+
|
|
50
|
+
// Detect "skills:" key
|
|
51
|
+
if (/^skills\s*:/.test(line)) {
|
|
52
|
+
inSkills = true;
|
|
53
|
+
|
|
54
|
+
// Check for inline array: skills: [a, b, c]
|
|
55
|
+
const inlineMatch = line.match(/\[(.*)]/);
|
|
56
|
+
if (inlineMatch) {
|
|
57
|
+
inlineMatch[1]
|
|
58
|
+
.split(',')
|
|
59
|
+
.map(s => s.trim().replace(/^["']|["']$/g, ''))
|
|
60
|
+
.filter(Boolean)
|
|
61
|
+
.forEach(s => skills.push(s));
|
|
62
|
+
inSkills = false;
|
|
63
|
+
}
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (inSkills) {
|
|
68
|
+
// A non-indented, non-empty line ends the block list
|
|
69
|
+
if (/^\S/.test(line)) {
|
|
70
|
+
inSkills = false;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// List item: " - skill-name"
|
|
74
|
+
const itemMatch = line.match(/^\s*-\s*(.*)/);
|
|
75
|
+
if (itemMatch) {
|
|
76
|
+
const value = itemMatch[1].trim().replace(/^["']|["']$/g, '');
|
|
77
|
+
if (value) skills.push(value);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (skills.length > 0) {
|
|
83
|
+
console.log(skills.join('\n'));
|
|
84
|
+
}
|
|
@@ -55,7 +55,7 @@ const findRoot = (currentDir) => {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
const parentDir = path.dirname(currentDir);
|
|
58
|
-
if (parentDir
|
|
58
|
+
if (parentDir.length < currentDir.length) {
|
|
59
59
|
findRoot(parentDir);
|
|
60
60
|
} else {
|
|
61
61
|
process.exit(1);
|
|
@@ -123,6 +123,7 @@ Use your internal Todo task tool to track the execution of all phases, and the f
|
|
|
123
123
|
- [ ] Execute $root/.ai/task-manager/config/hooks/PRE_PHASE.md hook before Phase 3.
|
|
124
124
|
- [ ] Phase 3: Execute 1 task(s) in parallel.
|
|
125
125
|
- [ ] Execute $root/.ai/task-manager/config/hooks/POST_PHASE.md hook after Phase 3.
|
|
126
|
+
- [ ] Execute $root/.ai/task-manager/config/hooks/POST_EXECUTION.md hook after all phases complete.
|
|
126
127
|
- [ ] Update the Plan 7 with execution summary using $root/.ai/task-manager/config/hooks/EXECUTION_SUMMARY_TEMPLATE.md.
|
|
127
128
|
- [ ] Archive Plan 7.
|
|
128
129
|
|
|
@@ -198,9 +199,16 @@ This structured output enables automated workflow coordination and must be inclu
|
|
|
198
199
|
|
|
199
200
|
Upon successful completion of all phases and validation gates, perform the following additional steps:
|
|
200
201
|
|
|
202
|
+
- [ ] Post-Execution Validation
|
|
201
203
|
- [ ] Execution Summary Generation
|
|
202
204
|
- [ ] Plan Archival
|
|
203
205
|
|
|
206
|
+
### 0. Post-Execution Validation
|
|
207
|
+
|
|
208
|
+
Read and execute $root/.ai/task-manager/config/hooks/POST_EXECUTION.md
|
|
209
|
+
|
|
210
|
+
If validation fails, halt execution. The plan remains in `plans/` for debugging.
|
|
211
|
+
|
|
204
212
|
### 1. Execution Summary Generation
|
|
205
213
|
|
|
206
214
|
Append an execution summary section to the plan document with the format described in $root/.ai/task-manager/config/templates/[EXECUTION_SUMMARY_TEMPLATE.md
|
|
@@ -31,7 +31,7 @@ const findRoot = (currentDir) => {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const parentDir = path.dirname(currentDir);
|
|
34
|
-
if (parentDir
|
|
34
|
+
if (parentDir.length < currentDir.length) {
|
|
35
35
|
findRoot(parentDir);
|
|
36
36
|
} else {
|
|
37
37
|
process.exit(1);
|
|
@@ -443,9 +443,16 @@ This structured output enables automated workflow coordination and must be inclu
|
|
|
443
443
|
|
|
444
444
|
Upon successful completion of all phases and validation gates, perform the following additional steps:
|
|
445
445
|
|
|
446
|
+
- [ ] Post-Execution Validation
|
|
446
447
|
- [ ] Execution Summary Generation
|
|
447
448
|
- [ ] Plan Archival
|
|
448
449
|
|
|
450
|
+
#### Post-Execution Validation
|
|
451
|
+
|
|
452
|
+
Read and execute $root/.ai/task-manager/config/hooks/POST_EXECUTION.md
|
|
453
|
+
|
|
454
|
+
If validation fails, halt execution. The plan remains in `plans/` for debugging.
|
|
455
|
+
|
|
449
456
|
#### Execution Summary Generation
|
|
450
457
|
|
|
451
458
|
Append an execution summary section to the plan document with the format described in $root/.ai/task-manager/config/templates/EXECUTION_SUMMARY_TEMPLATE.md
|