@harness-engineering/cli 2.7.1 → 3.0.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 (197) hide show
  1. package/dist/agents/personas/adversarial-reviewer.yaml +43 -0
  2. package/dist/agents/personas/frontend-races-reviewer.yaml +54 -0
  3. package/dist/agents/personas/typescript-strict-reviewer.yaml +53 -0
  4. package/dist/agents/skills/CHANGELOG.md +12 -0
  5. package/dist/agents/skills/claude-code/align-design-system/SKILL.md +18 -0
  6. package/dist/agents/skills/claude-code/align-design-system/skill.yaml +3 -0
  7. package/dist/agents/skills/claude-code/harness-audit-harness-strength/SKILL.md +188 -0
  8. package/dist/agents/skills/claude-code/harness-audit-harness-strength/skill.yaml +54 -0
  9. package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +2 -0
  10. package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +58 -12
  11. package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +107 -22
  12. package/dist/agents/skills/claude-code/harness-code-review/references/confidence-rubric.md +45 -0
  13. package/dist/agents/skills/claude-code/harness-code-review/references/risk-keywords.md +40 -0
  14. package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +3 -0
  15. package/dist/agents/skills/claude-code/harness-compound/SKILL.md +7 -4
  16. package/dist/agents/skills/claude-code/harness-execution/SKILL.md +1 -1
  17. package/dist/agents/skills/claude-code/harness-git-workflow/SKILL.md +2 -0
  18. package/dist/agents/skills/claude-code/harness-ideate/SKILL.md +279 -0
  19. package/dist/agents/skills/claude-code/harness-ideate/references/scoring.md +88 -0
  20. package/dist/agents/skills/claude-code/harness-ideate/skill.yaml +66 -0
  21. package/dist/agents/skills/claude-code/harness-knowledge-pipeline/SKILL.md +2 -0
  22. package/dist/agents/skills/claude-code/harness-planning/SKILL.md +14 -4
  23. package/dist/agents/skills/claude-code/harness-pulse/SKILL.md +12 -16
  24. package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +62 -4
  25. package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +36 -6
  26. package/dist/agents/skills/claude-code/harness-strategy/SKILL.md +152 -0
  27. package/dist/agents/skills/claude-code/harness-strategy/references/interview.md +122 -0
  28. package/dist/agents/skills/claude-code/harness-strategy/skill.yaml +54 -0
  29. package/dist/agents/skills/claude-code/harness-test-advisor/SKILL.md +80 -2
  30. package/dist/agents/skills/claude-code/harness-test-advisor/skill.yaml +4 -1
  31. package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +86 -18
  32. package/dist/agents/skills/claude-code/initialize-harness-project/skill.yaml +1 -0
  33. package/dist/agents/skills/claude-code/outcome-eval/SKILL.md +97 -0
  34. package/dist/agents/skills/claude-code/outcome-eval/skill.yaml +51 -0
  35. package/dist/agents/skills/codex/align-design-system/SKILL.md +18 -0
  36. package/dist/agents/skills/codex/align-design-system/skill.yaml +3 -0
  37. package/dist/agents/skills/codex/harness-audit-harness-strength/SKILL.md +188 -0
  38. package/dist/agents/skills/codex/harness-audit-harness-strength/skill.yaml +54 -0
  39. package/dist/agents/skills/codex/harness-autopilot/SKILL.md +2 -0
  40. package/dist/agents/skills/codex/harness-brainstorming/SKILL.md +58 -12
  41. package/dist/agents/skills/codex/harness-code-review/SKILL.md +107 -22
  42. package/dist/agents/skills/codex/harness-code-review/references/confidence-rubric.md +45 -0
  43. package/dist/agents/skills/codex/harness-code-review/references/risk-keywords.md +40 -0
  44. package/dist/agents/skills/codex/harness-code-review/skill.yaml +3 -0
  45. package/dist/agents/skills/codex/harness-compound/SKILL.md +7 -4
  46. package/dist/agents/skills/codex/harness-execution/SKILL.md +1 -1
  47. package/dist/agents/skills/codex/harness-git-workflow/SKILL.md +2 -0
  48. package/dist/agents/skills/codex/harness-ideate/SKILL.md +279 -0
  49. package/dist/agents/skills/codex/harness-ideate/references/scoring.md +88 -0
  50. package/dist/agents/skills/codex/harness-ideate/skill.yaml +66 -0
  51. package/dist/agents/skills/codex/harness-knowledge-pipeline/SKILL.md +2 -0
  52. package/dist/agents/skills/codex/harness-planning/SKILL.md +14 -4
  53. package/dist/agents/skills/codex/harness-pulse/SKILL.md +12 -16
  54. package/dist/agents/skills/codex/harness-roadmap/SKILL.md +62 -4
  55. package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +36 -6
  56. package/dist/agents/skills/codex/harness-strategy/SKILL.md +152 -0
  57. package/dist/agents/skills/codex/harness-strategy/references/interview.md +122 -0
  58. package/dist/agents/skills/codex/harness-strategy/skill.yaml +54 -0
  59. package/dist/agents/skills/codex/harness-test-advisor/SKILL.md +80 -2
  60. package/dist/agents/skills/codex/harness-test-advisor/skill.yaml +4 -1
  61. package/dist/agents/skills/codex/initialize-harness-project/SKILL.md +86 -18
  62. package/dist/agents/skills/codex/initialize-harness-project/skill.yaml +1 -0
  63. package/dist/agents/skills/codex/outcome-eval/SKILL.md +97 -0
  64. package/dist/agents/skills/codex/outcome-eval/skill.yaml +51 -0
  65. package/dist/agents/skills/cursor/align-design-system/SKILL.md +18 -0
  66. package/dist/agents/skills/cursor/align-design-system/skill.yaml +3 -0
  67. package/dist/agents/skills/cursor/harness-audit-harness-strength/SKILL.md +188 -0
  68. package/dist/agents/skills/cursor/harness-audit-harness-strength/skill.yaml +54 -0
  69. package/dist/agents/skills/cursor/harness-autopilot/SKILL.md +2 -0
  70. package/dist/agents/skills/cursor/harness-brainstorming/SKILL.md +58 -12
  71. package/dist/agents/skills/cursor/harness-code-review/SKILL.md +107 -22
  72. package/dist/agents/skills/cursor/harness-code-review/references/confidence-rubric.md +45 -0
  73. package/dist/agents/skills/cursor/harness-code-review/references/risk-keywords.md +40 -0
  74. package/dist/agents/skills/cursor/harness-code-review/skill.yaml +3 -0
  75. package/dist/agents/skills/cursor/harness-compound/SKILL.md +7 -4
  76. package/dist/agents/skills/cursor/harness-execution/SKILL.md +1 -1
  77. package/dist/agents/skills/cursor/harness-git-workflow/SKILL.md +2 -0
  78. package/dist/agents/skills/cursor/harness-ideate/SKILL.md +279 -0
  79. package/dist/agents/skills/cursor/harness-ideate/references/scoring.md +88 -0
  80. package/dist/agents/skills/cursor/harness-ideate/skill.yaml +66 -0
  81. package/dist/agents/skills/cursor/harness-knowledge-pipeline/SKILL.md +2 -0
  82. package/dist/agents/skills/cursor/harness-planning/SKILL.md +14 -4
  83. package/dist/agents/skills/cursor/harness-pulse/SKILL.md +12 -16
  84. package/dist/agents/skills/cursor/harness-roadmap/SKILL.md +62 -4
  85. package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +36 -6
  86. package/dist/agents/skills/cursor/harness-strategy/SKILL.md +152 -0
  87. package/dist/agents/skills/cursor/harness-strategy/references/interview.md +122 -0
  88. package/dist/agents/skills/cursor/harness-strategy/skill.yaml +54 -0
  89. package/dist/agents/skills/cursor/harness-test-advisor/SKILL.md +80 -2
  90. package/dist/agents/skills/cursor/harness-test-advisor/skill.yaml +4 -1
  91. package/dist/agents/skills/cursor/initialize-harness-project/SKILL.md +86 -18
  92. package/dist/agents/skills/cursor/initialize-harness-project/skill.yaml +1 -0
  93. package/dist/agents/skills/cursor/outcome-eval/SKILL.md +97 -0
  94. package/dist/agents/skills/cursor/outcome-eval/skill.yaml +51 -0
  95. package/dist/agents/skills/gemini-cli/align-design-system/SKILL.md +18 -0
  96. package/dist/agents/skills/gemini-cli/align-design-system/skill.yaml +3 -0
  97. package/dist/agents/skills/gemini-cli/harness-audit-harness-strength/SKILL.md +188 -0
  98. package/dist/agents/skills/gemini-cli/harness-audit-harness-strength/skill.yaml +54 -0
  99. package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +2 -0
  100. package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +58 -12
  101. package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +107 -22
  102. package/dist/agents/skills/gemini-cli/harness-code-review/references/confidence-rubric.md +45 -0
  103. package/dist/agents/skills/gemini-cli/harness-code-review/references/risk-keywords.md +40 -0
  104. package/dist/agents/skills/gemini-cli/harness-code-review/skill.yaml +3 -0
  105. package/dist/agents/skills/gemini-cli/harness-compound/SKILL.md +7 -4
  106. package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +1 -1
  107. package/dist/agents/skills/gemini-cli/harness-git-workflow/SKILL.md +2 -0
  108. package/dist/agents/skills/gemini-cli/harness-ideate/SKILL.md +279 -0
  109. package/dist/agents/skills/gemini-cli/harness-ideate/references/scoring.md +88 -0
  110. package/dist/agents/skills/gemini-cli/harness-ideate/skill.yaml +66 -0
  111. package/dist/agents/skills/gemini-cli/harness-knowledge-pipeline/SKILL.md +2 -0
  112. package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +14 -4
  113. package/dist/agents/skills/gemini-cli/harness-pulse/SKILL.md +12 -16
  114. package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +62 -4
  115. package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +36 -6
  116. package/dist/agents/skills/gemini-cli/harness-strategy/SKILL.md +152 -0
  117. package/dist/agents/skills/gemini-cli/harness-strategy/references/interview.md +122 -0
  118. package/dist/agents/skills/gemini-cli/harness-strategy/skill.yaml +54 -0
  119. package/dist/agents/skills/gemini-cli/harness-test-advisor/SKILL.md +80 -2
  120. package/dist/agents/skills/gemini-cli/harness-test-advisor/skill.yaml +4 -1
  121. package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +86 -18
  122. package/dist/agents/skills/gemini-cli/initialize-harness-project/skill.yaml +1 -0
  123. package/dist/agents/skills/gemini-cli/outcome-eval/SKILL.md +97 -0
  124. package/dist/agents/skills/gemini-cli/outcome-eval/skill.yaml +51 -0
  125. package/dist/agents/skills/package.json +1 -1
  126. package/dist/agents/skills/tests/harness-strategy.test.ts +145 -0
  127. package/dist/agents/skills/tests/harness-test-advisor.test.ts +94 -0
  128. package/dist/agents-md-XOJE5ETA.js +13 -0
  129. package/dist/analyzer-V633GUHY-MBCQWKDU.js +26 -0
  130. package/dist/{architecture-LUR2I67H.js → architecture-JEZPJ725.js} +6 -6
  131. package/dist/{assess-project-OJWECOP2.js → assess-project-RHXOQNMM.js} +1 -1
  132. package/dist/bin/harness-mcp.js +17 -17
  133. package/dist/bin/harness.js +27 -27
  134. package/dist/{check-phase-gate-HS5KYLRO.js → check-phase-gate-GNDOMS35.js} +6 -6
  135. package/dist/{chunk-6UHDQP2N.js → chunk-2N4OENGE.js} +1 -1
  136. package/dist/{chunk-O2ASYKA6.js → chunk-3ISHDWO7.js} +2 -2
  137. package/dist/{chunk-GGSNWH7P.js → chunk-527G27VI.js} +5 -5
  138. package/dist/{chunk-N5NSSLMU.js → chunk-6WQCLCBO.js} +2 -2
  139. package/dist/{chunk-OH3NXXUY.js → chunk-BDGTZRZ6.js} +11 -1
  140. package/dist/{chunk-Z3TMCCZB.js → chunk-BYVT5LVO.js} +9 -9
  141. package/dist/{chunk-TIH53QXY.js → chunk-CLI4K2CH.js} +1 -1
  142. package/dist/{chunk-VSIRUZQP.js → chunk-DE5U6KOL.js} +2 -2
  143. package/dist/{chunk-FXZI6NJ2.js → chunk-GGKRA7A7.js} +51 -4
  144. package/dist/{chunk-RJ2WEES5.js → chunk-GSP2XIVS.js} +2 -2
  145. package/dist/{chunk-CZPOPMMI.js → chunk-HEIMJJI4.js} +3 -3
  146. package/dist/{chunk-7AF6C5GE.js → chunk-HWTUUQOW.js} +3 -3
  147. package/dist/{chunk-FC4JPM6W.js → chunk-KAJOS3BA.js} +3 -3
  148. package/dist/{chunk-NIVWM7OW.js → chunk-MGUPSE6D.js} +10 -10
  149. package/dist/{chunk-WZY5U6NS.js → chunk-N24HCQA4.js} +3351 -887
  150. package/dist/{chunk-Y4T6ENKQ.js → chunk-N55WOGN3.js} +86 -17
  151. package/dist/{chunk-INBTDBV2.js → chunk-NWLGL3IR.js} +1 -1
  152. package/dist/{chunk-FEKBXX2J.js → chunk-ONCPJGHY.js} +9 -9
  153. package/dist/{chunk-PTHX545Q.js → chunk-PC2R5RUJ.js} +2 -2
  154. package/dist/{chunk-H2ZJOJ7A.js → chunk-PP6ZRL5T.js} +316 -42
  155. package/dist/{chunk-LECXPXS3.js → chunk-QBC7DI4Q.js} +2 -2
  156. package/dist/{chunk-B2VAYLYI.js → chunk-UX3PQKVZ.js} +8 -3
  157. package/dist/{chunk-7PLIWP7U.js → chunk-WWEVS7RO.js} +4409 -743
  158. package/dist/{chunk-LGYXR2KZ.js → chunk-XFU6SB2Q.js} +1122 -689
  159. package/dist/{chunk-KN3EMDZ5.js → chunk-XX4OLNWQ.js} +23 -3
  160. package/dist/{chunk-VI4IS55S.js → chunk-YQSYCBAH.js} +6 -6
  161. package/dist/{chunk-LYIPI2SJ.js → chunk-Z4AWEIBY.js} +6 -6
  162. package/dist/{ci-workflow-MDSTHJOY.js → ci-workflow-ORZ4F45F.js} +5 -5
  163. package/dist/{dist-E3SAAHCM.js → dist-ICW4QUEW.js} +5 -1
  164. package/dist/{dist-72ID44UE.js → dist-LHINSVK4.js} +136 -4
  165. package/dist/{dist-R3TOOPJ7.js → dist-OWHMNL4W.js} +1 -1
  166. package/dist/{docs-2RFOJ6XY.js → docs-AU3DXFFO.js} +6 -6
  167. package/dist/engine-6GPWOYQH.js +13 -0
  168. package/dist/{entropy-3UX6644G.js → entropy-VLKDRMRT.js} +5 -5
  169. package/dist/{feedback-CVCFYND4.js → feedback-YXYY44ZC.js} +1 -1
  170. package/dist/{generate-agent-definitions-HZ3XENWO.js → generate-agent-definitions-XIHQPKG3.js} +6 -6
  171. package/dist/{glob-helper-EX4YZKZO.js → glob-helper-GLZAURJC.js} +1 -1
  172. package/dist/{graph-loader-EIFEOUVI.js → graph-loader-HHXN5FLP.js} +1 -1
  173. package/dist/hooks/cost-tracker.js +29 -6
  174. package/dist/index.d.ts +202 -0
  175. package/dist/index.js +27 -27
  176. package/dist/{loader-6RHWU5FH.js → loader-YAN56MT3.js} +5 -5
  177. package/dist/{mcp-OYR26JDI.js → mcp-RK3SFVYB.js} +17 -17
  178. package/dist/{performance-JJMIRXCH.js → performance-64DPTLLQ.js} +6 -6
  179. package/dist/{review-pipeline-BHQZIXWZ.js → review-pipeline-NENG6LW7.js} +5 -5
  180. package/dist/{runtime-DALTAVTN.js → runtime-FFIIRT2T.js} +5 -5
  181. package/dist/{scan-LYKLM4EQ.js → scan-P7YFKB77.js} +1 -1
  182. package/dist/{security-RMLMYFPB.js → security-3PIBN35B.js} +1 -1
  183. package/dist/templates/basic/harness.config.json.hbs +34 -0
  184. package/dist/templates/ci/README.md +86 -0
  185. package/dist/templates/ci/required-review.ruleset.json +20 -0
  186. package/dist/templates/ci/required-review.yml.hbs +57 -0
  187. package/dist/templates/ci/template.json +5 -0
  188. package/dist/templates/intermediate/harness.config.json.hbs +36 -0
  189. package/dist/templates/orchestrator/harness.orchestrator.md +9 -0
  190. package/dist/{tool-tiers-B7JC2XC3.js → tool-tiers-OKK5FE57.js} +2 -0
  191. package/dist/{validate-R7DZRDFK.js → validate-7IAF2ES3.js} +6 -6
  192. package/dist/validate-cross-check-QPSAOZKD.js +13 -0
  193. package/package.json +8 -8
  194. package/dist/agents-md-FKMKH6ZF.js +0 -13
  195. package/dist/analyzer-H3AHBFSL-KPOPJYRB.js +0 -26
  196. package/dist/engine-BSFKOGPN.js +0 -13
  197. package/dist/validate-cross-check-AUUZFNVL.js +0 -13
