strikethroo 3.7.0 → 3.9.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 (97) hide show
  1. package/README.md +12 -12
  2. package/dist/index.js +1 -1
  3. package/dist/metadata.d.ts +1 -1
  4. package/dist/metadata.js +1 -1
  5. package/dist/serve/derivation.d.ts +1 -0
  6. package/dist/serve/derivation.d.ts.map +1 -1
  7. package/dist/serve/derivation.js +1 -0
  8. package/dist/serve/derivation.js.map +1 -1
  9. package/dist/serve/markdown.d.ts +1 -12
  10. package/dist/serve/markdown.d.ts.map +1 -1
  11. package/dist/serve/markdown.js +9 -2
  12. package/dist/serve/markdown.js.map +1 -1
  13. package/dist/skill-scripts/shared/complexity-score.d.ts +14 -0
  14. package/dist/skill-scripts/shared/complexity-score.d.ts.map +1 -0
  15. package/dist/skill-scripts/shared/complexity-score.js +21 -0
  16. package/dist/skill-scripts/shared/complexity-score.js.map +1 -0
  17. package/dist/skill-scripts/shared/root.js +1 -1
  18. package/dist-web/assets/{arc-xFaTbwSI.js → arc-U8dalZIB.js} +1 -1
  19. package/dist-web/assets/{architectureDiagram-3BPJPVTR-Xz0i2dF0.js → architectureDiagram-3BPJPVTR-BII4UusQ.js} +1 -1
  20. package/dist-web/assets/{blockDiagram-GPEHLZMM-BdKR7Rki.js → blockDiagram-GPEHLZMM-DY4WZYhw.js} +1 -1
  21. package/dist-web/assets/{c4Diagram-AAUBKEIU-DAayjcH7.js → c4Diagram-AAUBKEIU-ByZWkPq5.js} +1 -1
  22. package/dist-web/assets/channel-hoQZJ4FP.js +1 -0
  23. package/dist-web/assets/{chunk-2J33WTMH-D4OfjzqG.js → chunk-2J33WTMH-BkTWBAb4.js} +1 -1
  24. package/dist-web/assets/{chunk-4BX2VUAB-Ds6twHLE.js → chunk-4BX2VUAB-CQkRWCB3.js} +1 -1
  25. package/dist-web/assets/{chunk-55IACEB6-CoVGj0A6.js → chunk-55IACEB6-C-6bW0I1.js} +1 -1
  26. package/dist-web/assets/{chunk-727SXJPM--kGZcEL_.js → chunk-727SXJPM-C4TUUt4s.js} +1 -1
  27. package/dist-web/assets/{chunk-AQP2D5EJ-dK8X6Knv.js → chunk-AQP2D5EJ-Dtp8JWF7.js} +1 -1
  28. package/dist-web/assets/{chunk-FMBD7UC4-CIkH8fwk.js → chunk-FMBD7UC4-BwHFSRRs.js} +1 -1
  29. package/dist-web/assets/{chunk-ND2GUHAM-BqrY0fV2.js → chunk-ND2GUHAM-Cig_3TB-.js} +1 -1
  30. package/dist-web/assets/{chunk-QZHKN3VN-Bx8TPE1r.js → chunk-QZHKN3VN-BGETuJY7.js} +1 -1
  31. package/dist-web/assets/classDiagram-4FO5ZUOK-B0lk8Y6z.js +1 -0
  32. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-B0lk8Y6z.js +1 -0
  33. package/dist-web/assets/{cose-bilkent-S5V4N54A-PyZxi1yI.js → cose-bilkent-S5V4N54A-DuOybbaS.js} +1 -1
  34. package/dist-web/assets/{dagre-BM42HDAG-yXPAIOqC.js → dagre-BM42HDAG-VnC37qtr.js} +1 -1
  35. package/dist-web/assets/{diagram-2AECGRRQ-DDkzzAIo.js → diagram-2AECGRRQ-Ty7SQMgH.js} +1 -1
  36. package/dist-web/assets/{diagram-5GNKFQAL-BD_aXIRb.js → diagram-5GNKFQAL-BlKDu0VW.js} +1 -1
  37. package/dist-web/assets/{diagram-KO2AKTUF-rntOw_IG.js → diagram-KO2AKTUF-Bbg0OCZg.js} +1 -1
  38. package/dist-web/assets/{diagram-LMA3HP47-BAB3HQQs.js → diagram-LMA3HP47-kkVpRIsu.js} +1 -1
  39. package/dist-web/assets/{diagram-OG6HWLK6-CwTzozdw.js → diagram-OG6HWLK6-DOWYkZlS.js} +1 -1
  40. package/dist-web/assets/{erDiagram-TEJ5UH35-BW-Ha54s.js → erDiagram-TEJ5UH35-D8WlLdtK.js} +1 -1
  41. package/dist-web/assets/{flowDiagram-I6XJVG4X-AGkxH_mx.js → flowDiagram-I6XJVG4X-U7NYonjl.js} +1 -1
  42. package/dist-web/assets/{ganttDiagram-6RSMTGT7--ZS9LkZ2.js → ganttDiagram-6RSMTGT7-vw1uFVh5.js} +1 -1
  43. package/dist-web/assets/{gitGraphDiagram-PVQCEYII-D4KfIxPI.js → gitGraphDiagram-PVQCEYII-Coc0d6Bs.js} +1 -1
  44. package/dist-web/assets/{index-uk0kSvAs.js → index-4vwdK2qG.js} +4 -4
  45. package/dist-web/assets/{index-IHSMZO2U.js → index-D53fh0zY.js} +1 -1
  46. package/dist-web/assets/{index-BN30VZfQ.js → index-TwwNd18Z.js} +1 -1
  47. package/dist-web/assets/{infoDiagram-5YYISTIA-D_Z40zdo.js → infoDiagram-5YYISTIA-D1rd3cgn.js} +1 -1
  48. package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-CGzxJ2vS.js → ishikawaDiagram-YF4QCWOH-C6QHofgd.js} +1 -1
  49. package/dist-web/assets/{journeyDiagram-JHISSGLW-DLtpX1Ni.js → journeyDiagram-JHISSGLW-CfCP3_lL.js} +1 -1
  50. package/dist-web/assets/{kanban-definition-UN3LZRKU-C4_O7GEC.js → kanban-definition-UN3LZRKU-eK9aAtUE.js} +1 -1
  51. package/dist-web/assets/{linear-BoMijEDN.js → linear-Xl4NTVLR.js} +1 -1
  52. package/dist-web/assets/{mermaid.core-B7AM5BmV.js → mermaid.core-Bpv3Fy5r.js} +4 -4
  53. package/dist-web/assets/{mindmap-definition-RKZ34NQL-b8o1AjHb.js → mindmap-definition-RKZ34NQL-C-UftEj-.js} +1 -1
  54. package/dist-web/assets/{pieDiagram-4H26LBE5-D7BGsvW4.js → pieDiagram-4H26LBE5--B3LdTQd.js} +1 -1
  55. package/dist-web/assets/{quadrantDiagram-W4KKPZXB-BOsVmBQ_.js → quadrantDiagram-W4KKPZXB-DTr-7cow.js} +1 -1
  56. package/dist-web/assets/{requirementDiagram-4Y6WPE33-BwuELhlD.js → requirementDiagram-4Y6WPE33-CMKPuFbL.js} +1 -1
  57. package/dist-web/assets/{sankeyDiagram-5OEKKPKP-DDoQnSJz.js → sankeyDiagram-5OEKKPKP-DnThFDZc.js} +1 -1
  58. package/dist-web/assets/{sequenceDiagram-3UESZ5HK-Dto9SgGd.js → sequenceDiagram-3UESZ5HK-WqT16YFF.js} +1 -1
  59. package/dist-web/assets/{stateDiagram-AJRCARHV-Dx0qn_5x.js → stateDiagram-AJRCARHV-5nr9Um5q.js} +1 -1
  60. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-Doh4LSg5.js +1 -0
  61. package/dist-web/assets/{timeline-definition-PNZ67QCA-Dbhzc3Xh.js → timeline-definition-PNZ67QCA-CNOVn_B3.js} +1 -1
  62. package/dist-web/assets/{vennDiagram-CIIHVFJN-BEUtD6fT.js → vennDiagram-CIIHVFJN-D-h0Gph6.js} +1 -1
  63. package/dist-web/assets/{wardley-L42UT6IY-CqNfcWnP.js → wardley-L42UT6IY-C1fuBpoj.js} +1 -1
  64. package/dist-web/assets/{wardleyDiagram-YWT4CUSO-Co_bCOQZ.js → wardleyDiagram-YWT4CUSO-BauL5Z2B.js} +1 -1
  65. package/dist-web/assets/{xychartDiagram-2RQKCTM6-CguzZIIB.js → xychartDiagram-2RQKCTM6-Z9Z3wS3v.js} +1 -1
  66. package/dist-web/index.html +1 -1
  67. package/package.json +1 -1
  68. package/templates/harness/skills/st-create-plan/scripts/find-strikethroo-root.cjs +1 -1
  69. package/templates/harness/skills/st-create-plan/scripts/get-next-plan-id.cjs +1 -1
  70. package/templates/harness/skills/st-execute-blueprint/SKILL.md +1 -1
  71. package/templates/harness/skills/st-execute-blueprint/scripts/check-phase-readiness.cjs +1 -1
  72. package/templates/harness/skills/st-execute-blueprint/scripts/create-feature-branch.cjs +1 -1
  73. package/templates/harness/skills/st-execute-blueprint/scripts/find-strikethroo-root.cjs +1 -1
  74. package/templates/harness/skills/st-execute-blueprint/scripts/validate-plan-blueprint.cjs +93 -22
  75. package/templates/harness/skills/st-execute-task/scripts/check-task-dependencies.cjs +1 -1
  76. package/templates/harness/skills/st-execute-task/scripts/find-strikethroo-root.cjs +1 -1
  77. package/templates/harness/skills/st-execute-task/scripts/validate-plan-blueprint.cjs +93 -22
  78. package/templates/harness/skills/st-full-workflow/SKILL.md +56 -10
  79. package/templates/harness/skills/st-full-workflow/scripts/check-phase-readiness.cjs +1 -1
  80. package/templates/harness/skills/st-full-workflow/scripts/create-feature-branch.cjs +1 -1
  81. package/templates/harness/skills/st-full-workflow/scripts/find-strikethroo-root.cjs +1 -1
  82. package/templates/harness/skills/st-full-workflow/scripts/get-next-plan-id.cjs +1 -1
  83. package/templates/harness/skills/st-full-workflow/scripts/get-next-task-id.cjs +1 -1
  84. package/templates/harness/skills/st-full-workflow/scripts/validate-plan-blueprint.cjs +93 -22
  85. package/templates/harness/skills/st-generate-tasks/SKILL.md +56 -11
  86. package/templates/harness/skills/st-generate-tasks/scripts/find-strikethroo-root.cjs +1 -1
  87. package/templates/harness/skills/st-generate-tasks/scripts/get-next-task-id.cjs +1 -1
  88. package/templates/harness/skills/st-generate-tasks/scripts/validate-plan-blueprint.cjs +93 -22
  89. package/templates/harness/skills/st-refine-plan/scripts/find-strikethroo-root.cjs +1 -1
  90. package/templates/harness/skills/st-refine-plan/scripts/validate-plan-blueprint.cjs +93 -22
  91. package/templates/strikethroo/README.md +1 -1
  92. package/templates/strikethroo/config/hooks/POST_TASK_GENERATION_ALL.md +3 -13
  93. package/templates/strikethroo/config/templates/TASK_TEMPLATE.md +1 -0
  94. package/dist-web/assets/channel-Cmb5ngmL.js +0 -1
  95. package/dist-web/assets/classDiagram-4FO5ZUOK-Dh2pEfOy.js +0 -1
  96. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-Dh2pEfOy.js +0 -1
  97. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-qo6que2v.js +0 -1
