@namewta/speculo 0.8.5 → 0.8.7

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 (130) hide show
  1. package/README.md +4 -3
  2. package/dist/src/structured.js +162 -4
  3. package/dist/src/structured.js.map +1 -1
  4. package/package.json +2 -2
  5. package/template/canonical/canonical-specdev-goal-plan.md +14 -15
  6. package/template/canonical/canonical-specdev-grill-with-docs.md +9 -8
  7. package/template/canonical/canonical-specdev-spec.md +9 -8
  8. package/template/canonical/canonical-specdev-tickets.md +13 -14
  9. package/template/canonical/canonical-specdev-wayfinder.md +7 -7
  10. package/template/commands/status.md +3 -3
  11. package/template/skills/archive-and-consolidate/SKILL.md +19 -14
  12. package/template/workflows/learning/A-archive-and-consolidate/A-archive-and-consolidate.md +38 -0
  13. package/template/workflows/learning/A-archive-and-consolidate/promotion-plan-template.md +23 -0
  14. package/template/workflows/learning/A-assess-and-plan/A-assess-and-plan.md +39 -0
  15. package/template/workflows/learning/A-assess-and-plan/change-status-template.json +28 -0
  16. package/template/workflows/learning/A-assess-and-plan/learning-plan-template.md +28 -0
  17. package/template/workflows/learning/E-eli5/E-eli5.md +37 -0
  18. package/template/workflows/learning/E-eli5/lesson-template.md +31 -0
  19. package/template/workflows/learning/I-init-setup/I-init-setup.md +36 -0
  20. package/template/workflows/learning/I-init-setup/context-index-template.md +6 -0
  21. package/template/workflows/learning/I-init-setup/learner-profile-template.md +17 -0
  22. package/template/workflows/learning/I-init-setup/review-index-template.md +4 -0
  23. package/template/workflows/learning/INDEX.md +26 -0
  24. package/template/workflows/learning/P-practice/P-practice.md +34 -0
  25. package/template/workflows/learning/P-practice/practice-template.md +16 -0
  26. package/template/workflows/learning/Q-quiz/Q-quiz.md +34 -0
  27. package/template/workflows/learning/Q-quiz/quiz-artifact-template.md +16 -0
  28. package/template/workflows/learning/R-review/R-review.md +35 -0
  29. package/template/workflows/learning/R-review/review-template.md +12 -0
  30. package/template/workflows/learning/README.md +121 -0
  31. package/template/workflows/learning/_state/archive/.gitkeep +1 -0
  32. package/template/workflows/learning/_state/changes/.gitkeep +1 -0
  33. package/template/workflows/learning/_state/status.json +6 -0
  34. package/template/workflows/learning/common/rules/artifact-contract.md +27 -0
  35. package/template/workflows/learning/common/rules/assessment-policy.md +7 -0
  36. package/template/workflows/learning/common/rules/knowledge-organization.md +9 -0
  37. package/template/workflows/learning/common/rules/mastery-policy.md +21 -0
  38. package/template/workflows/learning/common/rules/path-reference-contract.md +7 -0
  39. package/template/workflows/learning/common/rules/teaching-policy.md +15 -0
  40. package/template/workflows/learning/common/schemas/change-status.schema.json +41 -0
  41. package/template/workflows/learning/common/schemas/status.schema.json +32 -0
  42. package/template/workflows/learning/common/skills/knowledge-promotion/SKILL.md +46 -0
  43. package/template/workflows/learning/common/skills/knowledge-promotion/domain-index-template.md +6 -0
  44. package/template/workflows/learning/common/skills/knowledge-promotion/domain-overview-template.md +19 -0
  45. package/template/workflows/learning/common/skills/knowledge-promotion/knowledge-template.md +25 -0
  46. package/template/workflows/learning/common/tools/validate-learning.mjs +356 -0
  47. package/template/workflows/learning/runtime-contract.json +11 -0
  48. package/template/workflows/specdev/I-init-setup/I-init-setup.md +1 -1
  49. package/template/workflows/specdev/I-init-setup/config-template.json +2 -2
  50. package/template/workflows/specdev/INDEX.md +2 -2
  51. package/template/workflows/specdev/P-goal-plan/planning-modes.md +1 -1
  52. package/template/workflows/specdev/P-prototype/P-prototype.md +30 -26
  53. package/template/workflows/specdev/P-prototype/design-library/INDEX.md +43 -0
  54. package/template/workflows/specdev/P-prototype/design-library/color-and-theme.md +65 -0
  55. package/template/workflows/specdev/P-prototype/design-library/foundations.md +66 -0
  56. package/template/workflows/specdev/P-prototype/design-library/interaction-patterns.md +61 -0
  57. package/template/workflows/specdev/P-prototype/design-library/product-pattern-index.md +73 -0
  58. package/template/workflows/specdev/P-prototype/design-library/research-provenance.md +54 -0
  59. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/METHODOLOGY.md +90 -0
  60. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/README.md +31 -0
  61. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/data/extended-projects.json +241 -0
  62. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/data/projects.json +253 -0
  63. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/reference/USAGE.md +40 -0
  64. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/reference/design-tokens.css +145 -0
  65. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/report/OPEN_SOURCE_UI_RESEARCH_2026.md +519 -0
  66. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/PROJECT_TEMPLATE.md +29 -0
  67. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/README.md +9 -0
  68. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/claude-code-modern-clients.md +407 -0
  69. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/creative-ai-communication.md +574 -0
  70. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/data-dev-tools.md +432 -0
  71. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/personal-multiplatform-apps.md +185 -0
  72. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/research/productivity-collaboration.md +398 -0
  73. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/01-dense-ide.html +68 -0
  74. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/02-monochrome-console.html +18 -0
  75. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/03-soft-personal-ai.html +17 -0
  76. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/04-responsive-web.html +14 -0
  77. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/05-mobile-supervisor.html +16 -0
  78. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/06-cross-platform-workspace.html +17 -0
  79. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/07-local-first-content.html +9 -0
  80. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/08-media-first.html +17 -0
  81. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/README.md +49 -0
  82. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/ATTRIBUTION.md +9 -0
  83. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/landscape.jpg +0 -0
  84. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/lucide.js +20494 -0
  85. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/mountain.jpg +0 -0
  86. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/assets/workspace.jpg +0 -0
  87. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/index.html +70 -0
  88. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/package-lock.json +78 -0
  89. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/package.json +12 -0
  90. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/screenshots/index-desktop.png +0 -0
  91. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/scripts/gallery.js +134 -0
  92. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/styles/base.css +795 -0
  93. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/styles/pages.css +533 -0
  94. package/template/workflows/specdev/P-prototype/design-library/research-snapshot/ui-gallery/tests/gallery.spec.js +56 -0
  95. package/template/workflows/specdev/P-prototype/design-library/responsive-and-platforms.md +53 -0
  96. package/template/workflows/specdev/P-prototype/design-library/style-index.md +32 -0
  97. package/template/workflows/specdev/P-prototype/design-package.schema.json +70 -0
  98. package/template/workflows/specdev/P-prototype/design-system-template.md +366 -0
  99. package/template/workflows/specdev/P-prototype/detect-existing-style.md +53 -0
  100. package/template/workflows/specdev/P-prototype/generate-design-package.md +50 -0
  101. package/template/workflows/specdev/P-prototype/style-selection-protocol.md +41 -0
  102. package/template/workflows/specdev/P-prototype/tools/materialize-prototype.mjs +126 -0
  103. package/template/workflows/specdev/P-prototype/tools/validate-design-package.mjs +155 -0
  104. package/template/workflows/specdev/README.md +12 -11
  105. package/template/workflows/specdev/T-triage/T-triage.md +1 -1
  106. package/template/workflows/specdev/W-wayfinder/W-wayfinder.md +1 -1
  107. package/template/workflows/specdev/common/README.md +2 -2
  108. package/template/workflows/specdev/common/rules/artifact-contract.md +3 -2
  109. package/template/workflows/specdev/common/schemas/config.schema.json +4 -4
  110. package/template/workflows/specdev/common/skills/dev-worktree/SKILL.md +4 -4
  111. package/template/workflows/specdev/common/skills/dev-worktree/references/create.md +1 -3
  112. package/template/workflows/specdev/common/tools/validate-specdev.mjs +83 -92
  113. package/template/canonical/canonical-specdev-engineering-cognitive-mentor.md +0 -1968
  114. package/template/workflows/specdev/E-eli5/E-eli5.md +0 -97
  115. package/template/workflows/specdev/E-engineering-cognitive-mentor/E-engineering-cognitive-mentor.md +0 -254
  116. package/template/workflows/specdev/E-engineering-cognitive-mentor/architecture-guidance.md +0 -90
  117. package/template/workflows/specdev/E-engineering-cognitive-mentor/bug-guidance.md +0 -80
  118. package/template/workflows/specdev/E-engineering-cognitive-mentor/codebase-guidance.md +0 -107
  119. package/template/workflows/specdev/E-engineering-cognitive-mentor/comprehension-and-closure.md +0 -95
  120. package/template/workflows/specdev/E-engineering-cognitive-mentor/domain-learning-guidance.md +0 -62
  121. package/template/workflows/specdev/E-engineering-cognitive-mentor/evidence-and-options.md +0 -132
  122. package/template/workflows/specdev/E-engineering-cognitive-mentor/interaction-protocol.md +0 -116
  123. package/template/workflows/specdev/E-engineering-cognitive-mentor/mentor-report-template.md +0 -135
  124. package/template/workflows/specdev/E-engineering-cognitive-mentor/mode-routing.md +0 -47
  125. package/template/workflows/specdev/E-engineering-cognitive-mentor/persistence-and-resume.md +0 -132
  126. package/template/workflows/specdev/E-engineering-cognitive-mentor/requirements-guidance.md +0 -92
  127. package/template/workflows/specdev/P-prototype/logic-prototype.md +0 -24
  128. package/template/workflows/specdev/P-prototype/prototype-record-template.md +0 -46
  129. package/template/workflows/specdev/P-prototype/ui-prototype.md +0 -21
  130. package/template/workflows/specdev/common/schemas/prototype-record.schema.json +0 -24
