@harness-engineering/cli 1.6.2 → 1.8.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 (180) hide show
  1. package/dist/agents/personas/documentation-maintainer.yaml +3 -1
  2. package/dist/agents/personas/performance-guardian.yaml +23 -0
  3. package/dist/agents/personas/planner.yaml +27 -0
  4. package/dist/agents/personas/verifier.yaml +30 -0
  5. package/dist/agents/skills/claude-code/align-documentation/SKILL.md +13 -0
  6. package/dist/agents/skills/claude-code/cleanup-dead-code/SKILL.md +25 -1
  7. package/dist/agents/skills/claude-code/cleanup-dead-code/skill.yaml +5 -2
  8. package/dist/agents/skills/claude-code/detect-doc-drift/SKILL.md +12 -0
  9. package/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +67 -1
  10. package/dist/agents/skills/claude-code/enforce-architecture/skill.yaml +5 -2
  11. package/dist/agents/skills/claude-code/harness-accessibility/SKILL.md +281 -0
  12. package/dist/agents/skills/claude-code/harness-accessibility/skill.yaml +51 -0
  13. package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +119 -72
  14. package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +4 -2
  15. package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +76 -4
  16. package/dist/agents/skills/claude-code/harness-brainstorming/skill.yaml +2 -0
  17. package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +487 -234
  18. package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +15 -2
  19. package/dist/agents/skills/claude-code/harness-codebase-cleanup/SKILL.md +226 -0
  20. package/dist/agents/skills/claude-code/harness-codebase-cleanup/skill.yaml +64 -0
  21. package/dist/agents/skills/claude-code/harness-dependency-health/SKILL.md +35 -6
  22. package/dist/agents/skills/claude-code/harness-dependency-health/skill.yaml +1 -1
  23. package/dist/agents/skills/claude-code/harness-design/SKILL.md +265 -0
  24. package/dist/agents/skills/claude-code/harness-design/skill.yaml +53 -0
  25. package/dist/agents/skills/claude-code/harness-design-mobile/SKILL.md +336 -0
  26. package/dist/agents/skills/claude-code/harness-design-mobile/skill.yaml +49 -0
  27. package/dist/agents/skills/claude-code/harness-design-system/SKILL.md +282 -0
  28. package/dist/agents/skills/claude-code/harness-design-system/skill.yaml +50 -0
  29. package/dist/agents/skills/claude-code/harness-design-web/SKILL.md +360 -0
  30. package/dist/agents/skills/claude-code/harness-design-web/skill.yaml +52 -0
  31. package/dist/agents/skills/claude-code/harness-docs-pipeline/SKILL.md +460 -0
  32. package/dist/agents/skills/claude-code/harness-docs-pipeline/skill.yaml +69 -0
  33. package/dist/agents/skills/claude-code/harness-execution/SKILL.md +73 -8
  34. package/dist/agents/skills/claude-code/harness-execution/skill.yaml +1 -0
  35. package/dist/agents/skills/claude-code/harness-hotspot-detector/SKILL.md +32 -6
  36. package/dist/agents/skills/claude-code/harness-hotspot-detector/skill.yaml +1 -1
  37. package/dist/agents/skills/claude-code/harness-i18n/SKILL.md +484 -0
  38. package/dist/agents/skills/claude-code/harness-i18n/skill.yaml +54 -0
  39. package/dist/agents/skills/claude-code/harness-i18n-process/SKILL.md +388 -0
  40. package/dist/agents/skills/claude-code/harness-i18n-process/skill.yaml +43 -0
  41. package/dist/agents/skills/claude-code/harness-i18n-workflow/SKILL.md +512 -0
  42. package/dist/agents/skills/claude-code/harness-i18n-workflow/skill.yaml +53 -0
  43. package/dist/agents/skills/claude-code/harness-impact-analysis/SKILL.md +51 -6
  44. package/dist/agents/skills/claude-code/harness-integrity/SKILL.md +35 -1
  45. package/dist/agents/skills/claude-code/harness-knowledge-mapper/SKILL.md +46 -5
  46. package/dist/agents/skills/claude-code/harness-knowledge-mapper/skill.yaml +1 -1
  47. package/dist/agents/skills/claude-code/harness-onboarding/SKILL.md +19 -1
  48. package/dist/agents/skills/claude-code/harness-perf/SKILL.md +37 -8
  49. package/dist/agents/skills/claude-code/harness-perf/skill.yaml +3 -0
  50. package/dist/agents/skills/claude-code/harness-perf-tdd/SKILL.md +17 -4
  51. package/dist/agents/skills/claude-code/harness-planning/SKILL.md +57 -3
  52. package/dist/agents/skills/claude-code/harness-planning/skill.yaml +2 -0
  53. package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +29 -9
  54. package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +562 -0
  55. package/dist/agents/skills/claude-code/harness-roadmap/skill.yaml +43 -0
  56. package/dist/agents/skills/claude-code/harness-security-review/SKILL.md +36 -2
  57. package/dist/agents/skills/claude-code/harness-security-review/skill.yaml +8 -6
  58. package/dist/agents/skills/claude-code/harness-security-scan/skill.yaml +1 -1
  59. package/dist/agents/skills/claude-code/harness-soundness-review/SKILL.md +1267 -0
  60. package/dist/agents/skills/claude-code/harness-soundness-review/skill.yaml +48 -0
  61. package/dist/agents/skills/claude-code/harness-test-advisor/SKILL.md +35 -6
  62. package/dist/agents/skills/claude-code/harness-verification/SKILL.md +66 -0
  63. package/dist/agents/skills/claude-code/harness-verification/skill.yaml +1 -0
  64. package/dist/agents/skills/claude-code/harness-verify/SKILL.md +37 -0
  65. package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +15 -1
  66. package/dist/agents/skills/claude-code/validate-context-engineering/SKILL.md +12 -0
  67. package/dist/agents/skills/gemini-cli/harness-accessibility/SKILL.md +281 -0
  68. package/dist/agents/skills/gemini-cli/harness-accessibility/skill.yaml +51 -0
  69. package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +119 -72
  70. package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +4 -2
  71. package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/SKILL.md +226 -0
  72. package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/skill.yaml +64 -0
  73. package/dist/agents/skills/gemini-cli/harness-dependency-health/SKILL.md +35 -6
  74. package/dist/agents/skills/gemini-cli/harness-dependency-health/skill.yaml +1 -1
  75. package/dist/agents/skills/gemini-cli/harness-design/SKILL.md +265 -0
  76. package/dist/agents/skills/gemini-cli/harness-design/skill.yaml +53 -0
  77. package/dist/agents/skills/gemini-cli/harness-design-mobile/SKILL.md +336 -0
  78. package/dist/agents/skills/gemini-cli/harness-design-mobile/skill.yaml +49 -0
  79. package/dist/agents/skills/gemini-cli/harness-design-system/SKILL.md +282 -0
  80. package/dist/agents/skills/gemini-cli/harness-design-system/skill.yaml +50 -0
  81. package/dist/agents/skills/gemini-cli/harness-design-web/SKILL.md +360 -0
  82. package/dist/agents/skills/gemini-cli/harness-design-web/skill.yaml +52 -0
  83. package/dist/agents/skills/gemini-cli/harness-docs-pipeline/SKILL.md +460 -0
  84. package/dist/agents/skills/gemini-cli/harness-docs-pipeline/skill.yaml +69 -0
  85. package/dist/agents/skills/gemini-cli/harness-hotspot-detector/SKILL.md +32 -6
  86. package/dist/agents/skills/gemini-cli/harness-hotspot-detector/skill.yaml +1 -1
  87. package/dist/agents/skills/gemini-cli/harness-i18n/SKILL.md +484 -0
  88. package/dist/agents/skills/gemini-cli/harness-i18n/skill.yaml +54 -0
  89. package/dist/agents/skills/gemini-cli/harness-i18n-process/SKILL.md +388 -0
  90. package/dist/agents/skills/gemini-cli/harness-i18n-process/skill.yaml +43 -0
  91. package/dist/agents/skills/gemini-cli/harness-i18n-workflow/SKILL.md +512 -0
  92. package/dist/agents/skills/gemini-cli/harness-i18n-workflow/skill.yaml +53 -0
  93. package/dist/agents/skills/gemini-cli/harness-impact-analysis/SKILL.md +51 -6
  94. package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/SKILL.md +46 -5
  95. package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/skill.yaml +1 -1
  96. package/dist/agents/skills/gemini-cli/harness-perf/SKILL.md +37 -8
  97. package/dist/agents/skills/gemini-cli/harness-perf/skill.yaml +3 -0
  98. package/dist/agents/skills/gemini-cli/harness-perf-tdd/SKILL.md +17 -4
  99. package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +29 -9
  100. package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +562 -0
  101. package/dist/agents/skills/gemini-cli/harness-roadmap/skill.yaml +43 -0
  102. package/dist/agents/skills/gemini-cli/harness-security-review/skill.yaml +8 -6
  103. package/dist/agents/skills/gemini-cli/harness-security-scan/skill.yaml +1 -1
  104. package/dist/agents/skills/gemini-cli/harness-soundness-review/SKILL.md +1267 -0
  105. package/dist/agents/skills/gemini-cli/harness-soundness-review/skill.yaml +48 -0
  106. package/dist/agents/skills/gemini-cli/harness-test-advisor/SKILL.md +35 -6
  107. package/dist/agents/skills/node_modules/.bin/vitest +2 -2
  108. package/dist/agents/skills/shared/design-knowledge/anti-patterns/color.yaml +106 -0
  109. package/dist/agents/skills/shared/design-knowledge/anti-patterns/layout.yaml +109 -0
  110. package/dist/agents/skills/shared/design-knowledge/anti-patterns/motion.yaml +109 -0
  111. package/dist/agents/skills/shared/design-knowledge/anti-patterns/typography.yaml +112 -0
  112. package/dist/agents/skills/shared/design-knowledge/industries/creative.yaml +80 -0
  113. package/dist/agents/skills/shared/design-knowledge/industries/ecommerce.yaml +80 -0
  114. package/dist/agents/skills/shared/design-knowledge/industries/emerging-tech.yaml +83 -0
  115. package/dist/agents/skills/shared/design-knowledge/industries/fintech.yaml +80 -0
  116. package/dist/agents/skills/shared/design-knowledge/industries/healthcare.yaml +80 -0
  117. package/dist/agents/skills/shared/design-knowledge/industries/lifestyle.yaml +80 -0
  118. package/dist/agents/skills/shared/design-knowledge/industries/saas.yaml +80 -0
  119. package/dist/agents/skills/shared/design-knowledge/industries/services.yaml +80 -0
  120. package/dist/agents/skills/shared/design-knowledge/palettes/curated.yaml +234 -0
  121. package/dist/agents/skills/shared/design-knowledge/platform-rules/android.yaml +125 -0
  122. package/dist/agents/skills/shared/design-knowledge/platform-rules/flutter.yaml +144 -0
  123. package/dist/agents/skills/shared/design-knowledge/platform-rules/ios.yaml +106 -0
  124. package/dist/agents/skills/shared/design-knowledge/platform-rules/web.yaml +102 -0
  125. package/dist/agents/skills/shared/design-knowledge/typography/pairings.yaml +274 -0
  126. package/dist/agents/skills/shared/i18n-knowledge/accessibility/intersection.yaml +142 -0
  127. package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/encoding.yaml +67 -0
  128. package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/formatting.yaml +106 -0
  129. package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/layout.yaml +80 -0
  130. package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/pluralization.yaml +80 -0
  131. package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/string-handling.yaml +106 -0
  132. package/dist/agents/skills/shared/i18n-knowledge/frameworks/android-resources.yaml +47 -0
  133. package/dist/agents/skills/shared/i18n-knowledge/frameworks/apple-strings.yaml +47 -0
  134. package/dist/agents/skills/shared/i18n-knowledge/frameworks/backend-patterns.yaml +50 -0
  135. package/dist/agents/skills/shared/i18n-knowledge/frameworks/flutter-intl.yaml +47 -0
  136. package/dist/agents/skills/shared/i18n-knowledge/frameworks/i18next.yaml +47 -0
  137. package/dist/agents/skills/shared/i18n-knowledge/frameworks/react-intl.yaml +47 -0
  138. package/dist/agents/skills/shared/i18n-knowledge/frameworks/vue-i18n.yaml +47 -0
  139. package/dist/agents/skills/shared/i18n-knowledge/industries/ecommerce.yaml +66 -0
  140. package/dist/agents/skills/shared/i18n-knowledge/industries/fintech.yaml +66 -0
  141. package/dist/agents/skills/shared/i18n-knowledge/industries/gaming.yaml +69 -0
  142. package/dist/agents/skills/shared/i18n-knowledge/industries/healthcare.yaml +66 -0
  143. package/dist/agents/skills/shared/i18n-knowledge/industries/legal.yaml +66 -0
  144. package/dist/agents/skills/shared/i18n-knowledge/locales/ar.yaml +41 -0
  145. package/dist/agents/skills/shared/i18n-knowledge/locales/de.yaml +35 -0
  146. package/dist/agents/skills/shared/i18n-knowledge/locales/en.yaml +32 -0
  147. package/dist/agents/skills/shared/i18n-knowledge/locales/es.yaml +35 -0
  148. package/dist/agents/skills/shared/i18n-knowledge/locales/fi.yaml +35 -0
  149. package/dist/agents/skills/shared/i18n-knowledge/locales/fr.yaml +35 -0
  150. package/dist/agents/skills/shared/i18n-knowledge/locales/he.yaml +41 -0
  151. package/dist/agents/skills/shared/i18n-knowledge/locales/hi.yaml +35 -0
  152. package/dist/agents/skills/shared/i18n-knowledge/locales/it.yaml +32 -0
  153. package/dist/agents/skills/shared/i18n-knowledge/locales/ja.yaml +38 -0
  154. package/dist/agents/skills/shared/i18n-knowledge/locales/ko.yaml +38 -0
  155. package/dist/agents/skills/shared/i18n-knowledge/locales/nl.yaml +32 -0
  156. package/dist/agents/skills/shared/i18n-knowledge/locales/pl.yaml +35 -0
  157. package/dist/agents/skills/shared/i18n-knowledge/locales/pt.yaml +32 -0
  158. package/dist/agents/skills/shared/i18n-knowledge/locales/ru.yaml +35 -0
  159. package/dist/agents/skills/shared/i18n-knowledge/locales/sv.yaml +32 -0
  160. package/dist/agents/skills/shared/i18n-knowledge/locales/th.yaml +35 -0
  161. package/dist/agents/skills/shared/i18n-knowledge/locales/tr.yaml +35 -0
  162. package/dist/agents/skills/shared/i18n-knowledge/locales/zh-Hans.yaml +38 -0
  163. package/dist/agents/skills/shared/i18n-knowledge/locales/zh-Hant.yaml +35 -0
  164. package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/i18next-mcp.yaml +56 -0
  165. package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/lingo-dev.yaml +56 -0
  166. package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/lokalise.yaml +60 -0
  167. package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/tolgee.yaml +60 -0
  168. package/dist/agents/skills/shared/i18n-knowledge/testing/locale-testing.yaml +107 -0
  169. package/dist/agents/skills/shared/i18n-knowledge/testing/pseudo-localization.yaml +86 -0
  170. package/dist/bin/harness.js +64 -4
  171. package/dist/{chunk-UDWGSL3T.js → chunk-3JWCBVUZ.js} +3 -3
  172. package/dist/{chunk-IUFFBBYV.js → chunk-LNI4T7R6.js} +179 -61
  173. package/dist/{chunk-USEYPS7F.js → chunk-SJECMKSS.js} +2250 -40
  174. package/dist/{dist-4MYPT3OE.js → dist-BDO5GFEM.js} +295 -14
  175. package/dist/{dist-RBZXXJHG.js → dist-NT3GXHQZ.js} +95 -1
  176. package/dist/index.d.ts +266 -7
  177. package/dist/index.js +7 -3
  178. package/dist/validate-cross-check-2OPGCGGU.js +7 -0
  179. package/package.json +7 -7
  180. package/dist/validate-cross-check-CPEPNLOD.js +0 -7