@@ -160,7 +160,42 @@ A task B depends on A if B requires A's output or artifacts, modifies code
160
160
  created by A, or tests functionality implemented by A. Validate that the
161
161
  final dependency graph is acyclic.
162
162
 
163
- ### 8. Allocate task IDs
163
+ ### 8. Complexity analysis
164
+
165
+ For every candidate task, assign a `complexity_score` (integer 1–10) before
166
+ writing any file. Base the score on these four dimensions:
167
+
168
+ | Score | Skill breadth | Acceptance-criteria clarity | Integration surface | Decomposition depth |
169
+ | --- | --- | --- | --- | --- |
170
+ | 1–3 | One well-known skill | Criteria are concrete and observable | None or a single file/module | No further split possible |
171
+ | 4–5 | One primary skill plus a familiar adjacent skill | Criteria are clear with few edge cases | One component or API boundary | Already atomic |
172
+ | 6–7 | Two distinct skills, or one skill with ambiguous requirements | Criteria need clarification or have multiple edge cases | Multiple components or contracts | Could still be split |
173
+ | 8–10 | Three or more skills, or cross-cutting design decisions | Criteria are vague, unknown, or depend on unresolved choices | Wide integration surface or external systems | Must be decomposed further |
174
+
175
+ **Pre-emission sanity rules** — apply these before any task is written:
176
+
177
+ - 3+ skills assigned → split the task into smaller tasks, each with 1–2 skills.
178
+ - Vague acceptance criteria → sharpen them until they include at least one
179
+ concrete, runnable verification step.
180
+ - Trivially small adjacent tasks → merge them into a single task.
181
+ - Score ≥ 8 → decompose further; do not emit as-is.
182
+ - Score 6–7 → either sharpen criteria or split; do not emit without an
183
+ explicit reason.
184
+
185
+ **Required frontmatter:**
186
+
187
+ - Every emitted task MUST include `complexity_score` (integer 1–10).
188
+ - Optionally include `complexity_notes` when the score needs justification,
189
+ such as "Ambiguous API contract" or "Decomposed from a higher-score parent".
190
+
191
+ **Loop-back rule:**
192
+
193
+ After applying split, sharpen, or merge, re-run dependency analysis and
194
+ re-score the adjusted tasks. Repeat this loop no more than three times. If
195
+ complexity is still unresolved after three passes, stop and surface the
196
+ blocker to the user.
197
+
198
+ ### 9. Allocate task IDs
164
199
 