@@ -39,7 +39,7 @@ import * as path11 from "path";
39
39
  import * as fs12 from "fs/promises";
40
40
  import * as path13 from "path";
41
41
  import { minimatch as minimatch2 } from "minimatch";
42
- import { relative as relative6 } from "path";
42
+ import { relative as relative7 } from "path";
43
43
  import * as fs13 from "fs/promises";
44
44
  import * as path14 from "path";
45
45
  function streamGraphNdjson(filePath, nodes, edges) {
@@ -484,6 +484,49 @@ function parseFrontmatter(raw) {
484
484
  body
485
485
  };
486
486
  }
487
+ function slugifyStrategySection(name) {
488
+ return name.toLowerCase().replace(/'/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
489
+ }
490
+ function parseStrategyMarkdown(raw) {
491
+ const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
492
+ if (!match) return null;
493
+ const yamlBlock = match[1];
494
+ const body = match[2];
495
+ const frontmatter = {};
496
+ for (const line of yamlBlock.split(/\r?\n/)) {
497
+ const kvMatch = line.match(/^(\w+):\s*(.+)$/);
498
+ if (!kvMatch) continue;
499
+ const key = kvMatch[1];
500
+ const rawValue = kvMatch[2].trim();
501
+ const unquoted = rawValue.replace(/^["']|["']$/g, "");
502
+ const asNumber = Number(unquoted);
503
+ if (unquoted !== "" && !Number.isNaN(asNumber) && /^-?\d+(?:\.\d+)?$/.test(unquoted)) {
504
+ frontmatter[key] = asNumber;
505
+ } else {
506
+ frontmatter[key] = unquoted;
507
+ }
508
+ }
509
+ const sections = [];
510
+ const h2Re = /^##[ \t]+(.+?)[ \t]*$/gm;
511
+ const matches = [];
512
+ let m;
513
+ while ((m = h2Re.exec(body)) !== null) {
514
+ matches.push({
515
+ name: (m[1] ?? "").trim(),
516
+ headingStart: m.index,
517
+ bodyStart: m.index + m[0].length
518
+ });
519
+ }
520
+ for (let i = 0; i < matches.length; i++) {
521
+ const current = matches[i];
522
+ const sliceEnd = matches[i + 1]?.headingStart ?? body.length;
523
+ sections.push({
524
+ name: current.name,
525
+ body: body.slice(current.bodyStart, sliceEnd).trim()
526
+ });
527
+ }
528
+ return { frontmatter, sections };
529
+ }
487
530
  function parseSolutionFrontmatter(raw) {
488
531
  const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
489
532
  if (!match) return null;
@@ -503,6 +546,49 @@ function parseSolutionFrontmatter(raw) {
503
546
  }
504
547
  return { frontmatter, body };
505
548
  }
549
+ function matchField(body, field) {
550
+ const re = new RegExp(`\\*\\*${field}:\\*\\*\\s*(.+)`, "i");
551
+ const m = body.match(re);
552
+ return m ? m[1].trim() : void 0;
553
+ }
554
+ function buildArchitectureAdrNode(parsed, filePath, architectureDir) {
555
+ const filename = path5.basename(filePath, ".md");
556
+ const relFromArch = path5.relative(architectureDir, filePath).replaceAll("\\", "/");
557
+ const topic = relFromArch.includes("/") ? relFromArch.split("/")[0] : "";
558
+ const nodeId = topic ? `decision:architecture:${topic}:${filename}` : `decision:architecture:${filename}`;
559
+ return {
560
+ id: nodeId,
561
+ type: "decision",
562
+ name: parsed.title,
563
+ path: filePath,
564
+ content: parsed.body.trim(),
565
+ metadata: {
566
+ number: parsed.number,
567
+ ...topic && { domain: topic },
568
+ source: "architecture",
569
+ ...parsed.date && { date: parsed.date },
570
+ ...parsed.status && { status: parsed.status },
571
+ ...parsed.deciders && { deciders: parsed.deciders }
572
+ }
573
+ };
574
+ }
575
+ function parseArchitectureAdr(raw) {
576
+ const h1 = raw.match(ARCHITECTURE_ADR_H1);
577
+ if (!h1) return null;
578
+ const number = h1[1];
579
+ const title = h1[2].trim();
580
+ const date = matchField(raw, "Date");
581
+ const status = matchField(raw, "Status");
582
+ const deciders = matchField(raw, "Deciders");
583
+ return {
584
+ number,
585
+ title,
586
+ body: raw,
587
+ ...date && { date },
588
+ ...status && { status },
589
+ ...deciders && { deciders }
590
+ };
591
+ }
506
592
  function detectEarsPattern(text) {
507
593
  const lower = text.toLowerCase();
508
594
  if (/^if\b.+\bthen\b.+\bshall not\b/.test(lower)) return "unwanted";
@@ -581,7 +667,7 @@ function emptyResult2(diagramType = "unknown") {
581
667
  function detectDiagramType(content) {
582
668
  for (const line of content.split("\n")) {
583
669
  const trimmed = line.trim();
584
- if (!trimmed) continue;
670
+ if (!trimmed || trimmed.startsWith("%%")) continue;
585
671
  if (/^(?:graph|flowchart)\b/i.test(trimmed)) return "flowchart";
586
672
  if (/^sequenceDiagram\b/.test(trimmed)) return "sequence";
587
673
  if (/^classDiagram\b/.test(trimmed)) return "class";
@@ -1032,6 +1118,16 @@ function scoreDomain(domain, knEntries, codeEntries, store) {
1032
1118
  grade: toGrade(score)
1033
1119
  };
1034
1120
  }
1121
+ function emptyIngestResult() {
1122
+ return {
1123
+ nodesAdded: 0,
1124
+ nodesUpdated: 0,
1125
+ edgesAdded: 0,
1126
+ edgesUpdated: 0,
1127
+ errors: [],
1128
+ durationMs: 0
1129
+ };
1130
+ }
1035
1131
  function withRetry(client, options) {
1036
1132
  const maxRetries = options?.maxRetries ?? 3;
1037
1133
  const baseDelayMs = options?.baseDelayMs ?? 1e3;
@@ -1643,7 +1739,7 @@ function parseAntiPatterns(content) {
1643
1739
  }
1644
1740
  return patterns;
1645
1741
  }
1646
- var NODE_TYPES, EDGE_TYPES, OBSERVABILITY_TYPES, CURRENT_SCHEMA_VERSION, NODE_STABILITY, GraphNodeSchema, GraphEdgeSchema, POISONED_KEYS, GraphStore, VectorStore, DEFAULT_TTL_MS, PackedSummaryCache, ContextQL, TEST_TYPES, DOC_TYPES, CODE_TYPES, DEFAULT_SKIP_DIRS, SKIP_METHOD_NAMES, FUNCTION_PATTERNS, CLASS_PATTERNS, INTERFACE_PATTERNS, METHOD_PATTERNS, GO_METHOD_PATTERN, VARIABLE_PATTERNS, SUPPORTED_EXTENSIONS, SKIP_EXTENSIONS, CodeIngestor, execFileAsync, GitIngestor, TopologicalLinker, CODE_NODE_TYPES, DOCS_OWNED_BY_OTHER_INGESTORS, KnowledgeIngestor, BUG_TRACK_CATEGORIES, KNOWLEDGE_TRACK_CATEGORIES, ISO_DATE, SolutionBaseSchema, SolutionDocFrontmatterSchema, BUSINESS_KNOWLEDGE_TYPES, GOVERNS_SOURCE_TYPES, CODE_NODE_TYPES2, MEASURABLE_TYPES, BusinessKnowledgeIngestor, CODE_NODE_TYPES3, DecisionIngestor, REQUIREMENT_SECTIONS, SECTION_HEADING_RE, NUMBERED_ITEM_RE, CODE_NODE_TYPES4, RequirementIngestor, DEFAULT_PATTERNS, DEFAULT_BLOCKLIST, CODE_EXTENSIONS, MermaidParser, D2Parser, PlantUmlParser, DIAGRAM_EXTENSIONS, DiagramParser, HEURISTIC_PATTERNS, SCANNABLE_TYPES, KnowledgeLinker, StructuralDriftDetector, BUSINESS_NODE_TYPES, KnowledgeStagingAggregator, EXT_TO_LANGUAGE, SKIP_EXTENSIONS2, EXTRACTOR_EDGE_TYPE, ExtractionRunner, PATTERNS, TestDescriptionExtractor, EnumConstantExtractor, ValidationRuleExtractor, ApiPathExtractor, ALL_EXTRACTORS, ImageAnalysisExtractor, KNOWLEDGE_NODE_TYPES, SIMILARITY_THRESHOLD, SEVERITY_MAP, ContradictionDetector, KNOWLEDGE_TYPES, CODE_TYPES2, KNOWLEDGE_EDGE_TYPES, CoverageScorer, VALID_BUSINESS_TYPES, DEFAULT_MAX_DOCS, MAX_COLLISION_SUFFIX, KnowledgeDocMaterializer, BUSINESS_NODE_TYPES2, SNAPSHOT_NODE_TYPES, KnowledgePipelineRunner, CODE_NODE_TYPES5, RETRYABLE_STATUSES, SANITIZE_RULES, SyncManager, SUMMARIZE_PROMPT, JiraConnector, SlackConnector, ConfluenceConnector, CIConnector, CONSTRAINT_KEYWORDS, FigmaConnector, MIN_CONTENT_LENGTH, CONCEPT_ITEM_TYPES, MiroConnector, STOP_WORDS, FusionLayer, CODE_NODE_TYPES6, GraphEntropyAdapter, GraphComplexityAdapter, GraphCouplingAdapter, DEFAULT_THRESHOLD, DEFAULT_METRICS, RECOGNIZED_METRICS, GraphAnomalyAdapter, INTENTS, SIGNAL_WEIGHTS, INTENT_SIGNALS, IntentClassifier, INTENT_KEYWORDS, STOP_WORDS2, PASCAL_OR_CAMEL_RE, FILE_PATH_RE, QUOTED_RE, EntityExtractor, EntityResolver, ResponseFormatter, CompositeProbabilityStrategy, DEFAULT_PROBABILITY_FLOOR, DEFAULT_MAX_DEPTH, CascadeSimulator, ENTITY_REQUIRED_INTENTS, classifier, extractor, formatter, PHASE_NODE_TYPES, CODE_NODE_TYPES7, Assembler, GraphConstraintAdapter, DesignIngestor, CODE_PREFIX_LABELS, DesignConstraintAdapter, GraphFeedbackAdapter, DEFAULT_EDGE_TYPES, TaskIndependenceAnalyzer, ConflictPredictor, VERSION;
1742
+ var NODE_TYPES, EDGE_TYPES, OBSERVABILITY_TYPES, CURRENT_SCHEMA_VERSION, NODE_STABILITY, GraphNodeSchema, GraphEdgeSchema, POISONED_KEYS, GraphStore, VectorStore, DEFAULT_TTL_MS, PackedSummaryCache, ContextQL, TEST_TYPES, DOC_TYPES, CODE_TYPES, DEFAULT_SKIP_DIRS, SKIP_METHOD_NAMES, FUNCTION_PATTERNS, CLASS_PATTERNS, INTERFACE_PATTERNS, METHOD_PATTERNS, GO_METHOD_PATTERN, VARIABLE_PATTERNS, SUPPORTED_EXTENSIONS, SKIP_EXTENSIONS, CodeIngestor, execFileAsync, GitIngestor, TopologicalLinker, CODE_NODE_TYPES, DOCS_OWNED_BY_OTHER_INGESTORS, KnowledgeIngestor, BUG_TRACK_CATEGORIES, KNOWLEDGE_TRACK_CATEGORIES, ISO_DATE, SolutionBaseSchema, SolutionDocFrontmatterSchema, BUSINESS_KNOWLEDGE_TYPES, GOVERNS_SOURCE_TYPES, CODE_NODE_TYPES2, MEASURABLE_TYPES, STRATEGY_REQUIRED_SECTIONS, STRATEGY_OPTIONAL_SECTIONS, STRATEGY_KNOWN_SECTIONS, STRATEGY_PLACEHOLDER_RE, BusinessKnowledgeIngestor, CODE_NODE_TYPES3, ARCHITECTURE_ADR_H1, DecisionIngestor, REQUIREMENT_SECTIONS, SECTION_HEADING_RE, NUMBERED_ITEM_RE, CODE_NODE_TYPES4, RequirementIngestor, DEFAULT_PATTERNS, DEFAULT_BLOCKLIST, CODE_EXTENSIONS, MermaidParser, D2Parser, PlantUmlParser, DIAGRAM_EXTENSIONS, DiagramParser, HEURISTIC_PATTERNS, SCANNABLE_TYPES, KnowledgeLinker, StructuralDriftDetector, BUSINESS_NODE_TYPES, KnowledgeStagingAggregator, EXT_TO_LANGUAGE, SKIP_EXTENSIONS2, EXTRACTOR_EDGE_TYPE, ExtractionRunner, PATTERNS, TestDescriptionExtractor, EnumConstantExtractor, ValidationRuleExtractor, ApiPathExtractor, ALL_EXTRACTORS, ImageAnalysisExtractor, KNOWLEDGE_NODE_TYPES, SIMILARITY_THRESHOLD, SEVERITY_MAP, ContradictionDetector, KNOWLEDGE_TYPES, CODE_TYPES2, KNOWLEDGE_EDGE_TYPES, CoverageScorer, VALID_BUSINESS_TYPES, DEFAULT_MAX_DOCS, MAX_COLLISION_SUFFIX, KnowledgeDocMaterializer, BUSINESS_NODE_TYPES2, SNAPSHOT_NODE_TYPES, KnowledgePipelineRunner, CODE_NODE_TYPES5, RETRYABLE_STATUSES, SANITIZE_RULES, SyncManager, SUMMARIZE_PROMPT, JiraConnector, SlackConnector, ConfluenceConnector, CIConnector, CONSTRAINT_KEYWORDS, FigmaConnector, MIN_CONTENT_LENGTH, CONCEPT_ITEM_TYPES, MiroConnector, STOP_WORDS, FusionLayer, CODE_NODE_TYPES6, GraphEntropyAdapter, GraphComplexityAdapter, GraphCouplingAdapter, DEFAULT_THRESHOLD, DEFAULT_METRICS, RECOGNIZED_METRICS, GraphAnomalyAdapter, INTENTS, SIGNAL_WEIGHTS, INTENT_SIGNALS, IntentClassifier, INTENT_KEYWORDS, STOP_WORDS2, PASCAL_OR_CAMEL_RE, FILE_PATH_RE, QUOTED_RE, EntityExtractor, EntityResolver, ResponseFormatter, CompositeProbabilityStrategy, DEFAULT_PROBABILITY_FLOOR, DEFAULT_MAX_DEPTH, CascadeSimulator, ENTITY_REQUIRED_INTENTS, classifier, extractor, formatter, PHASE_NODE_TYPES, CODE_NODE_TYPES7, Assembler, GraphConstraintAdapter, DesignIngestor, CODE_PREFIX_LABELS, DesignConstraintAdapter, GraphFeedbackAdapter, DEFAULT_EDGE_TYPES, TaskIndependenceAnalyzer, ConflictPredictor, VERSION;
1647
1743
  var init_dist = __esm({
1648
1744
  "../graph/dist/index.mjs"() {
1649
1745
  NODE_TYPES = [
@@ -3392,6 +3488,23 @@ var init_dist = __esm({
3392
3488
  "variable"
3393
3489
  ];
3394
3490
  MEASURABLE_TYPES = /* @__PURE__ */ new Set(["business_process", "business_concept"]);
3491
+ STRATEGY_REQUIRED_SECTIONS = [
3492
+ "Target problem",
3493
+ "Our approach",
3494
+ "Who it's for",
3495
+ "Key metrics",
3496
+ "Tracks"
3497
+ ];
3498
+ STRATEGY_OPTIONAL_SECTIONS = [
3499
+ "Milestones",
3500
+ "Not working on",
3501
+ "Marketing"
3502
+ ];
3503
+ STRATEGY_KNOWN_SECTIONS = /* @__PURE__ */ new Set([
3504
+ ...STRATEGY_REQUIRED_SECTIONS,
3505
+ ...STRATEGY_OPTIONAL_SECTIONS
3506
+ ]);
3507
+ STRATEGY_PLACEHOLDER_RE = /^<[^>]+>\s*$/;
3395
3508
  BusinessKnowledgeIngestor = class {
3396
3509
  constructor(store) {
3397
3510
  this.store = store;
@@ -3476,6 +3589,75 @@ var init_dist = __esm({
3476
3589
  durationMs: Date.now() - start
3477
3590
  };
3478
3591
  }
3592
+ /**
3593
+ * Ingest the repo-root STRATEGY.md anchor as `business_fact` nodes — one per
3594
+ * non-empty section. Soft-fails when the file is absent (returns empty result
3595
+ * with no errors) so existing projects without a strategy doc keep working.
3596
+ *
3597
+ * Each emitted node carries `metadata.domain === 'strategy'` and
3598
+ * `metadata.source === 'STRATEGY.md'`, making the strategy domain
3599
+ * discoverable through the same filters as other business-knowledge nodes.
3600
+ */
3601
+ async ingestStrategy(strategyPath) {
3602
+ const start = Date.now();
3603
+ const errors = [];
3604
+ let raw;
3605
+ try {
3606
+ raw = await fs3.readFile(strategyPath, "utf-8");
3607
+ } catch {
3608
+ return emptyResult(Date.now() - start);
3609
+ }
3610
+ const parsed = parseStrategyMarkdown(raw);
3611
+ if (!parsed) {
3612
+ errors.push(`${strategyPath}: no frontmatter found`);
3613
+ return { ...emptyResult(Date.now() - start), errors };
3614
+ }
3615
+ const relPath = path4.basename(strategyPath);
3616
+ let nodesAdded = 0;
3617
+ for (const section of parsed.sections) {
3618
+ const node = this.buildStrategyNode(section, parsed.frontmatter, relPath);
3619
+ if (node === null) continue;
3620
+ this.store.addNode(node);
3621
+ nodesAdded++;
3622
+ }
3623
+ return {
3624
+ nodesAdded,
3625
+ nodesUpdated: 0,
3626
+ edgesAdded: 0,
3627
+ edgesUpdated: 0,
3628
+ errors,
3629
+ durationMs: Date.now() - start
3630
+ };
3631
+ }
3632
+ /**
3633
+ * Build a single STRATEGY.md `business_fact` node from a parsed section.
3634
+ * Returns null when the section is unknown, empty, or carries unfilled
3635
+ * template placeholder text — callers iterate and skip nulls.
3636
+ */
3637
+ buildStrategyNode(section, frontmatter, relPath) {
3638
+ if (!STRATEGY_KNOWN_SECTIONS.has(section.name)) return null;
3639
+ const body = section.body.trim();
3640
+ if (body.length === 0) return null;
3641
+ if (STRATEGY_PLACEHOLDER_RE.test(body)) return null;
3642
+ const productName = typeof frontmatter.name === "string" ? frontmatter.name : "unnamed-product";
3643
+ return {
3644
+ id: `bk:strategy:${slugifyStrategySection(section.name)}`,
3645
+ type: "business_fact",
3646
+ name: section.name,
3647
+ path: relPath,
3648
+ content: body,
3649
+ metadata: {
3650
+ domain: "strategy",
3651
+ source: "STRATEGY.md",
3652
+ section_name: section.name,
3653
+ product_name: productName,
3654
+ ...typeof frontmatter.last_updated === "string" && {
3655
+ last_updated: frontmatter.last_updated
3656
+ },
3657
+ ...typeof frontmatter.version === "number" && { version: frontmatter.version }
3658
+ }
3659
+ };
3660
+ }
3479
3661
  async createNodes(files, knowledgeDir, errors) {
3480
3662
  const entries = [];
3481
3663
  for (const filePath of files) {
@@ -3582,6 +3764,7 @@ var init_dist = __esm({
3582
3764
  "interface",
3583
3765
  "variable"
3584
3766
  ];
3767
+ ARCHITECTURE_ADR_H1 = /^\s*#\s+ADR[-\s]*(\d+)\s*[:\-—]\s*(.+?)\s*$/im;
3585
3768
  DecisionIngestor = class {
3586
3769
  constructor(store) {
3587
3770
  this.store = store;
@@ -3638,6 +3821,71 @@ var init_dist = __esm({
3638
3821
  durationMs: Date.now() - start
3639
3822
  };
3640
3823
  }
3824
+ /**
3825
+ * Ingest ADRs written by `harness-architecture-advisor` from
3826
+ * `docs/architecture/<topic>/ADR-<n>.md`. These files do not carry YAML
3827
+ * frontmatter — the canonical format is:
3828
+ *
3829
+ * ```
3830
+ * # ADR-<n>: <Title>
3831
+ *
3832
+ * **Date:** <date>
3833
+ * **Status:** Accepted | Proposed | Superseded | Deprecated
3834
+ * **Deciders:** <who>
3835
+ * ```
3836
+ *
3837
+ * The first directory under `architectureDir` becomes `metadata.domain`
3838
+ * (the "topic"), so projects whose only knowledge substrate is ADRs surface
3839
+ * `architecture/<topic>` as a documented domain rather than reporting empty.
3840
+ *
3841
+ * Soft-fails when the directory is absent (the common case for projects that
3842
+ * do not use the architecture-advisor convention).
3843
+ */
3844
+ async ingestArchitecture(architectureDir) {
3845
+ const start = Date.now();
3846
+ const errors = [];
3847
+ let files;
3848
+ try {
3849
+ files = await this.findArchitectureAdrFiles(architectureDir);
3850
+ } catch {
3851
+ return emptyResult(Date.now() - start);
3852
+ }
3853
+ let nodesAdded = 0;
3854
+ let edgesAdded = 0;
3855
+ for (const filePath of files) {
3856
+ const delta = await this.processArchitectureAdrFile(filePath, architectureDir, errors);
3857
+ nodesAdded += delta.nodesAdded;
3858
+ edgesAdded += delta.edgesAdded;
3859
+ }
3860
+ return {
3861
+ nodesAdded,
3862
+ nodesUpdated: 0,
3863
+ edgesAdded,
3864
+ edgesUpdated: 0,
3865
+ errors,
3866
+ durationMs: Date.now() - start
3867
+ };
3868
+ }
3869
+ /**
3870
+ * Read, parse, and add a single architecture-advisor ADR. Returns the delta
3871
+ * the caller should fold into the aggregate counts. Errors are appended to
3872
+ * the shared `errors` array rather than thrown, matching the soft-fail
3873
+ * contract of `ingest()`.
3874
+ */
3875
+ async processArchitectureAdrFile(filePath, architectureDir, errors) {
3876
+ try {
3877
+ const raw = await fs4.readFile(filePath, "utf-8");
3878
+ const parsed = parseArchitectureAdr(raw);
3879
+ if (!parsed) return { nodesAdded: 0, edgesAdded: 0 };
3880
+ const node = buildArchitectureAdrNode(parsed, filePath, architectureDir);
3881
+ this.store.addNode(node);
3882
+ const edgesAdded = this.linkToCode(parsed.body, node.id);
3883
+ return { nodesAdded: 1, edgesAdded };
3884
+ } catch (err) {
3885
+ errors.push(`${filePath}: ${err instanceof Error ? err.message : String(err)}`);
3886
+ return { nodesAdded: 0, edgesAdded: 0 };
3887
+ }
3888
+ }
3641
3889
  parseFrontmatter(raw) {
3642
3890
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
3643
3891
  if (!match) return null;
@@ -3679,6 +3927,24 @@ var init_dist = __esm({
3679
3927
  const entries = await fs4.readdir(dir, { withFileTypes: true });
3680
3928
  return entries.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "README.md").map((e) => path5.join(dir, e.name));
3681
3929
  }
3930
+ /**
3931
+ * Recursively find `ADR-*.md` files under `dir`. Skips default skip dirs
3932
+ * (node_modules etc.) to keep the scan bounded on large repos.
3933
+ */
3934
+ async findArchitectureAdrFiles(dir) {
3935
+ const results = [];
3936
+ const entries = await fs4.readdir(dir, { withFileTypes: true });
3937
+ for (const entry of entries) {
3938
+ const full = path5.join(dir, entry.name);
3939
+ if (entry.isDirectory()) {
3940
+ if (DEFAULT_SKIP_DIRS.has(entry.name)) continue;
3941
+ results.push(...await this.findArchitectureAdrFiles(full));
3942
+ } else if (entry.isFile() && entry.name.endsWith(".md") && /^ADR[-_]?\d/i.test(entry.name)) {
3943
+ results.push(full);
3944
+ }
3945
+ }
3946
+ return results;
3947
+ }
3682
3948
  };
3683
3949
  REQUIREMENT_SECTIONS = [
3684
3950
  "Observable Truths",
@@ -6222,8 +6488,10 @@ var init_dist = __esm({
6222
6488
  async run(options) {
6223
6489
  this.inferenceOptions = options.inferenceOptions ?? {};
6224
6490
  const remediations = [];
6491
+ const ingestErrors = [];
6225
6492
  const preSnapshot = this.buildSnapshot(options.domain);
6226
6493
  const extraction = await this.extract(options);
6494
+ ingestErrors.push(...extraction.errors);
6227
6495
  const postSnapshot = this.buildSnapshot(options.domain);
6228
6496
  let driftResult = this.reconcile(preSnapshot, postSnapshot);
6229
6497
  const contradictions = new ContradictionDetector().detect(this.store);
@@ -6236,7 +6504,8 @@ var init_dist = __esm({
6236
6504
  options,
6237
6505
  driftResult,
6238
6506
  gapReport,
6239
- remediations
6507
+ remediations,
6508
+ ingestErrors
6240
6509
  );
6241
6510
  iterations = loopResult.iterations;
6242
6511
  materialization = loopResult.materialization;
@@ -6250,7 +6519,8 @@ var init_dist = __esm({
6250
6519
  return this.buildResult(
6251
6520
  driftResult,
6252
6521
  iterations,
6253
- extraction,
6522
+ extraction.counts,
6523
+ ingestErrors,
6254
6524
  gapReport,
6255
6525
  remediations,
6256
6526
  contradictions,
@@ -6259,7 +6529,7 @@ var init_dist = __esm({
6259
6529
  );
6260
6530
  }
6261
6531
  /** Run the remediation convergence loop; returns iteration count and accumulated materialization. */
6262
- async runRemediationLoop(options, driftResult, gapReport, remediations) {
6532
+ async runRemediationLoop(options, driftResult, gapReport, remediations, ingestErrors) {
6263
6533
  const maxIterations = options.maxIterations ?? 5;
6264
6534
  let iterations = 1;
6265
6535
  let currentDrift = driftResult;
@@ -6280,7 +6550,8 @@ var init_dist = __esm({
6280
6550
  }
6281
6551
  }
6282
6552
  const preSnapshot = this.buildSnapshot(options.domain);
6283
- await this.extract(options);
6553
+ const reExtract = await this.extract(options);
6554
+ ingestErrors.push(...reExtract.errors);
6284
6555
  const postSnapshot = this.buildSnapshot(options.domain);
6285
6556
  currentDrift = this.reconcile(preSnapshot, postSnapshot);
6286
6557
  currentGapReport = await this.detect(options);
@@ -6295,13 +6566,14 @@ var init_dist = __esm({
6295
6566
  };
6296
6567
  }
6297
6568
  /** Assemble the final pipeline result. */
6298
- buildResult(driftResult, iterations, extraction, gaps, remediations, contradictions, coverage, materialization) {
6569
+ buildResult(driftResult, iterations, extraction, errors, gaps, remediations, contradictions, coverage, materialization) {
6299
6570
  return {
6300
6571
  verdict: this.computeVerdict(driftResult),
6301
6572
  driftScore: driftResult.driftScore,
6302
6573
  iterations,
6303
6574
  findings: driftResult.summary,
6304
6575
  extraction,
6576
+ errors: Array.from(new Set(errors)),
6305
6577
  gaps,
6306
6578
  remediations,
6307
6579
  contradictions,
@@ -6332,58 +6604,60 @@ var init_dist = __esm({
6332
6604
  try {
6333
6605
  bkResult = await bkIngestor.ingest(knowledgeDir);
6334
6606
  } catch {
6335
- bkResult = {
6336
- nodesAdded: 0,
6337
- nodesUpdated: 0,
6338
- edgesAdded: 0,
6339
- edgesUpdated: 0,
6340
- errors: [],
6341
- durationMs: 0
6342
- };
6607
+ bkResult = emptyIngestResult();
6343
6608
  }
6344
6609
  const solutionsDir = path12.join(options.projectDir, "docs", "solutions");
6345
6610
  let solutionsResult;
6346
6611
  try {
6347
6612
  solutionsResult = await bkIngestor.ingestSolutions(solutionsDir);
6348
6613
  } catch {
6349
- solutionsResult = {
6350
- nodesAdded: 0,
6351
- nodesUpdated: 0,
6352
- edgesAdded: 0,
6353
- edgesUpdated: 0,
6354
- errors: [],
6355
- durationMs: 0
6356
- };
6614
+ solutionsResult = emptyIngestResult();
6615
+ }
6616
+ const strategyPath = path12.join(options.projectDir, "STRATEGY.md");
6617
+ let strategyResult;
6618
+ try {
6619
+ strategyResult = await bkIngestor.ingestStrategy(strategyPath);
6620
+ } catch {
6621
+ strategyResult = emptyIngestResult();
6357
6622
  }
6358
6623
  bkResult = {
6359
6624
  ...bkResult,
6360
- nodesAdded: bkResult.nodesAdded + solutionsResult.nodesAdded,
6361
- errors: [...bkResult.errors, ...solutionsResult.errors]
6625
+ nodesAdded: bkResult.nodesAdded + solutionsResult.nodesAdded + strategyResult.nodesAdded,
6626
+ errors: [...bkResult.errors, ...solutionsResult.errors, ...strategyResult.errors]
6362
6627
  };
6363
6628
  const decisionsDir = path12.join(options.projectDir, "docs", "knowledge", "decisions");
6629
+ const architectureDir = path12.join(options.projectDir, "docs", "architecture");
6364
6630
  const decisionIngestor = new DecisionIngestor(this.store);
6365
6631
  let decisionResult;
6366
6632
  try {
6367
6633
  decisionResult = await decisionIngestor.ingest(decisionsDir);
6368
6634
  } catch {
6369
- decisionResult = {
6370
- nodesAdded: 0,
6371
- nodesUpdated: 0,
6372
- edgesAdded: 0,
6373
- edgesUpdated: 0,
6374
- errors: [],
6375
- durationMs: 0
6376
- };
6635
+ decisionResult = emptyIngestResult();
6636
+ }
6637
+ let architectureResult;
6638
+ try {
6639
+ architectureResult = await decisionIngestor.ingestArchitecture(architectureDir);
6640
+ } catch {
6641
+ architectureResult = emptyIngestResult();
6377
6642
  }
6643
+ decisionResult = {
6644
+ ...decisionResult,
6645
+ nodesAdded: decisionResult.nodesAdded + architectureResult.nodesAdded,
6646
+ edgesAdded: decisionResult.edgesAdded + architectureResult.edgesAdded,
6647
+ errors: [...decisionResult.errors, ...architectureResult.errors]
6648
+ };
6378
6649
  const linker = new KnowledgeLinker(this.store, extractedDir);
6379
6650
  const linkResult = await linker.link();
6380
6651
  return {
6381
- codeSignals: extractionResult.nodesAdded,
6382
- diagrams: diagramResult.nodesAdded,
6383
- linkerFacts: linkResult.factsCreated,
6384
- businessKnowledge: bkResult.nodesAdded,
6385
- decisions: decisionResult.nodesAdded,
6386
- images: imageCount
6652
+ counts: {
6653
+ codeSignals: extractionResult.nodesAdded,
6654
+ diagrams: diagramResult.nodesAdded,
6655
+ linkerFacts: linkResult.factsCreated,
6656
+ businessKnowledge: bkResult.nodesAdded,
6657
+ decisions: decisionResult.nodesAdded,
6658
+ images: imageCount
6659
+ },
6660
+ errors: [...bkResult.errors, ...decisionResult.errors]
6387
6661
  };
6388
6662
  }
6389
6663
  // ── Phase 2: RECONCILE ────────────────────────────────────────────────────
@@ -9040,8 +9314,8 @@ ${replyLines.join("\n")}`;
9040
9314
  const { edges } = this.computeDependencyGraph();
9041
9315
  const violations = [];
9042
9316
  for (const edge of edges) {
9043
- const fromRelative = relative6(rootDir, edge.from).replaceAll("\\", "/");
9044
- const toRelative = relative6(rootDir, edge.to).replaceAll("\\", "/");
9317
+ const fromRelative = relative7(rootDir, edge.from).replaceAll("\\", "/");
9318
+ const toRelative = relative7(rootDir, edge.to).replaceAll("\\", "/");
9045
9319
  const fromLayer = this.resolveLayer(fromRelative, layers);
9046
9320
  const toLayer = this.resolveLayer(toRelative, layers);
9047
9321
  if (!fromLayer || !toLayer) continue;
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  init_dist
3
- } from "./chunk-WZY5U6NS.js";
3
+ } from "./chunk-N24HCQA4.js";
4
4
  import {
5
5
  Err,
6
6
  Ok
7
- } from "./chunk-OH3NXXUY.js";
7
+ } from "./chunk-BDGTZRZ6.js";
8
8
 
9
9
  // src/persona/generators/agents-md.ts
10
10
  init_dist();
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  init_dist
3
- } from "./chunk-WZY5U6NS.js";
3
+ } from "./chunk-N24HCQA4.js";
4
4
  import {
5
5
  Err,
6
6
  Ok
7
- } from "./chunk-OH3NXXUY.js";
7
+ } from "./chunk-BDGTZRZ6.js";
8
8
 
9
9
  // src/templates/engine.ts
10
10
  init_dist();
@@ -92,7 +92,12 @@ var NON_JSON_PACKAGE_CONFIGS = /* @__PURE__ */ new Set([
92
92
  "build.gradle",
93
93
  "build.gradle.kts"
94
94
  ]);
95
- var HARNESS_CONFIG_FILES = /* @__PURE__ */ new Set(["harness.config.json", "AGENTS.md", ".harness/.gitignore"]);
95
+ var HARNESS_CONFIG_FILES = /* @__PURE__ */ new Set([
96
+ "harness.config.json",
97
+ "AGENTS.md",
98
+ ".harness/.gitignore",
99
+ ".github/workflows/ci.yml"
100
+ ]);
96
101
  var IGNORED_TEMPLATE_FILES = /* @__PURE__ */ new Set([".DS_Store", "Thumbs.db", "desktop.ini"]);
97
102
  function isHarnessConfigFile(relativePath) {
98
103
  return HARNESS_CONFIG_FILES.has(relativePath);