@e0ipso/ai-task-manager 1.36.1 → 1.38.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,205 @@
1
+ ---
2
+ name: task-refine-plan
3
+ description: Refine an existing AI Task Manager plan in this repository. Use when the user asks to review, improve, interrogate, or update a specific plan ID — discovers the local .ai/task-manager root, resolves the plan, runs the project's plan hooks, pressure-tests the document for gaps and contradictions, gathers clarifications interactively or autonomously, and updates the plan in-place while preserving its identity and structure. Do not use for creating new plans or for generic brainstorming outside the AI Task Manager.
4
+ ---
5
+
6
+ # task-refine-plan
7
+
8
+ Drive the end-to-end refinement of an existing AI Task Manager plan. The skill
9
+ is assistant-agnostic and self-contained: every script it invokes lives under
10
+ this skill's `scripts/` directory and is referenced by relative path.
11
+
12
+ ## Inputs
13
+
14
+ The user supplies the numeric plan ID conversationally, along with any optional
15
+ refinement notes or constraints. Treat the plan ID as the only authoritative
16
+ source of intent. Do not invent answers to clarifying questions — prompt the
17
+ user instead.
18
+
19
+ ## Operating Procedure
20
+
21
+ ### 1. Locate the task-manager root
22
+
23
+ Run `scripts/find-task-manager-root.cjs` from the user's working directory.
24
+ The script walks up looking for `.ai/task-manager/.init-metadata.json` and
25
+ prints the absolute path of the resolved root on success.
26
+
27
+ If the script exits non-zero, the working directory is not inside an
28
+ initialized task-manager workspace. Stop and ask the user to run the project
29
+ initializer (e.g. `npx @e0ipso/ai-task-manager init`) before continuing. Do
30
+ not attempt to refine a plan outside of a valid root.
31
+
32
+ For every subsequent step, treat the path printed by this script as `<root>`.
33
+
34
+ ### 2. Resolve the plan
35
+
36
+ Run `scripts/validate-plan-blueprint.cjs <plan-id> planFile` to obtain the
37
+ absolute path of the plan file. The same script also accepts these field
38
+ names (single-field output mode) and exposes them on demand:
39
+
40
+ - `planDir` — absolute path of the plan directory
41
+ - `taskCount` — number of existing task files in that plan's `tasks/`
42
+ - `blueprintExists` — `yes` or `no`
43
+ - `taskManagerRoot` — absolute path of `<root>`
44
+ - `planId` — the resolved numeric plan ID
45
+
46
+ If the script exits non-zero, stop and ask the user to confirm the plan ID.
47
+ Do not guess a different ID.
48
+
49
+ ### 3. Load project context
50
+
51
+ Read these files, in order:
52
+
53
+ - `<root>/config/TASK_MANAGER.md` — directory conventions and project context.
54
+ - `<root>/config/hooks/PRE_PLAN.md` — execute the instructions it contains
55
+ before proceeding.
56
+ - `<root>/config/templates/PLAN_TEMPLATE.md` — the structural baseline the
57
+ refined plan must continue to conform to.
58
+
59
+ ### 4. Baseline Review
60
+
61
+ Read the entire plan end-to-end. Without modifying the file:
62
+
63
+ 1. Capture key metadata (plan title, summary, creation date, related initiatives).
64
+ 2. Surface the strongest sections, contradictions, and potential risks.
65
+ 3. Identify gaps using these lenses:
66
+ - **Context gaps**: missing background, assumptions, competing priorities.
67
+ - **Technical gaps**: underspecified architecture, unclear interfaces, missing diagrams.
68
+ - **Risk gaps**: untracked risks, missing mitigations, hand-wavy success metrics.
69
+ - **Scope issues**: gold-plating, ambiguous boundaries, requirements that
70
+ contradict YAGNI.
71
+
72
+ Document each gap with `{section, issue, severity, proposed fix}` so you can
73
+ reference it when refining the plan.
74
+
75
+ ### 5. Clarification Loop
76
+
77
+ **Default to Interactive Clarification.** Only switch to **Autonomous
78
+ Clarification** when the trigger is unambiguous and beyond reasonable doubt.
79
+ Treat ambiguity as a vote for Interactive: asking a question the user
80
+ cannot answer is recoverable; making silent assumptions when the user
81
+ expected to be consulted is not.
82
+
83
+ Switch to Autonomous Clarification only if at least one of the following
84
+ holds without interpretation:
85
+
86
+ - The user's request contains an explicit, unambiguous mode keyword such
87
+ as "auto", "autonomous", "non-interactive", "without asking me", "don't
88
+ ask", or equivalent phrasing that names the mode by intent.
89
+ - An upstream orchestrator (for example the `task-full-workflow` skill)
90
+ has declared autonomous operation for this invocation in the prompt
91
+ passed to this skill.
92
+ - The skill is invoked in auto mode (for example by the `task-full-workflow`
93
+ orchestrator or by a caller that explicitly requests autonomous operation).
94
+
95
+ If none of the above holds, use Interactive Clarification even when the
96
+ user's presence is uncertain. Do not infer autonomous mode from indirect
97
+ signals such as terse prompts, scripted-looking input, or absence of
98
+ recent user messages.
99
+
100
+ After the clarification loop completes, append all new findings to the
101
+ "Plan Clarifications" section in the plan document using the existing format
102
+ (table with question/answer pairs). Mark the source of each entry
103
+ appropriately.
104
+
105
+ #### Interactive Clarification
106
+
107
+ Think harder before interrupting the user — only trigger this loop when you
108
+ can cite concrete uncertainties.
109
+
110
+ 1. Review the gaps documented in the Baseline Review.
111
+ 2. If no gaps remain, stop here and proceed to Stage 6.
112
+ 3. Build a clarification packet grouped by theme.
113
+ 4. Prefill each question with the most plausible answer so the user can
114
+ confirm or deny quickly.
115
+ 5. Always include an "Other / open-ended" option to capture nuances you did
116
+ not anticipate.
117
+ 6. **STOP AND ASK**: Present the clarification packet to the user. You must
118
+ halt execution here and await user input. Do not simulate the user's
119
+ response. Do not proceed to Stage 6 until you have received explicit answers.
120
+ 7. After receiving answers, record them in the Plan Clarifications table.
121
+ If the user cannot answer a question, record it as unresolved with
122
+ mitigation notes so downstream assistants know the risk.
123
+ 8. Re-evaluate whether new gaps emerged from the answers. If so, repeat
124
+ this loop.
125
+
126
+ #### Autonomous Clarification
127
+
128
+ Think harder before flagging gaps — only document concrete uncertainties
129
+ you can cite.
130
+
131
+ 1. Review the gaps documented in the Baseline Review.
132
+ 2. For each gap, attempt to resolve it by:
133
+ - Inspecting the codebase, configuration files, and documentation.
134
+ - Analyzing existing patterns and conventions in the project.
135
+ - Reviewing assistant documents and README files.
136
+ - Making reasonable assumptions based on common practices and project
137
+ context.
138
+ 3. Record all resolutions in the Plan Clarifications table. Mark each
139
+ entry's source as either "auto-resolved" (confirmed via codebase) or
140
+ "assumption" (best-effort guess with rationale).
141
+ 4. For truly unresolvable questions, record them as unresolved with
142
+ mitigation notes so downstream assistants know the risk.
143
+ 5. If no gaps remain (or all have been resolved or documented), proceed to
144
+ Stage 6.
145
+
146
+ ### 6. Refinement Implementation
147
+
148
+ Once you have sufficient context (or have documented all missing context),
149
+ refine the plan directly in-place. The plan file path is the one returned by
150
+ step 2.
151
+
152
+ 1. **Maintain Identity**: Keep the existing `id` and directory. Do not create
153
+ a new plan ID. Do not move the plan to a new location.
154
+ 2. **Structure Compliance**: Ensure the plan still follows
155
+ `<root>/config/templates/PLAN_TEMPLATE.md`. Add missing sections if
156
+ necessary.
157
+ 3. **Content Updates**:
158
+ - Refresh the executive summary to reflect clarifications and new insights.
159
+ - Update architectural sections, diagrams, and risk mitigations to resolve
160
+ the identified gaps.
161
+ - Trim any scope creep that is not explicitly required.
162
+ - Clearly reference clarifications in the relevant plan sections (e.g.,
163
+ italicized notes that point back to the Q&A table).
164
+ 4. **Net-New Sections**: If the plan needs a new subsection (e.g., Decision
165
+ Log, Data Contracts), add it under `Notes` with a clearly labeled section
166
+ so it remains discoverable.
167
+ 5. **Change Log**: Append a bullet list in the `Notes` section that briefly
168
+ states what changed in this refinement session (e.g.,
169
+ `- 2025-03-16: Clarified auth flow tokens and updated architecture diagram`).
170
+ 6. **Validation Hooks**: Execute `<root>/config/hooks/POST_PLAN.md` to ensure
171
+ the refined plan still meets quality bars.
172
+
173
+ ### 7. Run the post-plan hook
174
+
175
+ Execute `<root>/config/hooks/POST_PLAN.md` after the plan file is updated.
176
+
177
+ ### 8. Emit the structured summary
178
+
179
+ Conclude with exactly this block as the final output:
180
+
181
+ ```
182
+ ---
183
+
184
+ Plan Refinement Summary:
185
+ - Plan ID: [numeric-id]
186
+ - Plan File: [absolute-path-to-plan-file]
187
+ ```
188
+
189
+ The summary is consumed by downstream automation; keep the format exact.
190
+
191
+ ## Failure Modes
192
+
193
+ - **No task-manager root found.** Stop and instruct the user to initialize the
194
+ project. Do not read or write any plan files.
195
+ - **Plan ID does not resolve.** Stop and surface the script's stderr to the
196
+ user. Do not guess a different ID and do not read or write any files.
197
+ - **User refuses to answer a clarifying question that blocks refinement.**
198
+ Record the unresolved question in the Plan Clarifications table with
199
+ mitigation notes, proceed with available context, and flag the remaining
200
+ risk in the Refinement Report.
201
+ - **A helper script fails unexpectedly.** Surface stderr to the user and
202
+ stop — do not fall back to manual path discovery.
203
+ - **Plan file is missing after resolution.** This indicates a consistency
204
+ issue in the task-manager workspace. Stop and report the error without
205
+ attempting to recreate the plan.
@@ -0,0 +1,116 @@
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/find-task-manager-root.ts
31
+ var find_task_manager_root_exports = {};
32
+ __export(find_task_manager_root_exports, {
33
+ main: () => main
34
+ });
35
+ module.exports = __toCommonJS(find_task_manager_root_exports);
36
+
37
+ // src/skill-scripts/shared/root.ts
38
+ var fs = __toESM(require("fs"));
39
+ var path = __toESM(require("path"));
40
+ var EXPECTED_SCHEMA = true ? 1 : 1;
41
+ var isValidTaskManagerRoot = (taskManagerPath) => {
42
+ try {
43
+ if (!fs.existsSync(taskManagerPath)) return false;
44
+ if (!fs.lstatSync(taskManagerPath).isDirectory()) return false;
45
+ const metadataPath = path.join(taskManagerPath, ".init-metadata.json");
46
+ if (!fs.existsSync(metadataPath)) return false;
47
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, "utf8"));
48
+ return metadata && typeof metadata === "object" && "version" in metadata;
49
+ } catch (_err) {
50
+ return false;
51
+ }
52
+ };
53
+ var getTaskManagerAt = (directory) => {
54
+ const taskManagerPath = path.join(directory, ".ai", "task-manager");
55
+ return isValidTaskManagerRoot(taskManagerPath) ? taskManagerPath : null;
56
+ };
57
+ var getParentPaths = (currentPath, acc = []) => {
58
+ const absolutePath = path.resolve(currentPath);
59
+ const nextAcc = [...acc, absolutePath];
60
+ const parentPath = path.dirname(absolutePath);
61
+ if (parentPath === absolutePath) return nextAcc;
62
+ return getParentPaths(parentPath, nextAcc);
63
+ };
64
+ var checkWorkspaceSchema = (metadataPath) => {
65
+ let metadata;
66
+ try {
67
+ metadata = JSON.parse(fs.readFileSync(metadataPath, "utf8"));
68
+ } catch {
69
+ return;
70
+ }
71
+ const actual = typeof metadata.workspaceSchemaVersion === "number" ? metadata.workspaceSchemaVersion : 1;
72
+ if (actual === EXPECTED_SCHEMA) return;
73
+ if (actual < EXPECTED_SCHEMA) {
74
+ process.stderr.write(
75
+ `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.
76
+ `
77
+ );
78
+ } else {
79
+ process.stderr.write(
80
+ `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.
81
+ `
82
+ );
83
+ }
84
+ process.exit(1);
85
+ };
86
+ var findTaskManagerRoot = (startPath = process.cwd()) => {
87
+ const paths = getParentPaths(startPath);
88
+ const found = paths.find((p) => getTaskManagerAt(p));
89
+ if (!found) return null;
90
+ const root = getTaskManagerAt(found);
91
+ if (root) checkWorkspaceSchema(path.join(root, ".init-metadata.json"));
92
+ return root;
93
+ };
94
+
95
+ // src/skill-scripts/find-task-manager-root.ts
96
+ var main = () => {
97
+ const startPath = process.argv[2] || process.cwd();
98
+ const root = findTaskManagerRoot(startPath);
99
+ if (!root) {
100
+ process.stderr.write(
101
+ `Could not find .ai/task-manager root from ${startPath} or any parent directory.
102
+ `
103
+ );
104
+ process.exit(1);
105
+ }
106
+ process.stdout.write(`${root}
107
+ `);
108
+ process.exit(0);
109
+ };
110
+ if (require.main === module) {
111
+ main();
112
+ }
113
+ // Annotate the CommonJS export names for ESM import in node:
114
+ 0 && (module.exports = {
115
+ main
116
+ });