165
200
  Run `scripts/get-next-task-id.cjs <plan-id>` to obtain the first available
166
201
  task ID. Allocate subsequent IDs by incrementing in-process; do not invoke
@@ -170,7 +205,7 @@ field and the zero-padded form (`{padded-id}--{slug}`) for the filename.
170
205
  The slug derives from a short task title: lowercase, alphanumeric and
171
206
  hyphens only, collapsed, trimmed.
172
207
 
173
- ### 9. Emit the task files
208
+ ### 10. Emit the task files
174
209
 
175
210
  Write each task to:
176
211
 
@@ -188,11 +223,15 @@ including required frontmatter fields:
188
223
  - `created` (YYYY-MM-DD)
189
224
  - `skills` (array of 1–2 kebab-case skills)
190
225
 
191
- Optional frontmatter for high-complexity or decomposed tasks:
226
+ Required additional frontmatter:
227
+
228
+ - `complexity_score` (integer 1–10, required on every emitted task)
229
+
230
+ Optional frontmatter:
192
231
 
193
- - `complexity_score` (number, 1–10, include only if >4 or for decomposed
194
- tasks)
195
- - `complexity_notes` (string)
232
+ - `complexity_notes` (string) — include when the score needs justification,
233
+ such as "Decomposed from a cross-cutting parent task" or "Ambiguous API
234
+ contract".
196
235
 