@@ -34,8 +34,6 @@ const EXPECTED_WORKS = new Set([
34
34
  "A-archive-and-consolidate",
35
35
  "C-code-review",
36
36
  "D-diagnose-bugs",
37
- "E-eli5",
38
- "E-engineering-cognitive-mentor",
39
37
  "G-grill-with-docs",
40
38
  "I-implement",
41
39
  "I-init-setup",
@@ -99,7 +97,6 @@ const VALID_STAGES = new Set([
99
97
  "triage",
100
98
  "diagnosis",
101
99
  "grill",
102
- "eli5",
103
100
  "spec",
104
101
  "tickets",
105
102
  "goal-plan",
@@ -169,7 +166,6 @@ const STATE_ARTIFACT_BASENAMES = new Set([
169
166
  "source.md",
170
167
  "architecture-review.md",
171
168
  "architecture-review.html",
172
- "eli_index.md",
173
169
  "wayfinder-map.md",
174
170
  "design-tree.json",
175
171
  ]);
@@ -469,10 +465,21 @@ function validateDocumentReferences(root) {
469
465
  const errors = [];
470
466
  const warnings = [];
471
467
  const entries = walk(root);
472
- const knownFiles = new Set(entries.filter(isFile).map((path) => basename(path)));
473
- const knownDirectories = new Set(entries.filter(isDirectory).map((path) => basename(path)));
468
+ const frozenResearchRoot = join(
469
+ root,
470
+ "P-prototype",
471
+ "design-library",
472
+ "research-snapshot",
473
+ );
474
+ const governedEntries = entries.filter(
475
+ (path) => path !== frozenResearchRoot && !path.startsWith(`${frozenResearchRoot}${sep}`),
476
+ );
477
+ const knownFiles = new Set(governedEntries.filter(isFile).map((path) => basename(path)));
478
+ const knownDirectories = new Set(governedEntries.filter(isDirectory).map((path) => basename(path)));
474
479
 
475
- for (const path of entries.filter(
480
+ // The pinned research snapshot preserves its upstream relative links and HTML
481
+ // asset paths byte-for-byte. Global template link checks still validate it.
482
+ for (const path of governedEntries.filter(
476
483
  (item) => isFile(item) && [".md", ".html"].includes(extname(item).toLowerCase()),
477
484
  )) {
478
485
  const label = toPosix(relative(root, path));
@@ -686,12 +693,13 @@ function validateExecutionContractAssets(root) {
686
693
  configTemplate.execution.max_implementation_agents < 1 ||
687
694
  !Number.isInteger(configTemplate.execution?.max_integration_attempts) ||
688
695
  configTemplate.execution.max_integration_attempts < 1 ||
689
- !Number.isInteger(configTemplate.planning?.ui_prototype_default_variants) ||
690
- !Number.isInteger(configTemplate.planning?.ui_prototype_max_variants) ||
691
- configTemplate.planning.ui_prototype_default_variants < 1 ||
692
- configTemplate.planning.ui_prototype_max_variants < configTemplate.planning.ui_prototype_default_variants
696
+ !Number.isInteger(configTemplate.planning?.ui_design_default_candidates) ||
697
+ !Number.isInteger(configTemplate.planning?.ui_design_max_candidates) ||
698
+ configTemplate.planning.ui_design_default_candidates < 2 ||
699
+ configTemplate.planning.ui_design_max_candidates > 4 ||
700
+ configTemplate.planning.ui_design_max_candidates < configTemplate.planning.ui_design_default_candidates
693
701
  ) {
694
- errors.push("config-template.json must define SpecDev config v5 with positive execution limits and valid prototype variant bounds");
702
+ errors.push("config-template.json must define SpecDev config v5 with positive execution limits and valid UI design candidate bounds");
695
703
  }
696
704
  for (const obsolete of ["auto_commit", "worktree_for_parallel", "max_parallel"]) {
697
705
  if (JSON.stringify(configTemplate).includes(`\"${obsolete}\"`)) {
@@ -820,14 +828,7 @@ function capabilityChecks(root) {
820
828
  "prototype",
821
829
  [
822
830
  join(root, "P-prototype", "P-prototype.md"),
823
- ["一个问题", "Logic", "UI", "临时 branch/worktree", "promotion target", "main"],
824
- ],
825
- ],
826
- [
827
- "eli5",
828
- [
829
- join(root, "E-eli5", "E-eli5.md"),
830
- ["大一新生", "零专业背景", "$ARGUMENTS", "ASCII", "eli_index.md", "{number}_{topic}.md"],
831
+ ["设计定向", "风格", "design-system.md", "comparison", "HTML/CSS/JS", "design-library/INDEX.md"],
831
832
  ],
832
833
  ],
833
834
  [
@@ -1207,88 +1208,79 @@ function validateReviews(change, required, errors) {
1207
1208
 
1208
1209
  function validatePrototypes(change, required, errors) {
1209
1210
  const root = join(change, "prototypes");
1210
- const paths = isDirectory(root)
1211
- ? walk(root).filter((path) => isFile(path) && basename(path) === "record.md").sort()
1212
- : [];
1213
- if (required && !paths.length) errors.push("prototype stage requires a prototypes/<id>/record.md artifact");
1214
- for (const path of paths) {
1215
- const { meta, body } = parseFrontmatter(path);
1216
- const label = toPosix(relative(change, path));
1217
- if (meta.schema_version !== 1 || meta.artifact !== "prototype-record") {
1218
- errors.push(`${label}: artifact/schema_version must be prototype-record/1`);
1219
- }
1220
- if (meta.change !== basename(change)) errors.push(`${label}: change must equal directory name`);
1221
- if (!/^PROTO-\d{3,}$/.test(String(meta.prototype_id ?? ""))) errors.push(`${label}: invalid prototype_id`);
1222
- if (!new Set(["logic", "ui"]).has(meta.branch)) errors.push(`${label}: invalid prototype branch`);
1223
- if (!new Set(["active", "answered", "blocked", "discarded"]).has(meta.status)) errors.push(`${label}: invalid prototype status`);
1224
- if (typeof meta.workspace_ref !== "string" || ABSOLUTE_MACHINE_PATH_RE.test(meta.workspace_ref)) {
1225
- errors.push(`${label}: workspace_ref must be a portable locator`);
1226
- }
1227
- if (meta.status === "answered" && (!String(meta.winner ?? "").trim() || !String(meta.promotion_target ?? "").trim())) {
1228
- errors.push(`${label}: answered prototype requires winner and promotion_target`);
1229
- }
1230
- if (!new Set(["pending", "clean", "registered"]).has(meta.cleanup_status)) errors.push(`${label}: invalid cleanup_status`);
1231
- for (const heading of ["## Question and Assumption", "## Run and Assets", "## Evaluation", "## Promotion and Cleanup"]) {
1232
- if (!body.includes(heading)) errors.push(`${label}: missing '${heading}'`);
1233
- }
1211
+ if (!isDirectory(root)) {
1212
+ if (required) errors.push("prototype stage requires a prototypes/UI-NNN/design-system.md artifact");
1213
+ return [];
1234
1214
  }
1235
- return paths;
1236
- }
1237
-
1238
- function validateEli5(change, required, errors) {
1239
- const indexPath = join(change, "eli_index.md");
1240
- const diagramFiles = readdirSync(change, { withFileTypes: true })
1241
- .filter((entry) => entry.isFile() && /^\d{2,}_[^/\\\\\s]+\.md$/.test(entry.name))
1242
- .map((entry) => entry.name)
1243
- .sort();
1244
1215
 
1245
- if (!isFile(indexPath)) {
1246
- if (required) errors.push("eli5 stage requires eli_index.md");
1247
- return null;
1248
- }
1216
+ const validator = resolve(
1217
+ dirname(fileURLToPath(import.meta.url)),
1218
+ "..",
1219
+ "..",
1220
+ "P-prototype",
1221
+ "tools",
1222
+ "validate-design-package.mjs",
1223
+ );
1224
+ const paths = [];
1225
+ let readyCount = 0;
1249
1226
 
1250
- const index = readText(indexPath);
1251
- if (!index.includes("# ELI5 图解索引")) errors.push("eli_index.md: missing index heading");
1252
- const entries = Array.from(index.matchAll(/^\|\s*(\d{2,})\s*\|\s*([^|\s]+\.md)\s*\|\s*([^|]+)\|\s*([^|]+)\|\s*$/gm));
1253
- if (!entries.length && required) errors.push("eli_index.md: requires at least one diagram entry");
1227
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
1228
+ const entryPath = join(root, entry.name);
1229
+ const label = toPosix(relative(change, entryPath));
1230
+ if (entry.isSymbolicLink()) {
1231
+ errors.push(`${label}: prototype design directories and files must not be symlinks`);
1232
+ continue;
1233
+ }
1234
+ if (!entry.isDirectory()) {
1235
+ errors.push(`${label}: prototypes may only contain UI-NNN design directories`);
1236
+ continue;
1237
+ }
1238
+ if (!/^UI-\d{3,}$/.test(entry.name)) {
1239
+ errors.push(`${label}: prototype design directory must use UI-NNN`);
1240
+ continue;
1241
+ }
1254
1242
 
1255
- const indexedFiles = new Set();
1256
- let previousNumber = 0;
1257
- for (const entry of entries) {
1258
- const [, number, fileName, topic, summary] = entry;
1259
- const numericNumber = Number(number);
1260
- if (!/^\d{2,}_[^/\\\\\s]+\.md$/.test(fileName)) {
1261
- errors.push(`eli_index.md: invalid diagram filename '${fileName}'`);
1243
+ const designPath = join(entryPath, "design-system.md");
1244
+ if (!isFile(designPath)) {
1245
+ errors.push(`${label}: missing design-system.md`);
1262
1246
  continue;
1263
1247
  }
1264
- if (numericNumber <= previousNumber) errors.push("eli_index.md: diagram numbers must increase");
1265
- if (numericNumber !== previousNumber + 1) errors.push("eli_index.md: diagram numbers must start at 01 and be continuous");
1266
- previousNumber = numericNumber;
1267
- if (!fileName.startsWith(`${number}_`)) errors.push(`eli_index.md: '${fileName}' must start with '${number}_'`);
1268
- if (!topic.trim() || !summary.trim()) errors.push(`eli_index.md: '${fileName}' requires a topic and summary`);
1269
- indexedFiles.add(fileName);
1248
+ paths.push(designPath);
1249
+ const { meta } = parseFrontmatter(designPath);
1250
+ if (meta.status === "ready") readyCount += 1;
1251
+ try {
1252
+ execFileSync(process.execPath, [validator, designPath], {
1253
+ encoding: "utf8",
1254
+ stdio: ["ignore", "pipe", "pipe"],
1255
+ });
1256
+ } catch (error) {
1257
+ const details = String(error.stderr || error.stdout || error.message)
1258
+ .trim()
1259
+ .split(/\r?\n/)
1260
+ .filter(Boolean);
1261
+ if (!details.length) errors.push(`${label}: design package validation failed`);
1262
+ for (const detail of details) errors.push(`${label}: ${detail}`);
1263
+ }
1270
1264
  }
1271
1265
 
1272
- for (const fileName of diagramFiles) {
1273
- if (!indexedFiles.has(fileName)) errors.push(`eli_index.md: missing entry for '${fileName}'`);
1274
- }
1275
- for (const fileName of indexedFiles) {
1276
- if (!diagramFiles.includes(fileName)) errors.push(`eli_index.md: '${fileName}' does not exist`);
1266
+ const obsoleteRecords = walk(root).filter(
1267
+ (path) => isFile(path) && basename(path) === "record.md",
1268
+ );
1269
+ for (const path of obsoleteRecords) {
1270
+ errors.push(`${toPosix(relative(change, path))}: obsolete prototype record is forbidden; use UI-NNN/design-system.md`);
1277
1271
  }
1278
-
1279
- for (const fileName of diagramFiles) {
1280
- const markdown = readText(join(change, fileName));
1281
- for (const heading of ["## 先看全图", "## 一步一步看", "## 术语小词典", "## 你现在能复述什么"]) {
1282
- if (!markdown.includes(heading)) errors.push(`${fileName}: missing '${heading}'`);
1283
- }
1284
- if (!/```(?:text)?\s*[\s\S]*?(?:->|\||\+--)[\s\S]*?```/.test(markdown)) {
1285
- errors.push(`${fileName}: requires an ASCII diagram in a fenced code block`);
1286
- }
1287
- if (/<\/?(?:html|head|body|svg|canvas|img|picture)\b/i.test(markdown)) {
1288
- errors.push(`${fileName}: must be Markdown, not HTML`);
1272
+ const discoveredDesigns = walk(root).filter(
1273
+ (path) => isFile(path) && basename(path) === "design-system.md",
1274
+ );
1275
+ for (const path of discoveredDesigns) {
1276
+ if (!paths.includes(path)) {
1277
+ errors.push(`${toPosix(relative(change, path))}: design-system.md must be directly under prototypes/UI-NNN`);
1289
1278
  }
1290
1279
  }
1291
- return indexPath;
1280
+ if (required && readyCount === 0) {
1281
+ errors.push("prototype stage requires at least one ready UI design package");
1282
+ }
1283
+ return paths;
1292
1284
  }
1293
1285
 
1294
1286
  function validateSpec(path, errors, warnings) {
@@ -2151,7 +2143,6 @@ function validateChange(change, stage = null, repoRoot = null) {
2151
2143
  }
2152
2144
  validateReviews(change, stage === "review", errors);
2153
2145
  validatePrototypes(change, stage === "prototype", errors);
2154
- validateEli5(change, stage === "eli5", errors);
2155
2146
 
2156
2147
  const specRequired = new Set(["spec", "tickets", "goal-plan", "implement", "complete"]).has(stage);
2157
2148
  const specPath = join(change, "spec.md");