@e0ipso/ai-task-manager 1.36.1 → 1.37.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/README.md +26 -21
- package/dist/cli.js +1 -32
- package/dist/cli.js.map +1 -1
- package/dist/conflict-detector.d.ts.map +1 -1
- package/dist/conflict-detector.js +0 -4
- package/dist/conflict-detector.js.map +1 -1
- package/dist/index.d.ts +3 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +50 -245
- package/dist/index.js.map +1 -1
- package/dist/metadata.d.ts +9 -0
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +14 -0
- package/dist/metadata.js.map +1 -1
- package/dist/types.d.ts +18 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +27 -58
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +93 -219
- package/dist/utils.js.map +1 -1
- package/package.json +4 -2
- package/templates/ai-task-manager/config/TASK_MANAGER.md +3 -3
- package/templates/ai-task-manager/config/hooks/PRE_PHASE.md +6 -26
- package/templates/ai-task-manager/config/hooks/PRE_TASK_ASSIGNMENT.md +6 -24
- package/templates/ai-task-manager/config/templates/PLAN_TEMPLATE.md +1 -1
- package/templates/{assistant → harness}/agents/plan-creator.md +2 -2
- package/templates/harness/skills/task-create-plan/SKILL.md +120 -0
- package/templates/harness/skills/task-create-plan/scripts/find-task-manager-root.cjs +116 -0
- package/templates/harness/skills/task-create-plan/scripts/get-next-plan-id.cjs +214 -0
- package/templates/harness/skills/task-execute-blueprint/SKILL.md +139 -0
- package/templates/harness/skills/task-execute-blueprint/scripts/create-feature-branch.cjs +376 -0
- package/templates/harness/skills/task-execute-blueprint/scripts/find-task-manager-root.cjs +116 -0
- package/templates/harness/skills/task-execute-blueprint/scripts/validate-plan-blueprint.cjs +375 -0
- package/templates/harness/skills/task-execute-task/SKILL.md +195 -0
- package/templates/harness/skills/task-execute-task/scripts/check-task-dependencies.cjs +437 -0
- package/templates/harness/skills/task-execute-task/scripts/find-task-manager-root.cjs +116 -0
- package/templates/harness/skills/task-execute-task/scripts/validate-plan-blueprint.cjs +375 -0
- package/templates/harness/skills/task-full-workflow/SKILL.md +378 -0
- package/templates/harness/skills/task-full-workflow/scripts/create-feature-branch.cjs +376 -0
- package/templates/harness/skills/task-full-workflow/scripts/find-task-manager-root.cjs +116 -0
- package/templates/harness/skills/task-full-workflow/scripts/get-next-plan-id.cjs +214 -0
- package/templates/harness/skills/task-full-workflow/scripts/get-next-task-id.cjs +312 -0
- package/templates/harness/skills/task-full-workflow/scripts/validate-plan-blueprint.cjs +375 -0
- package/templates/harness/skills/task-generate-tasks/SKILL.md +244 -0
- package/templates/harness/skills/task-generate-tasks/scripts/find-task-manager-root.cjs +116 -0
- package/templates/harness/skills/task-generate-tasks/scripts/get-next-task-id.cjs +312 -0
- package/templates/harness/skills/task-generate-tasks/scripts/validate-plan-blueprint.cjs +375 -0
- package/templates/harness/skills/task-refine-plan/SKILL.md +205 -0
- package/templates/harness/skills/task-refine-plan/scripts/find-task-manager-root.cjs +116 -0
- package/templates/harness/skills/task-refine-plan/scripts/validate-plan-blueprint.cjs +375 -0
- package/dist/exec.d.ts +0 -13
- package/dist/exec.d.ts.map +0 -1
- package/dist/exec.js +0 -261
- package/dist/exec.js.map +0 -1
- package/templates/ai-task-manager/config/scripts/check-task-dependencies.cjs +0 -240
- package/templates/ai-task-manager/config/scripts/compose-prompt.cjs +0 -234
- package/templates/ai-task-manager/config/scripts/create-feature-branch.cjs +0 -204
- package/templates/ai-task-manager/config/scripts/extract-task-skills.cjs +0 -84
- package/templates/ai-task-manager/config/scripts/find-root.cjs +0 -10
- package/templates/ai-task-manager/config/scripts/get-next-plan-id.cjs +0 -49
- package/templates/ai-task-manager/config/scripts/get-next-task-id.cjs +0 -81
- package/templates/ai-task-manager/config/scripts/shared-utils.cjs +0 -418
- package/templates/ai-task-manager/config/scripts/validate-plan-blueprint.cjs +0 -138
- package/templates/assistant/commands/tasks/create-plan-auto.md +0 -174
- package/templates/assistant/commands/tasks/create-plan.md +0 -175
- package/templates/assistant/commands/tasks/execute-blueprint.md +0 -233
- package/templates/assistant/commands/tasks/execute-task.md +0 -351
- package/templates/assistant/commands/tasks/fix-broken-tests.md +0 -44
- package/templates/assistant/commands/tasks/full-workflow.md +0 -849
- package/templates/assistant/commands/tasks/generate-tasks.md +0 -348
- package/templates/assistant/commands/tasks/refine-plan-auto.md +0 -172
- package/templates/assistant/commands/tasks/refine-plan.md +0 -163
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/skill-scripts/validate-plan-blueprint.ts
|
|
31
|
+
var validate_plan_blueprint_exports = {};
|
|
32
|
+
__export(validate_plan_blueprint_exports, {
|
|
33
|
+
main: () => main
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(validate_plan_blueprint_exports);
|
|
36
|
+
var fs4 = __toESM(require("fs"));
|
|
37
|
+
var path4 = __toESM(require("path"));
|
|
38
|
+
|
|
39
|
+
// src/skill-scripts/shared/root.ts
|
|
40
|
+
var fs = __toESM(require("fs"));
|
|
41
|
+
var path = __toESM(require("path"));
|
|
42
|
+
var EXPECTED_SCHEMA = true ? 1 : 1;
|
|
43
|
+
var isValidTaskManagerRoot = (taskManagerPath) => {
|
|
44
|
+
try {
|
|
45
|
+
if (!fs.existsSync(taskManagerPath)) return false;
|
|
46
|
+
if (!fs.lstatSync(taskManagerPath).isDirectory()) return false;
|
|
47
|
+
const metadataPath = path.join(taskManagerPath, ".init-metadata.json");
|
|
48
|
+
if (!fs.existsSync(metadataPath)) return false;
|
|
49
|
+
const metadata = JSON.parse(fs.readFileSync(metadataPath, "utf8"));
|
|
50
|
+
return metadata && typeof metadata === "object" && "version" in metadata;
|
|
51
|
+
} catch (_err) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var getTaskManagerAt = (directory) => {
|
|
56
|
+
const taskManagerPath = path.join(directory, ".ai", "task-manager");
|
|
57
|
+
return isValidTaskManagerRoot(taskManagerPath) ? taskManagerPath : null;
|
|
58
|
+
};
|
|
59
|
+
var getParentPaths = (currentPath, acc = []) => {
|
|
60
|
+
const absolutePath = path.resolve(currentPath);
|
|
61
|
+
const nextAcc = [...acc, absolutePath];
|
|
62
|
+
const parentPath = path.dirname(absolutePath);
|
|
63
|
+
if (parentPath === absolutePath) return nextAcc;
|
|
64
|
+
return getParentPaths(parentPath, nextAcc);
|
|
65
|
+
};
|
|
66
|
+
var checkWorkspaceSchema = (metadataPath) => {
|
|
67
|
+
let metadata;
|
|
68
|
+
try {
|
|
69
|
+
metadata = JSON.parse(fs.readFileSync(metadataPath, "utf8"));
|
|
70
|
+
} catch {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const actual = typeof metadata.workspaceSchemaVersion === "number" ? metadata.workspaceSchemaVersion : 1;
|
|
74
|
+
if (actual === EXPECTED_SCHEMA) return;
|
|
75
|
+
if (actual < EXPECTED_SCHEMA) {
|
|
76
|
+
process.stderr.write(
|
|
77
|
+
`Workspace schema v${actual} is older than this skill requires (v${EXPECTED_SCHEMA}). Re-run \`npx @e0ipso/ai-task-manager init\` with the latest CLI to update.
|
|
78
|
+
`
|
|
79
|
+
);
|
|
80
|
+
} else {
|
|
81
|
+
process.stderr.write(
|
|
82
|
+
`This skill (built for workspace schema v${EXPECTED_SCHEMA}) is older than the workspace (v${actual}). Re-run \`npx skills add e0ipso/ai-task-manager\` to update skills.
|
|
83
|
+
`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
process.exit(1);
|
|
87
|
+
};
|
|
88
|
+
var findTaskManagerRoot = (startPath = process.cwd()) => {
|
|
89
|
+
const paths = getParentPaths(startPath);
|
|
90
|
+
const found = paths.find((p) => getTaskManagerAt(p));
|
|
91
|
+
if (!found) return null;
|
|
92
|
+
const root = getTaskManagerAt(found);
|
|
93
|
+
if (root) checkWorkspaceSchema(path.join(root, ".init-metadata.json"));
|
|
94
|
+
return root;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// src/skill-scripts/shared/plan-scan.ts
|
|
98
|
+
var fs2 = __toESM(require("fs"));
|
|
99
|
+
var path2 = __toESM(require("path"));
|
|
100
|
+
|
|
101
|
+
// src/skill-scripts/shared/frontmatter.ts
|
|
102
|
+
var ID_PATTERNS = [
|
|
103
|
+
/^\s*["']?id["']?\s*:\s*["']?([+-]?\d+)["']?\s*(?:#.*)?$/im,
|
|
104
|
+
/^\s*id\s*:\s*([+-]?\d+)\s*(?:#.*)?$/im,
|
|
105
|
+
/^\s*["']?id["']?\s*:\s*"([+-]?\d+)"\s*(?:#.*)?$/im,
|
|
106
|
+
/^\s*["']?id["']?\s*:\s*'([+-]?\d+)'\s*(?:#.*)?$/im,
|
|
107
|
+
/^\s*["']id["']\s*:\s*([+-]?\d+)\s*(?:#.*)?$/im,
|
|
108
|
+
/^\s*id\s*:\s*[|>]\s*([+-]?\d+)\s*$/im
|
|
109
|
+
];
|
|
110
|
+
var validateId = (rawId) => {
|
|
111
|
+
const id = parseInt(rawId, 10);
|
|
112
|
+
if (Number.isNaN(id) || id < 0 || id > Number.MAX_SAFE_INTEGER) return null;
|
|
113
|
+
return id;
|
|
114
|
+
};
|
|
115
|
+
var extractIdFromMarkdown = (content) => {
|
|
116
|
+
const frontmatterMatch = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
|
|
117
|
+
if (!frontmatterMatch || !frontmatterMatch[1]) return null;
|
|
118
|
+
const block = frontmatterMatch[1];
|
|
119
|
+
for (const pattern of ID_PATTERNS) {
|
|
120
|
+
const match = block.match(pattern);
|
|
121
|
+
if (match && match[1]) {
|
|
122
|
+
const id = validateId(match[1]);
|
|
123
|
+
if (id !== null) return id;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
};
|
|
128
|
+
var extractIdFromHtml = (content) => {
|
|
129
|
+
const headMatch = content.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
|
|
130
|
+
const scope = headMatch && headMatch[1] ? headMatch[1] : content;
|
|
131
|
+
const metaPatterns = [
|
|
132
|
+
/<meta\s+[^>]*name\s*=\s*["']id["'][^>]*content\s*=\s*["']([+-]?\d+)["'][^>]*\/?>/i,
|
|
133
|
+
/<meta\s+[^>]*content\s*=\s*["']([+-]?\d+)["'][^>]*name\s*=\s*["']id["'][^>]*\/?>/i
|
|
134
|
+
];
|
|
135
|
+
for (const pattern of metaPatterns) {
|
|
136
|
+
const match = scope.match(pattern);
|
|
137
|
+
if (match && match[1]) {
|
|
138
|
+
const id = validateId(match[1]);
|
|
139
|
+
if (id !== null) return id;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
};
|
|
144
|
+
var extractPlanId = (content, filePath) => {
|
|
145
|
+
if (filePath.toLowerCase().endsWith(".html")) return extractIdFromHtml(content);
|
|
146
|
+
return extractIdFromMarkdown(content);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// src/skill-scripts/shared/plan-scan.ts
|
|
150
|
+
var PLAN_EXTENSIONS = [".md", ".html"];
|
|
151
|
+
var scanPlanDir = (planDirPath, dirName, isArchive) => {
|
|
152
|
+
let entries;
|
|
153
|
+
try {
|
|
154
|
+
entries = fs2.readdirSync(planDirPath, { withFileTypes: true });
|
|
155
|
+
} catch (_err) {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
return entries.filter((e) => e.isFile() && PLAN_EXTENSIONS.some((ext) => e.name.endsWith(ext))).flatMap((e) => {
|
|
159
|
+
const filePath = path2.join(planDirPath, e.name);
|
|
160
|
+
try {
|
|
161
|
+
const content = fs2.readFileSync(filePath, "utf8");
|
|
162
|
+
const id = extractPlanId(content, filePath);
|
|
163
|
+
if (id === null) return [];
|
|
164
|
+
return [{ id, file: filePath, dir: planDirPath, isArchive, name: dirName }];
|
|
165
|
+
} catch (_err) {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
var getAllPlans = (taskManagerRoot) => {
|
|
171
|
+
const sources = [
|
|
172
|
+
{ dir: path2.join(taskManagerRoot, "plans"), isArchive: false },
|
|
173
|
+
{ dir: path2.join(taskManagerRoot, "archive"), isArchive: true }
|
|
174
|
+
];
|
|
175
|
+
return sources.flatMap(({ dir, isArchive }) => {
|
|
176
|
+
if (!fs2.existsSync(dir)) return [];
|
|
177
|
+
let entries;
|
|
178
|
+
try {
|
|
179
|
+
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
180
|
+
} catch (_err) {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
return entries.filter((e) => e.isDirectory()).flatMap((e) => scanPlanDir(path2.join(dir, e.name), e.name, isArchive));
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// src/skill-scripts/shared/plan-resolve.ts
|
|
188
|
+
var fs3 = __toESM(require("fs"));
|
|
189
|
+
var path3 = __toESM(require("path"));
|
|
190
|
+
var isValidRootDir = (taskManagerPath) => {
|
|
191
|
+
try {
|
|
192
|
+
if (!fs3.existsSync(taskManagerPath)) return false;
|
|
193
|
+
if (!fs3.lstatSync(taskManagerPath).isDirectory()) return false;
|
|
194
|
+
const metadataPath = path3.join(taskManagerPath, ".init-metadata.json");
|
|
195
|
+
if (!fs3.existsSync(metadataPath)) return false;
|
|
196
|
+
const metadata = JSON.parse(fs3.readFileSync(metadataPath, "utf8"));
|
|
197
|
+
return metadata && typeof metadata === "object" && "version" in metadata;
|
|
198
|
+
} catch (_err) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
var checkStandardRootShortcut = (filePath) => {
|
|
203
|
+
const planDir = path3.dirname(filePath);
|
|
204
|
+
const parentDir = path3.dirname(planDir);
|
|
205
|
+
const possibleRoot = path3.dirname(parentDir);
|
|
206
|
+
const parentBase = path3.basename(parentDir);
|
|
207
|
+
if (parentBase !== "plans" && parentBase !== "archive") return null;
|
|
208
|
+
if (path3.basename(possibleRoot) !== "task-manager") return null;
|
|
209
|
+
const dotAiDir = path3.dirname(possibleRoot);
|
|
210
|
+
if (path3.basename(dotAiDir) !== ".ai") return null;
|
|
211
|
+
return isValidRootDir(possibleRoot) ? possibleRoot : null;
|
|
212
|
+
};
|
|
213
|
+
var resolveByPath = (absolutePath) => {
|
|
214
|
+
let content;
|
|
215
|
+
try {
|
|
216
|
+
content = fs3.readFileSync(absolutePath, "utf8");
|
|
217
|
+
} catch (_err) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
const planId = extractPlanId(content, absolutePath);
|
|
221
|
+
if (planId === null) return null;
|
|
222
|
+
const tmRoot = checkStandardRootShortcut(absolutePath) || findTaskManagerRoot(path3.dirname(absolutePath));
|
|
223
|
+
if (!tmRoot) return null;
|
|
224
|
+
return {
|
|
225
|
+
planFile: absolutePath,
|
|
226
|
+
planDir: path3.dirname(absolutePath),
|
|
227
|
+
taskManagerRoot: tmRoot,
|
|
228
|
+
planId
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
var resolveByIdInAncestry = (planId, startPath, searched = /* @__PURE__ */ new Set()) => {
|
|
232
|
+
const tmRoot = findTaskManagerRoot(startPath);
|
|
233
|
+
if (!tmRoot) return null;
|
|
234
|
+
const normalized = path3.normalize(tmRoot);
|
|
235
|
+
if (searched.has(normalized)) return null;
|
|
236
|
+
searched.add(normalized);
|
|
237
|
+
const plans = getAllPlans(tmRoot);
|
|
238
|
+
const match = plans.find((p) => p.id === planId);
|
|
239
|
+
if (match) {
|
|
240
|
+
return {
|
|
241
|
+
planFile: match.file,
|
|
242
|
+
planDir: match.dir,
|
|
243
|
+
taskManagerRoot: tmRoot,
|
|
244
|
+
planId
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
const parentOfRoot = path3.dirname(path3.dirname(tmRoot));
|
|
248
|
+
if (parentOfRoot === tmRoot) return null;
|
|
249
|
+
return resolveByIdInAncestry(planId, parentOfRoot, searched);
|
|
250
|
+
};
|
|
251
|
+
var resolvePlan = (input, startPath = process.cwd()) => {
|
|
252
|
+
if (input === null || input === void 0 || input === "") return null;
|
|
253
|
+
const inputStr = String(input);
|
|
254
|
+
if (inputStr.startsWith("/")) {
|
|
255
|
+
return resolveByPath(inputStr);
|
|
256
|
+
}
|
|
257
|
+
const planId = parseInt(inputStr, 10);
|
|
258
|
+
if (Number.isNaN(planId)) return null;
|
|
259
|
+
return resolveByIdInAncestry(planId, startPath);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
// src/skill-scripts/validate-plan-blueprint.ts
|
|
263
|
+
var VALID_FIELDS = [
|
|
264
|
+
"planFile",
|
|
265
|
+
"planDir",
|
|
266
|
+
"taskCount",
|
|
267
|
+
"blueprintExists",
|
|
268
|
+
"taskManagerRoot",
|
|
269
|
+
"planId"
|
|
270
|
+
];
|
|
271
|
+
var countTasks = (planDir) => {
|
|
272
|
+
const tasksDir = path4.join(planDir, "tasks");
|
|
273
|
+
if (!fs4.existsSync(tasksDir)) return 0;
|
|
274
|
+
try {
|
|
275
|
+
const stat = fs4.lstatSync(tasksDir);
|
|
276
|
+
if (!stat.isDirectory()) return 0;
|
|
277
|
+
return fs4.readdirSync(tasksDir).filter((f) => f.endsWith(".md")).length;
|
|
278
|
+
} catch (_err) {
|
|
279
|
+
return 0;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
var checkBlueprintExists = (planFile) => {
|
|
283
|
+
try {
|
|
284
|
+
const content = fs4.readFileSync(planFile, "utf8");
|
|
285
|
+
return /^## Execution Blueprint/m.test(content);
|
|
286
|
+
} catch (_err) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
var usage = () => {
|
|
291
|
+
const lines = [
|
|
292
|
+
"Plan ID or absolute path is required",
|
|
293
|
+
"",
|
|
294
|
+
"Usage: node validate-plan-blueprint.cjs <plan-id-or-path> [field-name]",
|
|
295
|
+
"",
|
|
296
|
+
"Examples:",
|
|
297
|
+
" node validate-plan-blueprint.cjs 47",
|
|
298
|
+
" node validate-plan-blueprint.cjs /path/to/plan.md",
|
|
299
|
+
" node validate-plan-blueprint.cjs 47 planFile",
|
|
300
|
+
" node validate-plan-blueprint.cjs 47 blueprintExists"
|
|
301
|
+
];
|
|
302
|
+
lines.forEach((l) => process.stderr.write(`[ERROR] ${l}
|
|
303
|
+
`));
|
|
304
|
+
};
|
|
305
|
+
var listAvailablePlans = (startPath) => {
|
|
306
|
+
const tmRoot = findTaskManagerRoot(startPath);
|
|
307
|
+
if (!tmRoot) return [];
|
|
308
|
+
const plans = getAllPlans(tmRoot);
|
|
309
|
+
return plans.map((p) => p.name).sort((a, b) => {
|
|
310
|
+
const aMatch = a.match(/^(\d+)--/);
|
|
311
|
+
const bMatch = b.match(/^(\d+)--/);
|
|
312
|
+
if (!aMatch || !bMatch || !aMatch[1] || !bMatch[1]) return 0;
|
|
313
|
+
return parseInt(aMatch[1], 10) - parseInt(bMatch[1], 10);
|
|
314
|
+
});
|
|
315
|
+
};
|
|
316
|
+
var main = () => {
|
|
317
|
+
const inputId = process.argv[2];
|
|
318
|
+
const fieldName = process.argv[3];
|
|
319
|
+
if (!inputId) {
|
|
320
|
+
usage();
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
const numericInput = parseInt(inputId, 10);
|
|
324
|
+
const isNumeric = !Number.isNaN(numericInput);
|
|
325
|
+
const isAbsolutePath = inputId.startsWith("/");
|
|
326
|
+
if (!isNumeric && !isAbsolutePath) {
|
|
327
|
+
process.stderr.write(`[ERROR] Invalid plan ID: "${inputId}" is not a valid number
|
|
328
|
+
`);
|
|
329
|
+
process.exit(1);
|
|
330
|
+
}
|
|
331
|
+
const resolved = resolvePlan(inputId);
|
|
332
|
+
if (!resolved) {
|
|
333
|
+
process.stderr.write(`[ERROR] Plan ID ${inputId} not found or invalid
|
|
334
|
+
`);
|
|
335
|
+
process.stderr.write("[ERROR] \n");
|
|
336
|
+
const available = listAvailablePlans(process.cwd());
|
|
337
|
+
if (available.length > 0) {
|
|
338
|
+
process.stderr.write("[ERROR] Available plans:\n");
|
|
339
|
+
available.forEach((name) => process.stderr.write(`[ERROR] ${name}
|
|
340
|
+
`));
|
|
341
|
+
}
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
const result = {
|
|
345
|
+
planFile: resolved.planFile,
|
|
346
|
+
planDir: resolved.planDir,
|
|
347
|
+
taskManagerRoot: resolved.taskManagerRoot,
|
|
348
|
+
planId: resolved.planId,
|
|
349
|
+
taskCount: countTasks(resolved.planDir),
|
|
350
|
+
blueprintExists: checkBlueprintExists(resolved.planFile) ? "yes" : "no"
|
|
351
|
+
};
|
|
352
|
+
if (fieldName) {
|
|
353
|
+
if (!VALID_FIELDS.includes(fieldName)) {
|
|
354
|
+
process.stderr.write(`[ERROR] Invalid field name: ${fieldName}
|
|
355
|
+
`);
|
|
356
|
+
process.stderr.write(`[ERROR] Valid fields: ${VALID_FIELDS.join(", ")}
|
|
357
|
+
`);
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
const value = result[fieldName];
|
|
361
|
+
process.stdout.write(`${String(value)}
|
|
362
|
+
`);
|
|
363
|
+
} else {
|
|
364
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
365
|
+
`);
|
|
366
|
+
}
|
|
367
|
+
process.exit(0);
|
|
368
|
+
};
|
|
369
|
+
if (require.main === module) {
|
|
370
|
+
main();
|
|
371
|
+
}
|
|
372
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
373
|
+
0 && (module.exports = {
|
|
374
|
+
main
|
|
375
|
+
});
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: task-execute-task
|
|
3
|
+
description: Execute a single task from an AI Task Manager plan. Use when the user asks to run, implement, or carry out one specific task ID within a plan — discovers the local .ai/task-manager root, resolves the plan, validates the task file, checks status and dependencies, runs pre-execution hooks, deploys an agent, updates status, documents noteworthy events, and emits a structured Task Execution Result. Do not use for generic development work outside the AI Task Manager.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# task-execute-task
|
|
7
|
+
|
|
8
|
+
Drive the execution of a single task within an existing AI Task Manager plan.
|
|
9
|
+
The skill is assistant-agnostic and self-contained: every script it invokes
|
|
10
|
+
lives under this skill's `scripts/` directory and is referenced by relative
|
|
11
|
+
path.
|
|
12
|
+
|
|
13
|
+
## Critical Rules
|
|
14
|
+
|
|
15
|
+
1. **Never skip dependency validation** — task execution requires all dependencies to be completed.
|
|
16
|
+
2. **Validate task status** — never execute tasks that are already completed, in-progress, or needs-clarification.
|
|
17
|
+
3. **Maintain status integrity** — update task status throughout the execution lifecycle.
|
|
18
|
+
4. **Document execution** — record all outcomes and issues encountered.
|
|
19
|
+
5. **Provide structured output** — always emit the structured result block for orchestrator parsing.
|
|
20
|
+
|
|
21
|
+
## Inputs
|
|
22
|
+
|
|
23
|
+
The user supplies the numeric plan ID and task ID conversationally. Treat them
|
|
24
|
+
as the only authoritative source of intent. Do not invent answers to
|
|
25
|
+
clarifying questions — prompt the user instead.
|
|
26
|
+
|
|
27
|
+
## Failure Modes
|
|
28
|
+
|
|
29
|
+
- **No task-manager root found.** Stop and instruct the user to initialize the
|
|
30
|
+
project. Do not execute the task.
|
|
31
|
+
- **Plan ID does not resolve.** Stop and surface the script's stderr to the
|
|
32
|
+
user. Do not guess a different ID.
|
|
33
|
+
- **Task file not found.** Stop and list available tasks in the plan to help
|
|
34
|
+
the user identify the correct task ID.
|
|
35
|
+
- **Task status blocks execution.** If the task is `completed`,
|
|
36
|
+
`in-progress`, or `needs-clarification`, halt and provide guidance on
|
|
37
|
+
resolving the blocker.
|
|
38
|
+
- **Dependency validation failure.** If `scripts/check-task-dependencies.cjs`
|
|
39
|
+
exits 1, stop and report unresolved dependencies. Do not proceed until they
|
|
40
|
+
are satisfied.
|
|
41
|
+
- **Execution or hook failure.** If `PRE_TASK_EXECUTION.md`,
|
|
42
|
+
`PRE_TASK_ASSIGNMENT.md`, or `POST_ERROR_DETECTION.md` fails, or the
|
|
43
|
+
implementing agent encounters an unrecoverable error, set the task status
|
|
44
|
+
to `failed`, document the error in Noteworthy Events, and emit the
|
|
45
|
+
structured result with `Exit Code: 1`.
|
|
46
|
+
|
|
47
|
+
## Operating Procedure
|
|
48
|
+
|
|
49
|
+
### 1. Locate the task-manager root
|
|
50
|
+
|
|
51
|
+
Run `scripts/find-task-manager-root.cjs` from the user's working directory.
|
|
52
|
+
The script walks up looking for `.ai/task-manager/.init-metadata.json` and
|
|
53
|
+
prints the absolute path of the resolved root on success.
|
|
54
|
+
|
|
55
|
+
If the script exits non-zero, the working directory is not inside an
|
|
56
|
+
initialized task-manager workspace. Stop and ask the user to run the project
|
|
57
|
+
initializer (e.g. `npx @e0ipso/ai-task-manager init`) before continuing. Do
|
|
58
|
+
not attempt to execute a task outside of a valid root.
|
|
59
|
+
|
|
60
|
+
For every subsequent step, treat the path printed by this script as `<root>`.
|
|
61
|
+
|
|
62
|
+
### 2. Resolve the plan
|
|
63
|
+
|
|
64
|
+
Run `scripts/validate-plan-blueprint.cjs <plan-id> planFile` to obtain the
|
|
65
|
+
absolute path of the plan file. The same script also accepts these field
|
|
66
|
+
names (single-field output mode) and exposes them on demand:
|
|
67
|
+
|
|
68
|
+
- `planDir` — absolute path of the plan directory
|
|
69
|
+
- `taskCount` — number of existing task files in that plan's `tasks/`
|
|
70
|
+
- `blueprintExists` — `yes` or `no`
|
|
71
|
+
- `taskManagerRoot` — absolute path of `<root>`
|
|
72
|
+
- `planId` — the resolved numeric plan ID
|
|
73
|
+
|
|
74
|
+
If the script exits non-zero, stop and ask the user to confirm the plan ID.
|
|
75
|
+
Do not guess a different ID.
|
|
76
|
+
|
|
77
|
+
Treat the plan directory path returned by this script as `<plan-dir>`.
|
|
78
|
+
|
|
79
|
+
### 3. Validate the task file
|
|
80
|
+
|
|
81
|
+
Locate the specific task file inside `<plan-dir>/tasks/`. Match using both
|
|
82
|
+
padded and unpadded forms of the task ID:
|
|
83
|
+
|
|
84
|
+
- First, look for `<plan-dir>/tasks/<task-id>--*.md`
|
|
85
|
+
- If not found, look for `<plan-dir>/tasks/0<task-id>--*.md`
|
|
86
|
+
|
|
87
|
+
If no file matches, stop and report that the task ID was not found in the
|
|
88
|
+
plan. List the available task files in `<plan-dir>/tasks/` to help the user
|
|
89
|
+
identify the correct ID.
|
|
90
|
+
|
|
91
|
+
Treat the resolved file path as `<task-file>`.
|
|
92
|
+
|
|
93
|
+
### 4. Check task status
|
|
94
|
+
|
|
95
|
+
Read the YAML frontmatter of `<task-file>` and extract the `status` field.
|
|
96
|
+
|
|
97
|
+
- Block execution if the status is `completed`, `in-progress`, or
|
|
98
|
+
`needs-clarification`.
|
|
99
|
+
- Allow execution if the status is `pending` or `failed`.
|
|
100
|
+
- If the status is missing or unrecognized, proceed with caution and note
|
|
101
|
+
the ambiguity.
|
|
102
|
+
|
|
103
|
+
If execution is blocked, stop and explain why, including guidance on how
|
|
104
|
+
to resolve the blocker (e.g., use execute-blueprint to re-execute a completed
|
|
105
|
+
task, or resolve clarification questions first).
|
|
106
|
+
|
|
107
|
+
#### Valid Status Transitions
|
|
108
|
+
|
|
109
|
+
Reference for orchestrators and execution flow:
|
|
110
|
+
|
|
111
|
+
- `pending` → `in-progress` (execution starts)
|
|
112
|
+
- `in-progress` → `completed` (successful execution)
|
|
113
|
+
- `in-progress` → `failed` (execution error)
|
|
114
|
+
- `failed` → `in-progress` (retry attempt)
|
|
115
|
+
- `pending` → `needs-clarification` (set externally by orchestrator or reviewer)
|
|
116
|
+
- `needs-clarification` → `pending` (clarification resolved, set externally)
|
|
117
|
+
|
|
118
|
+
### 5. Validate dependencies
|
|
119
|
+
|
|
120
|
+
Run `scripts/check-task-dependencies.cjs <plan-id> <task-id>`. The script
|
|
121
|
+
validates that every dependency declared in the task frontmatter has status
|
|
122
|
+
`completed`.
|
|
123
|
+
|
|
124
|
+
If the script exits 1, stop and report that the task is blocked by unresolved
|
|
125
|
+
dependencies. Do not proceed until dependencies are satisfied.
|
|
126
|
+
|
|
127
|
+
### 6. Agent selection
|
|
128
|
+
|
|
129
|
+
Read `<root>/config/hooks/PRE_TASK_ASSIGNMENT.md` and follow its instructions
|
|
130
|
+
for selecting the appropriate agent or skill set for this task.
|
|
131
|
+
|
|
132
|
+
### 7. Update status to in-progress
|
|
133
|
+
|
|
134
|
+
Rewrite the YAML frontmatter of `<task-file>`, setting `status: "in-progress"`.
|
|
135
|
+
Preserve all other frontmatter fields exactly.
|
|
136
|
+
|
|
137
|
+
### 8. Execute the task
|
|
138
|
+
|
|
139
|
+
Deploy an agent using your internal Task tool. The agent MUST perform these
|
|
140
|
+
steps in order:
|
|
141
|
+
|
|
142
|
+
1. **Pre-flight validation**: Read and execute
|
|
143
|
+
`<root>/config/hooks/PRE_TASK_EXECUTION.md` before starting any
|
|
144
|
+
implementation work.
|
|
145
|
+
2. **Execute the task**: Read the complete `<task-file>` and implement
|
|
146
|
+
according to its requirements, including:
|
|
147
|
+
- Objective and acceptance criteria
|
|
148
|
+
- Technical requirements and implementation notes
|
|
149
|
+
- Input dependencies and expected output artifacts
|
|
150
|
+
3. **Monitor progress**: Capture outputs, artifacts, and any issues
|
|
151
|
+
encountered during implementation.
|
|
152
|
+
|
|
153
|
+
### 9. Update status to completed or failed
|
|
154
|
+
|
|
155
|
+
After the agent finishes, rewrite the YAML frontmatter of `<task-file>` based
|
|
156
|
+
on the outcome:
|
|
157
|
+
|
|
158
|
+
- Set `status: "completed"` if the task was implemented successfully and
|
|
159
|
+
all acceptance criteria are met.
|
|
160
|
+
- Set `status: "failed"` if the task could not be completed, acceptance
|
|
161
|
+
criteria were not met, or an unrecoverable error occurred.
|
|
162
|
+
|
|
163
|
+
Preserve all other frontmatter fields exactly.
|
|
164
|
+
|
|
165
|
+
### 10. Document noteworthy events
|
|
166
|
+
|
|
167
|
+
If anything significant occurred during execution — decisions made, issues
|
|
168
|
+
encountered, deviations from the plan, or follow-up actions required —
|
|
169
|
+
append a "Noteworthy Events" section to the end of `<task-file>`:
|
|
170
|
+
|
|
171
|
+
```markdown
|
|
172
|
+
## Noteworthy Events
|
|
173
|
+
- [YYYY-MM-DD] [Event description with sufficient context for the orchestrator]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
If no noteworthy events occurred, do not add the section.
|
|
177
|
+
|
|
178
|
+
### 11. Error handling
|
|
179
|
+
|
|
180
|
+
If any error occurred during execution, read
|
|
181
|
+
`<root>/config/hooks/POST_ERROR_DETECTION.md` and execute its instructions.
|
|
182
|
+
Document the error in Noteworthy Events and ensure the task status is set to
|
|
183
|
+
`failed` if it is not already.
|
|
184
|
+
|
|
185
|
+
### 12. Emit structured output
|
|
186
|
+
|
|
187
|
+
End the session with exactly this block as the final output:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
---
|
|
191
|
+
Task Execution Result:
|
|
192
|
+
- Plan ID: [numeric-id]
|
|
193
|
+
- Task ID: [numeric-id]
|
|
194
|
+
- Exit Code: [0 for success, 1 for failure]
|
|
195
|
+
```
|