@@ -15,6 +15,8 @@ import * as fs3 from "fs/promises";
15
15
  import * as path4 from "path";
16
16
  import { minimatch } from "minimatch";
17
17
  import { relative as relative2 } from "path";
18
+ import * as fs4 from "fs/promises";
19
+ import * as path5 from "path";
18
20
  var NODE_TYPES = [
19
21
  // Code
20
22
  "repository",
@@ -46,7 +48,11 @@ var NODE_TYPES = [
46
48
  "layer",
47
49
  "pattern",
48
50
  "constraint",
49
- "violation"
51
+ "violation",
52
+ // Design
53
+ "design_token",
54
+ "aesthetic_intent",
55
+ "design_constraint"
50
56
  ];
51
57
  var EDGE_TYPES = [
52
58
  // Code relationships
@@ -70,7 +76,12 @@ var EDGE_TYPES = [
70
76
  "failed_in",
71
77
  // Execution relationships (future)
72
78
  "executed_by",
73
- "measured_by"
79
+ "measured_by",
80
+ // Design relationships
81
+ "uses_token",
82
+ "declares_intent",
83
+ "violates_design",
84
+ "platform_binding"
74
85
  ];
75
86
  var OBSERVABILITY_TYPES = /* @__PURE__ */ new Set(["span", "metric", "log"]);
76
87
  var CURRENT_SCHEMA_VERSION = 1;
@@ -130,6 +141,14 @@ async function loadGraph(dirPath) {
130
141
  const graphContent = await readFile(graphPath, "utf-8");
131
142
  return JSON.parse(graphContent);
132
143
  }
144
+ var POISONED_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
145
+ function safeMerge(target, source) {
146
+ for (const key of Object.keys(source)) {
147
+ if (!POISONED_KEYS.has(key)) {
148
+ target[key] = source[key];
149
+ }
150
+ }
151
+ }
133
152
  var GraphStore = class {
134
153
  db;
135
154
  nodes;
@@ -148,7 +167,7 @@ var GraphStore = class {
148
167
  addNode(node) {
149
168
  const existing = this.nodes.by("id", node.id);
150
169
  if (existing) {
151
- Object.assign(existing, node);
170
+ safeMerge(existing, node);
152
171
  this.nodes.update(existing);
153
172
  } else {
154
173
  this.nodes.insert({ ...node });
@@ -192,7 +211,7 @@ var GraphStore = class {
192
211
  });
193
212
  if (existing) {
194
213
  if (edge.metadata) {
195
- Object.assign(existing, edge);
214
+ safeMerge(existing, edge);
196
215
  this.edges.update(existing);
197
216
  }
198
217
  return;
@@ -1069,9 +1088,8 @@ var TopologicalLinker = class {
1069
1088
  return cycles;
1070
1089
  }
1071
1090
  };
1072
- var CODE_NODE_TYPES = ["file", "function", "class", "method", "interface", "variable"];
1073
1091
  function hash(text) {
1074
- return crypto.createHash("md5").update(text).digest("hex").slice(0, 8);
1092
+ return crypto.createHash("sha256").update(text).digest("hex").slice(0, 8);
1075
1093
  }
1076
1094
  function mergeResults(...results) {
1077
1095
  return {
@@ -1086,6 +1104,7 @@ function mergeResults(...results) {
1086
1104
  function emptyResult(durationMs = 0) {
1087
1105
  return { nodesAdded: 0, nodesUpdated: 0, edgesAdded: 0, edgesUpdated: 0, errors: [], durationMs };
1088
1106
  }
1107
+ var CODE_NODE_TYPES = ["file", "function", "class", "method", "interface", "variable"];
1089
1108
  var KnowledgeIngestor = class {
1090
1109
  constructor(store) {
1091
1110
  this.store = store;
@@ -1275,6 +1294,22 @@ var KnowledgeIngestor = class {
1275
1294
  }
1276
1295
  };
1277
1296
  var CODE_NODE_TYPES2 = ["file", "function", "class", "method", "interface", "variable"];
1297
+ function sanitizeExternalText(text, maxLength = 2e3) {
1298
+ let sanitized = text.replace(
1299
+ /<\/?(?:system|instruction|prompt|role|context|tool_call|function_call|assistant|human|user)[^>]*>/gi,
1300
+ ""
1301
+ ).replace(/^#{1,3}\s*(?:system|instruction|prompt)\s*[::]\s*/gim, "").replace(
1302
+ /(?:ignore|disregard|forget)\s+(?:all\s+)?(?:previous|prior|above)\s+(?:instructions?|prompts?|context)/gi,
1303
+ "[filtered]"
1304
+ ).replace(
1305
+ /you\s+are\s+now\s+(?:a\s+)?(?:helpful\s+)?(?:an?\s+)?(?:assistant|system|ai|bot|agent|tool)\b/gi,
1306
+ "[filtered]"
1307
+ );
1308
+ if (sanitized.length > maxLength) {
1309
+ sanitized = sanitized.slice(0, maxLength) + "\u2026";
1310
+ }
1311
+ return sanitized;
1312
+ }
1278
1313
  function linkToCode(store, content, sourceNodeId, edgeType, options) {
1279
1314
  let edgesCreated = 0;
1280
1315
  for (const type of CODE_NODE_TYPES2) {
@@ -1436,7 +1471,7 @@ var JiraConnector = class {
1436
1471
  store.addNode({
1437
1472
  id: nodeId,
1438
1473
  type: "issue",
1439
- name: issue.fields.summary,
1474
+ name: sanitizeExternalText(issue.fields.summary, 500),
1440
1475
  metadata: {
1441
1476
  key: issue.key,
1442
1477
  status: issue.fields.status?.name,
@@ -1446,7 +1481,9 @@ var JiraConnector = class {
1446
1481
  }
1447
1482
  });
1448
1483
  nodesAdded++;
1449
- const searchText = [issue.fields.summary, issue.fields.description ?? ""].join(" ");
1484
+ const searchText = sanitizeExternalText(
1485
+ [issue.fields.summary, issue.fields.description ?? ""].join(" ")
1486
+ );
1450
1487
  edgesAdded += linkToCode(store, searchText, nodeId, "applies_to");
1451
1488
  }
1452
1489
  startAt += maxResults;
@@ -1520,7 +1557,8 @@ var SlackConnector = class {
1520
1557
  }
1521
1558
  for (const message of data.messages) {
1522
1559
  const nodeId = `conversation:slack:${channel}:${message.ts}`;
1523
- const snippet = message.text.length > 100 ? message.text.slice(0, 100) : message.text;
1560
+ const sanitizedText = sanitizeExternalText(message.text);
1561
+ const snippet = sanitizedText.length > 100 ? sanitizedText.slice(0, 100) : sanitizedText;
1524
1562
  store.addNode({
1525
1563
  id: nodeId,
1526
1564
  type: "conversation",
@@ -1532,7 +1570,9 @@ var SlackConnector = class {
1532
1570
  }
1533
1571
  });
1534
1572
  nodesAdded++;
1535
- edgesAdded += linkToCode(store, message.text, nodeId, "references", { checkPaths: true });
1573
+ edgesAdded += linkToCode(store, sanitizedText, nodeId, "references", {
1574
+ checkPaths: true
1575
+ });
1536
1576
  }
1537
1577
  } catch (err) {
1538
1578
  errors.push(
@@ -1593,7 +1633,7 @@ var ConfluenceConnector = class {
1593
1633
  store.addNode({
1594
1634
  id: nodeId,
1595
1635
  type: "document",
1596
- name: page.title,
1636
+ name: sanitizeExternalText(page.title, 500),
1597
1637
  metadata: {
1598
1638
  source: "confluence",
1599
1639
  spaceKey,
@@ -1603,7 +1643,7 @@ var ConfluenceConnector = class {
1603
1643
  }
1604
1644
  });
1605
1645
  nodesAdded++;
1606
- const text = `${page.title} ${page.body?.storage?.value ?? ""}`;
1646
+ const text = sanitizeExternalText(`${page.title} ${page.body?.storage?.value ?? ""}`);
1607
1647
  edgesAdded += linkToCode(store, text, nodeId, "documents");
1608
1648
  }
1609
1649
  nextUrl = data._links?.next ? `${baseUrl}${data._links.next}` : null;
@@ -1666,10 +1706,11 @@ var CIConnector = class {
1666
1706
  const data = await response.json();
1667
1707
  for (const run of data.workflow_runs) {
1668
1708
  const buildId = `build:${run.id}`;
1709
+ const safeName = sanitizeExternalText(run.name, 200);
1669
1710
  store.addNode({
1670
1711
  id: buildId,
1671
1712
  type: "build",
1672
- name: `${run.name} #${run.id}`,
1713
+ name: `${safeName} #${run.id}`,
1673
1714
  metadata: {
1674
1715
  source: "github-actions",
1675
1716
  status: run.status,
@@ -1691,7 +1732,7 @@ var CIConnector = class {
1691
1732
  store.addNode({
1692
1733
  id: testResultId,
1693
1734
  type: "test_result",
1694
- name: `Failed: ${run.name} #${run.id}`,
1735
+ name: `Failed: ${safeName} #${run.id}`,
1695
1736
  metadata: {
1696
1737
  source: "github-actions",
1697
1738
  buildId: String(run.id),
@@ -2424,6 +2465,244 @@ var GraphConstraintAdapter = class {
2424
2465
  return void 0;
2425
2466
  }
2426
2467
  };
2468
+ function isDTCGToken(obj) {
2469
+ return typeof obj === "object" && obj !== null && "$value" in obj && "$type" in obj;
2470
+ }
2471
+ async function readFileOrNull(filePath) {
2472
+ try {
2473
+ return await fs4.readFile(filePath, "utf-8");
2474
+ } catch {
2475
+ return null;
2476
+ }
2477
+ }
2478
+ function parseJsonOrError(content, filePath) {
2479
+ try {
2480
+ return { data: JSON.parse(content) };
2481
+ } catch (err) {
2482
+ return {
2483
+ error: `Failed to parse ${filePath}: ${err instanceof Error ? err.message : String(err)}`
2484
+ };
2485
+ }
2486
+ }
2487
+ function walkDTCGTokens(store, obj, groupPath, topGroup, tokensPath) {
2488
+ let count = 0;
2489
+ for (const [key, value] of Object.entries(obj)) {
2490
+ if (key.startsWith("$")) continue;
2491
+ if (isDTCGToken(value)) {
2492
+ const tokenPath = [...groupPath, key].join(".");
2493
+ store.addNode({
2494
+ id: `design_token:${tokenPath}`,
2495
+ type: "design_token",
2496
+ name: tokenPath,
2497
+ path: tokensPath,
2498
+ metadata: {
2499
+ tokenType: value.$type,
2500
+ value: value.$value,
2501
+ group: topGroup || groupPath[0] || key,
2502
+ ...value.$description ? { description: value.$description } : {}
2503
+ }
2504
+ });
2505
+ count++;
2506
+ } else if (typeof value === "object" && value !== null) {
2507
+ count += walkDTCGTokens(
2508
+ store,
2509
+ value,
2510
+ [...groupPath, key],
2511
+ topGroup || key,
2512
+ tokensPath
2513
+ );
2514
+ }
2515
+ }
2516
+ return count;
2517
+ }
2518
+ function parseAestheticDirection(content) {
2519
+ const extract = (pattern) => {
2520
+ const m = content.match(pattern);
2521
+ return m ? m[1].trim() : void 0;
2522
+ };
2523
+ const result = {};
2524
+ const style = extract(/\*\*Style:\*\*\s*(.+)/);
2525
+ if (style !== void 0) result.style = style;
2526
+ const tone = extract(/\*\*Tone:\*\*\s*(.+)/);
2527
+ if (tone !== void 0) result.tone = tone;
2528
+ const differentiator = extract(/\*\*Differentiator:\*\*\s*(.+)/);
2529
+ if (differentiator !== void 0) result.differentiator = differentiator;
2530
+ const strictness = extract(/^level:\s*(strict|standard|permissive)\s*$/m);
2531
+ if (strictness !== void 0) result.strictness = strictness;
2532
+ return result;
2533
+ }
2534
+ function parseAntiPatterns(content) {
2535
+ const lines = content.split("\n");
2536
+ const patterns = [];
2537
+ let inSection = false;
2538
+ for (const line of lines) {
2539
+ if (/^##\s+Anti-Patterns/i.test(line)) {
2540
+ inSection = true;
2541
+ continue;
2542
+ }
2543
+ if (inSection && /^##\s+/.test(line)) {
2544
+ break;
2545
+ }
2546
+ if (inSection) {
2547
+ const bulletMatch = line.match(/^-\s+(.+)/);
2548
+ if (bulletMatch) {
2549
+ patterns.push(bulletMatch[1].trim());
2550
+ }
2551
+ }
2552
+ }
2553
+ return patterns;
2554
+ }
2555
+ var DesignIngestor = class {
2556
+ constructor(store) {
2557
+ this.store = store;
2558
+ }
2559
+ async ingestTokens(tokensPath) {
2560
+ const start = Date.now();
2561
+ const content = await readFileOrNull(tokensPath);
2562
+ if (content === null) return emptyResult(Date.now() - start);
2563
+ const parsed = parseJsonOrError(content, tokensPath);
2564
+ if ("error" in parsed) {
2565
+ return { ...emptyResult(Date.now() - start), errors: [parsed.error] };
2566
+ }
2567
+ const nodesAdded = walkDTCGTokens(this.store, parsed.data, [], "", tokensPath);
2568
+ return {
2569
+ nodesAdded,
2570
+ nodesUpdated: 0,
2571
+ edgesAdded: 0,
2572
+ edgesUpdated: 0,
2573
+ errors: [],
2574
+ durationMs: Date.now() - start
2575
+ };
2576
+ }
2577
+ async ingestDesignIntent(designPath) {
2578
+ const start = Date.now();
2579
+ const content = await readFileOrNull(designPath);
2580
+ if (content === null) return emptyResult(Date.now() - start);
2581
+ let nodesAdded = 0;
2582
+ const direction = parseAestheticDirection(content);
2583
+ const metadata = {};
2584
+ if (direction.style) metadata.style = direction.style;
2585
+ if (direction.tone) metadata.tone = direction.tone;
2586
+ if (direction.differentiator) metadata.differentiator = direction.differentiator;
2587
+ if (direction.strictness) metadata.strictness = direction.strictness;
2588
+ this.store.addNode({
2589
+ id: "aesthetic_intent:project",
2590
+ type: "aesthetic_intent",
2591
+ name: "project",
2592
+ path: designPath,
2593
+ metadata
2594
+ });
2595
+ nodesAdded++;
2596
+ for (const text of parseAntiPatterns(content)) {
2597
+ this.store.addNode({
2598
+ id: `design_constraint:${hash(text)}`,
2599
+ type: "design_constraint",
2600
+ name: text,
2601
+ path: designPath,
2602
+ metadata: { rule: text, severity: "warn", scope: "project" }
2603
+ });
2604
+ nodesAdded++;
2605
+ }
2606
+ return {
2607
+ nodesAdded,
2608
+ nodesUpdated: 0,
2609
+ edgesAdded: 0,
2610
+ edgesUpdated: 0,
2611
+ errors: [],
2612
+ durationMs: Date.now() - start
2613
+ };
2614
+ }
2615
+ async ingestAll(designDir) {
2616
+ const start = Date.now();
2617
+ const [tokensResult, intentResult] = await Promise.all([
2618
+ this.ingestTokens(path5.join(designDir, "tokens.json")),
2619
+ this.ingestDesignIntent(path5.join(designDir, "DESIGN.md"))
2620
+ ]);
2621
+ const merged = mergeResults(tokensResult, intentResult);
2622
+ return { ...merged, durationMs: Date.now() - start };
2623
+ }
2624
+ };
2625
+ var DesignConstraintAdapter = class {
2626
+ constructor(store) {
2627
+ this.store = store;
2628
+ }
2629
+ checkForHardcodedColors(source, file, strictness) {
2630
+ const severity = this.mapSeverity(strictness);
2631
+ const tokenNodes = this.store.findNodes({ type: "design_token" });
2632
+ const colorValues = /* @__PURE__ */ new Set();
2633
+ for (const node of tokenNodes) {
2634
+ if (node.metadata.tokenType === "color" && typeof node.metadata.value === "string") {
2635
+ colorValues.add(node.metadata.value.toLowerCase());
2636
+ }
2637
+ }
2638
+ const hexPattern = /#[0-9a-fA-F]{3,8}\b/g;
2639
+ const violations = [];
2640
+ let match;
2641
+ while ((match = hexPattern.exec(source)) !== null) {
2642
+ const hexValue = match[0];
2643
+ if (!colorValues.has(hexValue.toLowerCase())) {
2644
+ violations.push({
2645
+ code: "DESIGN-001",
2646
+ file,
2647
+ message: `Hardcoded color ${hexValue} is not in the design token set`,
2648
+ severity,
2649
+ value: hexValue
2650
+ });
2651
+ }
2652
+ }
2653
+ return violations;
2654
+ }
2655
+ checkForHardcodedFonts(source, file, strictness) {
2656
+ const severity = this.mapSeverity(strictness);
2657
+ const tokenNodes = this.store.findNodes({ type: "design_token" });
2658
+ const fontFamilies = /* @__PURE__ */ new Set();
2659
+ for (const node of tokenNodes) {
2660
+ if (node.metadata.tokenType === "typography") {
2661
+ const value = node.metadata.value;
2662
+ if (typeof value === "object" && value !== null && "fontFamily" in value) {
2663
+ fontFamilies.add(value.fontFamily.toLowerCase());
2664
+ }
2665
+ }
2666
+ }
2667
+ const fontPatterns = [/fontFamily:\s*['"]([^'"]+)['"]/g, /font-family:\s*['"]([^'"]+)['"]/g];
2668
+ const violations = [];
2669
+ const seen = /* @__PURE__ */ new Set();
2670
+ for (const pattern of fontPatterns) {
2671
+ let match;
2672
+ while ((match = pattern.exec(source)) !== null) {
2673
+ const fontName = match[1];
2674
+ if (seen.has(fontName.toLowerCase())) continue;
2675
+ seen.add(fontName.toLowerCase());
2676
+ if (!fontFamilies.has(fontName.toLowerCase())) {
2677
+ violations.push({
2678
+ code: "DESIGN-002",
2679
+ file,
2680
+ message: `Hardcoded font family "${fontName}" is not in the design token set`,
2681
+ severity,
2682
+ value: fontName
2683
+ });
2684
+ }
2685
+ }
2686
+ }
2687
+ return violations;
2688
+ }
2689
+ checkAll(source, file, strictness) {
2690
+ return [
2691
+ ...this.checkForHardcodedColors(source, file, strictness),
2692
+ ...this.checkForHardcodedFonts(source, file, strictness)
2693
+ ];
2694
+ }
2695
+ mapSeverity(strictness = "standard") {
2696
+ switch (strictness) {
2697
+ case "permissive":
2698
+ return "info";
2699
+ case "standard":
2700
+ return "warn";
2701
+ case "strict":
2702
+ return "error";
2703
+ }
2704
+ }
2705
+ };
2427
2706
  var GraphFeedbackAdapter = class {
2428
2707
  constructor(store) {
2429
2708
  this.store = store;
@@ -2501,6 +2780,8 @@ export {
2501
2780
  CodeIngestor,
2502
2781
  ConfluenceConnector,
2503
2782
  ContextQL,
2783
+ DesignConstraintAdapter,
2784
+ DesignIngestor,
2504
2785
  EDGE_TYPES,
2505
2786
  FusionLayer,
2506
2787
  GitIngestor,