197
236
  The body sections (Objective, Skills Required, Acceptance Criteria, Technical
198
237
  Requirements, Input Dependencies, Output Artifacts, Implementation Notes)
@@ -200,7 +239,7 @@ must be filled with task-specific content. Place detailed implementation
200
239
  guidance inside a `<details>` block under "Implementation Notes" — write it
201
240
  so a non-thinking LLM could execute the task from that section alone.
202
241
 
203
- ### 10. Validation checklist
242
+ ### 11. Validation checklist
204
243
 
205
244
  Before declaring task generation complete, verify:
206
245
 
@@ -218,21 +257,27 @@ Before declaring task generation complete, verify:
218
257
  - Minimization applied (20–30% reduction target).
219
258
  - Test tasks focus on business logic, not framework functionality.
220
259
  - No gold-plating: only plan requirements are addressed.
260
+ - After writing the task files, run
261
+ `scripts/validate-plan-blueprint.cjs <plan-id> complexityScoresValid`. Stop
262
+ unless it prints `yes`; if it prints `no`, run
263
+ `scripts/validate-plan-blueprint.cjs <plan-id> invalidComplexityTasks` to see
264
+ which files are missing, non-integer, or out-of-range, fix them, and re-run.
265
+ Every generated task must carry an integer `complexity_score` from 1 to 10.
266
+ - Add `complexity_notes` only when a score needs explanation (typically atomic
267
+ tasks scoring greater than 4).
221
268
 
222
- ### 11. Run the POST_TASK_GENERATION_ALL hook
269
+ ### 12. Run the POST_TASK_GENERATION_ALL hook
223
270
 
224
271
  Read `<root>/config/hooks/POST_TASK_GENERATION_ALL.md` and follow its
225
272
  instructions. This typically requires:
226
273
 
227
- - Sanity-checking complexity (3+ technologies/skills → split; vague criteria
228
- → sharpen; trivially small → merge).
229
274
  - Appending an Execution Blueprint section to the plan document, including a
230
275
  Mermaid dependency diagram and explicit phase groupings (Phase 1 contains
231
276
  zero-dependency tasks; each subsequent phase contains tasks whose
232
277
  dependencies all live in earlier phases). Use
233
278
  `<root>/config/templates/BLUEPRINT_TEMPLATE.md` for structure.
234
279
 
235
- ### 12. Emit the structured summary
280
+ ### 13. Emit the structured summary
236
281
 
237
282
  Conclude with exactly this block as the final output:
238
283
 
@@ -37,7 +37,7 @@ module.exports = __toCommonJS(find_strikethroo_root_exports);
37
37
  // src/skill-scripts/shared/root.ts
38
38
  var fs = __toESM(require("fs"));
39
39
  var path = __toESM(require("path"));
