@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.
Files changed (72) hide show
  1. package/README.md +26 -21
  2. package/dist/cli.js +1 -32
  3. package/dist/cli.js.map +1 -1
  4. package/dist/conflict-detector.d.ts.map +1 -1
  5. package/dist/conflict-detector.js +0 -4
  6. package/dist/conflict-detector.js.map +1 -1
  7. package/dist/index.d.ts +3 -16
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +50 -245
  10. package/dist/index.js.map +1 -1
  11. package/dist/metadata.d.ts +9 -0
  12. package/dist/metadata.d.ts.map +1 -1
  13. package/dist/metadata.js +14 -0
  14. package/dist/metadata.js.map +1 -1
  15. package/dist/types.d.ts +18 -18
  16. package/dist/types.d.ts.map +1 -1
  17. package/dist/utils.d.ts +27 -58
  18. package/dist/utils.d.ts.map +1 -1
  19. package/dist/utils.js +93 -219
  20. package/dist/utils.js.map +1 -1
  21. package/package.json +4 -2
  22. package/templates/ai-task-manager/config/TASK_MANAGER.md +3 -3
  23. package/templates/ai-task-manager/config/hooks/PRE_PHASE.md +6 -26
  24. package/templates/ai-task-manager/config/hooks/PRE_TASK_ASSIGNMENT.md +6 -24
  25. package/templates/ai-task-manager/config/templates/PLAN_TEMPLATE.md +1 -1
  26. package/templates/{assistant → harness}/agents/plan-creator.md +2 -2
  27. package/templates/harness/skills/task-create-plan/SKILL.md +120 -0
  28. package/templates/harness/skills/task-create-plan/scripts/find-task-manager-root.cjs +116 -0
  29. package/templates/harness/skills/task-create-plan/scripts/get-next-plan-id.cjs +214 -0
  30. package/templates/harness/skills/task-execute-blueprint/SKILL.md +139 -0
  31. package/templates/harness/skills/task-execute-blueprint/scripts/create-feature-branch.cjs +376 -0
  32. package/templates/harness/skills/task-execute-blueprint/scripts/find-task-manager-root.cjs +116 -0
  33. package/templates/harness/skills/task-execute-blueprint/scripts/validate-plan-blueprint.cjs +375 -0
  34. package/templates/harness/skills/task-execute-task/SKILL.md +195 -0
  35. package/templates/harness/skills/task-execute-task/scripts/check-task-dependencies.cjs +437 -0
  36. package/templates/harness/skills/task-execute-task/scripts/find-task-manager-root.cjs +116 -0
  37. package/templates/harness/skills/task-execute-task/scripts/validate-plan-blueprint.cjs +375 -0
  38. package/templates/harness/skills/task-full-workflow/SKILL.md +378 -0
  39. package/templates/harness/skills/task-full-workflow/scripts/create-feature-branch.cjs +376 -0
  40. package/templates/harness/skills/task-full-workflow/scripts/find-task-manager-root.cjs +116 -0
  41. package/templates/harness/skills/task-full-workflow/scripts/get-next-plan-id.cjs +214 -0
  42. package/templates/harness/skills/task-full-workflow/scripts/get-next-task-id.cjs +312 -0
  43. package/templates/harness/skills/task-full-workflow/scripts/validate-plan-blueprint.cjs +375 -0
  44. package/templates/harness/skills/task-generate-tasks/SKILL.md +244 -0
  45. package/templates/harness/skills/task-generate-tasks/scripts/find-task-manager-root.cjs +116 -0
  46. package/templates/harness/skills/task-generate-tasks/scripts/get-next-task-id.cjs +312 -0
  47. package/templates/harness/skills/task-generate-tasks/scripts/validate-plan-blueprint.cjs +375 -0
  48. package/templates/harness/skills/task-refine-plan/SKILL.md +205 -0
  49. package/templates/harness/skills/task-refine-plan/scripts/find-task-manager-root.cjs +116 -0
  50. package/templates/harness/skills/task-refine-plan/scripts/validate-plan-blueprint.cjs +375 -0
  51. package/dist/exec.d.ts +0 -13
  52. package/dist/exec.d.ts.map +0 -1
  53. package/dist/exec.js +0 -261
  54. package/dist/exec.js.map +0 -1
  55. package/templates/ai-task-manager/config/scripts/check-task-dependencies.cjs +0 -240
  56. package/templates/ai-task-manager/config/scripts/compose-prompt.cjs +0 -234
  57. package/templates/ai-task-manager/config/scripts/create-feature-branch.cjs +0 -204
  58. package/templates/ai-task-manager/config/scripts/extract-task-skills.cjs +0 -84
  59. package/templates/ai-task-manager/config/scripts/find-root.cjs +0 -10
  60. package/templates/ai-task-manager/config/scripts/get-next-plan-id.cjs +0 -49
  61. package/templates/ai-task-manager/config/scripts/get-next-task-id.cjs +0 -81
  62. package/templates/ai-task-manager/config/scripts/shared-utils.cjs +0 -418
  63. package/templates/ai-task-manager/config/scripts/validate-plan-blueprint.cjs +0 -138
  64. package/templates/assistant/commands/tasks/create-plan-auto.md +0 -174
  65. package/templates/assistant/commands/tasks/create-plan.md +0 -175
  66. package/templates/assistant/commands/tasks/execute-blueprint.md +0 -233
  67. package/templates/assistant/commands/tasks/execute-task.md +0 -351
  68. package/templates/assistant/commands/tasks/fix-broken-tests.md +0 -44
  69. package/templates/assistant/commands/tasks/full-workflow.md +0 -849
  70. package/templates/assistant/commands/tasks/generate-tasks.md +0 -348
  71. package/templates/assistant/commands/tasks/refine-plan-auto.md +0 -172
  72. 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
+ ```