40
- var EXPECTED_SCHEMA = true ? 2 : 2;
40
+ var EXPECTED_SCHEMA = true ? 3 : 3;
41
41
  var isValidStrikethrooRoot = (strikethrooPath) => {
42
42
  try {
43
43
  if (!fs.existsSync(strikethrooPath)) return false;
@@ -41,7 +41,7 @@ var path3 = __toESM(require("path"));
41
41
  // src/skill-scripts/shared/root.ts
42
42
  var fs = __toESM(require("fs"));
43
43
  var path = __toESM(require("path"));
44
- var EXPECTED_SCHEMA = true ? 2 : 2;
44
+ var EXPECTED_SCHEMA = true ? 3 : 3;
45
45
  var isValidStrikethrooRoot = (strikethrooPath) => {
46
46
  try {
47
47
  if (!fs.existsSync(strikethrooPath)) return false;
@@ -33,13 +33,11 @@ __export(validate_plan_blueprint_exports, {
33
33
  main: () => main
34
34
  });
35
35
  module.exports = __toCommonJS(validate_plan_blueprint_exports);
36
- var fs4 = __toESM(require("fs"));
37
- var path4 = __toESM(require("path"));
38
36
 
39
37
  // src/skill-scripts/shared/root.ts
40
38
  var fs = __toESM(require("fs"));
41
39
  var path = __toESM(require("path"));
42
- var EXPECTED_SCHEMA = true ? 2 : 2;
40
+ var EXPECTED_SCHEMA = true ? 3 : 3;
43
41
  var isValidStrikethrooRoot = (strikethrooPath) => {
44
42
  try {
45
43
  if (!fs.existsSync(strikethrooPath)) return false;
@@ -242,34 +240,104 @@ var resolvePlan = (input, startPath = process.cwd()) => {
242
240
  return resolveByIdInAncestry(planId, startPath);
243
241
  };
244
242
 
245
- // src/skill-scripts/validate-plan-blueprint.ts
246
- var VALID_FIELDS = [
247
- "planFile",
248
- "planDir",
249
- "taskCount",
250
- "blueprintExists",
251
- "strikethrooRoot",
252
- "planId"
253
- ];
254
- var countTasks = (planDir) => {
243
+ // src/skill-scripts/shared/blueprint-detection.ts
244
+ var fs4 = __toESM(require("fs"));
245
+ var hasExecutionBlueprint = (planFile) => {
246
+ try {
247
+ const content = fs4.readFileSync(planFile, "utf8");
248
+ return /^## Execution Blueprint/m.test(content);
249
+ } catch (_err) {
250
+ return false;
251
+ }
252
+ };
253
+
254
+ // src/skill-scripts/shared/task-count.ts
255
+ var fs5 = __toESM(require("fs"));
256
+ var path4 = __toESM(require("path"));
257
+ var countTaskFiles = (planDir) => {
255
258
  const tasksDir = path4.join(planDir, "tasks");
256
- if (!fs4.existsSync(tasksDir)) return 0;
259
+ if (!fs5.existsSync(tasksDir)) return 0;
257
260
  try {
258
- const stat = fs4.lstatSync(tasksDir);
261
+ const stat = fs5.lstatSync(tasksDir);
259
262
  if (!stat.isDirectory()) return 0;
260
- return fs4.readdirSync(tasksDir).filter((f) => f.endsWith(".md")).length;
263
+ return fs5.readdirSync(tasksDir).filter((f) => f.endsWith(".md")).length;
261
264
  } catch (_err) {
262
265
  return 0;
263
266
  }
264
267
  };
265
- var checkBlueprintExists = (planFile) => {
268
+
269
+ // src/skill-scripts/shared/task-complexity.ts
270
+ var fs6 = __toESM(require("fs"));
271
+ var path5 = __toESM(require("path"));
272
+
273
+ // src/skill-scripts/shared/complexity-score.ts
274
+ var validateComplexityScore = (value) => {
275
+ const trimmed = value.trim();
276
+ if (!/^\d+$/.test(trimmed)) {
277
+ return { valid: false, reason: "non-integer" };
278
+ }
279
+ const parsed = Number.parseInt(trimmed, 10);
280
+ if (parsed < 1 || parsed > 10) {
281
+ return { valid: false, reason: "out-of-range", value: parsed };
282
+ }
283
+ return { valid: true, value: parsed };
284
+ };
285
+
286
+ // src/skill-scripts/shared/task-file.ts
287
+ var extractFrontmatter = (content) => {
288
+ const match = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
289
+ return match && match[1] ? match[1] : null;
290
+ };
291
+
292
+ // src/skill-scripts/shared/task-complexity.ts
293
+ var validateTaskComplexityScores = (planDir) => {
294
+ const tasksDir = path5.join(planDir, "tasks");
295
+ if (!fs6.existsSync(tasksDir)) return [];
296
+ let files;
266
297
  try {
267
- const content = fs4.readFileSync(planFile, "utf8");
268
- return /^## Execution Blueprint/m.test(content);
298
+ if (!fs6.lstatSync(tasksDir).isDirectory()) return [];
299
+ files = fs6.readdirSync(tasksDir).filter((f) => f.endsWith(".md")).sort();
269
300
  } catch (_err) {
270
- return false;
301
+ return [];
271
302
  }
303
+ const invalid = [];
304
+ for (const file of files) {
305
+ let content;
306
+ try {
307
+ content = fs6.readFileSync(path5.join(tasksDir, file), "utf8");
308
+ } catch (_err) {
309
+ invalid.push(`${file}: unreadable`);
310
+ continue;
311
+ }
312
+ const frontmatter = extractFrontmatter(content);
313
+ const match = frontmatter ? frontmatter.match(/^\s*complexity_score\s*:\s*(.*?)\s*(?:#.*)?$/im) : null;
314
+ if (!match || match[1] === void 0) {
315
+ invalid.push(`${file}: missing complexity_score`);
316
+ continue;
317
+ }
318
+ const raw = match[1].trim();
319
+ const result = validateComplexityScore(raw);
320
+ if (result.valid) continue;
321
+ if (result.reason === "non-integer") {
322
+ invalid.push(`${file}: non-integer complexity_score "${raw}"`);
323
+ continue;
324
+ }
325
+ invalid.push(`${file}: complexity_score ${result.value} out of range 1-10`);
326
+ }
327
+ return invalid;
272
328
  };
329
+
330
+ // src/skill-scripts/validate-plan-blueprint.ts
331
+ var VALID_FIELDS = [
332
+ "planFile",
333
+ "planDir",
334
+ "taskCount",
335
+ "blueprintExists",
336
+ "strikethrooRoot",
337
+ "planId",
338
+ "complexityScoresValid",
339
+ "invalidComplexityTasks"
340
+ ];
273
341
  var usage = () => {
274
342
  const lines = [
275
343
  "Plan ID or absolute path is required",
@@ -324,13 +392,16 @@ var main = () => {
324
392
  }
325
393
  process.exit(1);
326
394
  }
395
+ const invalidComplexity = validateTaskComplexityScores(resolved.planDir);
327
396
  const result = {
328
397
  planFile: resolved.planFile,
329
398
  planDir: resolved.planDir,
330
399
  strikethrooRoot: resolved.strikethrooRoot,
331
400
  planId: resolved.planId,
332
- taskCount: countTasks(resolved.planDir),
333
- blueprintExists: checkBlueprintExists(resolved.planFile) ? "yes" : "no"
401
+ taskCount: countTaskFiles(resolved.planDir),
402
+ blueprintExists: hasExecutionBlueprint(resolved.planFile) ? "yes" : "no",
403
+ complexityScoresValid: invalidComplexity.length === 0 ? "yes" : "no",
404
+ invalidComplexityTasks: invalidComplexity.join("; ")
334
405
  };
335
406
  if (fieldName) {
336
407
  if (!VALID_FIELDS.includes(fieldName)) {
@@ -37,7 +37,7 @@ module.exports = __toCommonJS(find_strikethroo_root_exports);
37
37
  // src/skill-scripts/shared/root.ts
38
38
  var fs = __toESM(require("fs"));
39
39
  var path = __toESM(require("path"));
40
- var EXPECTED_SCHEMA = true ? 2 : 2;
40
+ var EXPECTED_SCHEMA = true ? 3 : 3;
41
41
  var isValidStrikethrooRoot = (strikethrooPath) => {
42
42
  try {
43
43
  if (!fs.existsSync(strikethrooPath)) return false;
@@ -33,13 +33,11 @@ __export(validate_plan_blueprint_exports, {
33
33
  main: () => main
34
34
  });
35
35
  module.exports = __toCommonJS(validate_plan_blueprint_exports);
36
- var fs4 = __toESM(require("fs"));
37
- var path4 = __toESM(require("path"));
38
36
 
39
37
  // src/skill-scripts/shared/root.ts
40
38
  var fs = __toESM(require("fs"));
41
39
  var path = __toESM(require("path"));
42
- var EXPECTED_SCHEMA = true ? 2 : 2;
40
+ var EXPECTED_SCHEMA = true ? 3 : 3;
43
41
  var isValidStrikethrooRoot = (strikethrooPath) => {
44
42
  try {
45
43
  if (!fs.existsSync(strikethrooPath)) return false;
@@ -242,34 +240,104 @@ var resolvePlan = (input, startPath = process.cwd()) => {
242
240
  return resolveByIdInAncestry(planId, startPath);
243
241
  };
244
242
 
245
- // src/skill-scripts/validate-plan-blueprint.ts
246
- var VALID_FIELDS = [
247
- "planFile",
248
- "planDir",
249
- "taskCount",
250
- "blueprintExists",
251
- "strikethrooRoot",
252
- "planId"
253
- ];
254
- var countTasks = (planDir) => {
243
+ // src/skill-scripts/shared/blueprint-detection.ts
244
+ var fs4 = __toESM(require("fs"));
245
+ var hasExecutionBlueprint = (planFile) => {
246
+ try {
247
+ const content = fs4.readFileSync(planFile, "utf8");
248
+ return /^## Execution Blueprint/m.test(content);
249
+ } catch (_err) {
250
+ return false;
251
+ }
252
+ };
253
+
254
+ // src/skill-scripts/shared/task-count.ts
255
+ var fs5 = __toESM(require("fs"));
256
+ var path4 = __toESM(require("path"));
257
+ var countTaskFiles = (planDir) => {
255
258
  const tasksDir = path4.join(planDir, "tasks");
256
- if (!fs4.existsSync(tasksDir)) return 0;
259
+ if (!fs5.existsSync(tasksDir)) return 0;
257
260
  try {
258
- const stat = fs4.lstatSync(tasksDir);
261
+ const stat = fs5.lstatSync(tasksDir);
259
262
  if (!stat.isDirectory()) return 0;
260
- return fs4.readdirSync(tasksDir).filter((f) => f.endsWith(".md")).length;
263
+ return fs5.readdirSync(tasksDir).filter((f) => f.endsWith(".md")).length;
261
264
  } catch (_err) {
262
265
  return 0;
263
266
  }
264
267
  };
265
- var checkBlueprintExists = (planFile) => {
268
+
269
+ // src/skill-scripts/shared/task-complexity.ts
270
+ var fs6 = __toESM(require("fs"));
271
+ var path5 = __toESM(require("path"));
272
+
273
+ // src/skill-scripts/shared/complexity-score.ts
274
+ var validateComplexityScore = (value) => {
275
+ const trimmed = value.trim();
276
+ if (!/^\d+$/.test(trimmed)) {
277
+ return { valid: false, reason: "non-integer" };
278
+ }
279
+ const parsed = Number.parseInt(trimmed, 10);
280
+ if (parsed < 1 || parsed > 10) {
281
+ return { valid: false, reason: "out-of-range", value: parsed };
282
+ }
283
+ return { valid: true, value: parsed };
284
+ };
285
+
286
+ // src/skill-scripts/shared/task-file.ts
287
+ var extractFrontmatter = (content) => {
288
+ const match = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
289
+ return match && match[1] ? match[1] : null;
290
+ };
291
+
292
+ // src/skill-scripts/shared/task-complexity.ts
293
+ var validateTaskComplexityScores = (planDir) => {
294
+ const tasksDir = path5.join(planDir, "tasks");
295
+ if (!fs6.existsSync(tasksDir)) return [];
296
+ let files;
266
297
  try {
267
- const content = fs4.readFileSync(planFile, "utf8");
268
- return /^## Execution Blueprint/m.test(content);
298
+ if (!fs6.lstatSync(tasksDir).isDirectory()) return [];
299
+ files = fs6.readdirSync(tasksDir).filter((f) => f.endsWith(".md")).sort();
269
300
  } catch (_err) {
270
- return false;
301
+ return [];
271
302
  }
303
+ const invalid = [];
304
+ for (const file of files) {
305
+ let content;
306
+ try {
307
+ content = fs6.readFileSync(path5.join(tasksDir, file), "utf8");
308
+ } catch (_err) {
309
+ invalid.push(`${file}: unreadable`);
310
+ continue;
311
+ }
312
+ const frontmatter = extractFrontmatter(content);
313
+ const match = frontmatter ? frontmatter.match(/^\s*complexity_score\s*:\s*(.*?)\s*(?:#.*)?$/im) : null;
314
+ if (!match || match[1] === void 0) {
315
+ invalid.push(`${file}: missing complexity_score`);
316
+ continue;
317
+ }
318
+ const raw = match[1].trim();
319
+ const result = validateComplexityScore(raw);
320
+ if (result.valid) continue;
321
+ if (result.reason === "non-integer") {
322
+ invalid.push(`${file}: non-integer complexity_score "${raw}"`);
323
+ continue;
324
+ }
325
+ invalid.push(`${file}: complexity_score ${result.value} out of range 1-10`);
326
+ }
327
+ return invalid;
272
328
  };
329
+
330
+ // src/skill-scripts/validate-plan-blueprint.ts
331
+ var VALID_FIELDS = [
332
+ "planFile",
333
+ "planDir",
334
+ "taskCount",
335
+ "blueprintExists",
336
+ "strikethrooRoot",
337
+ "planId",
338
+ "complexityScoresValid",
339
+ "invalidComplexityTasks"
340
+ ];
273
341
  var usage = () => {
274
342
  const lines = [
275
343
  "Plan ID or absolute path is required",
@@ -324,13 +392,16 @@ var main = () => {
324
392
  }
325
393
  process.exit(1);
326
394
  }
395
+ const invalidComplexity = validateTaskComplexityScores(resolved.planDir);
327
396
  const result = {
328
397
  planFile: resolved.planFile,
329
398
  planDir: resolved.planDir,
330
399
  strikethrooRoot: resolved.strikethrooRoot,
331
400
  planId: resolved.planId,
332
- taskCount: countTasks(resolved.planDir),
333
- blueprintExists: checkBlueprintExists(resolved.planFile) ? "yes" : "no"
401
+ taskCount: countTaskFiles(resolved.planDir),
402
+ blueprintExists: hasExecutionBlueprint(resolved.planFile) ? "yes" : "no",
403
+ complexityScoresValid: invalidComplexity.length === 0 ? "yes" : "no",
404
+ invalidComplexityTasks: invalidComplexity.join("; ")
334
405
  };
335
406
  if (fieldName) {
336
407
  if (!VALID_FIELDS.includes(fieldName)) {
@@ -4,4 +4,4 @@ This directory contains AI-assisted task management files for this project.
4
4
 
5
5
  Managed by the [Strikethroo](https://www.github.com/e0ipso/strikethroo) project.
6
6
 
7
- **Documentation**: https://mateuaguilo.com/strikethroo
7
+ **Documentation**: https://strikethroo.canpicasoft.com
@@ -1,20 +1,10 @@
1
1
  # POST_TASK_GENERATION_ALL Hook
2
2
 
3
- After all tasks have been generated, perform these two steps:
3
+ After all tasks have been generated, update the plan with the execution blueprint.
4
4
 
5
- ## 1. Review Task Complexity
5
+ ## 1. Update Plan with Blueprint
6
6
 
7
- For each generated task, do a quick sanity check:
8
-
9
- - **Too complex?** If a task spans 3+ technologies or requires 3+ skills, split it.
10
- - **Too vague?** If acceptance criteria are unclear, sharpen them.
11
- - **Too trivial?** If two tasks could be one without adding complexity, merge them.
12
-
13
- Target: every task should be completable with 1-2 skills and have clear acceptance criteria.
14
-
15
- ## 2. Update Plan with Blueprint
16
-
17
- After finalizing tasks, append to the plan document:
7
+ Append to the plan document:
18
8
 
19
9
  ### Dependency Diagram
20
10
 
@@ -7,6 +7,7 @@ created: [YYYY-MM-DD]
7
7
  skills: # Technical skills required for this task
8
8
  - [SKILL-1]
9
9
  - [SKILL-2]
10
+ complexity_score: [1-10] # Required on every newly generated task
10
11
  ---
11
12
  # [TASK-TITLE]
12
13
 
@@ -1 +0,0 @@
1
- import{U as a,C as n}from"./mermaid.core-B7AM5BmV.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,a as s,c as e,C as t}from"./chunk-727SXJPM--kGZcEL_.js";import{b as i}from"./mermaid.core-B7AM5BmV.js";import"./chunk-FMBD7UC4-CIkH8fwk.js";import"./chunk-ND2GUHAM-BqrY0fV2.js";import"./chunk-55IACEB6-CoVGj0A6.js";import"./chunk-2J33WTMH-D4OfjzqG.js";import"./index-uk0kSvAs.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- import{s as a,a as s,c as e,C as t}from"./chunk-727SXJPM--kGZcEL_.js";import{b as i}from"./mermaid.core-B7AM5BmV.js";import"./chunk-FMBD7UC4-CIkH8fwk.js";import"./chunk-ND2GUHAM-BqrY0fV2.js";import"./chunk-55IACEB6-CoVGj0A6.js";import"./chunk-2J33WTMH-D4OfjzqG.js";import"./index-uk0kSvAs.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +0,0 @@
1
- import{b as e,a as r,s as a,S as s}from"./chunk-AQP2D5EJ-dK8X6Knv.js";import{b as i}from"./mermaid.core-B7AM5BmV.js";import"./chunk-55IACEB6-CoVGj0A6.js";import"./chunk-2J33WTMH-D4OfjzqG.js";import"./index-uk0kSvAs.js";var u={parser:a,get db(){return new s(2)},renderer:r,styles:e,init:i(t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute},"init")};export{u as diagram};