@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.
- package/dist/agents/personas/documentation-maintainer.yaml +3 -1
- package/dist/agents/personas/performance-guardian.yaml +23 -0
- package/dist/agents/personas/planner.yaml +27 -0
- package/dist/agents/personas/verifier.yaml +30 -0
- package/dist/agents/skills/claude-code/align-documentation/SKILL.md +13 -0
- package/dist/agents/skills/claude-code/cleanup-dead-code/SKILL.md +25 -1
- package/dist/agents/skills/claude-code/cleanup-dead-code/skill.yaml +5 -2
- package/dist/agents/skills/claude-code/detect-doc-drift/SKILL.md +12 -0
- package/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +67 -1
- package/dist/agents/skills/claude-code/enforce-architecture/skill.yaml +5 -2
- package/dist/agents/skills/claude-code/harness-accessibility/SKILL.md +281 -0
- package/dist/agents/skills/claude-code/harness-accessibility/skill.yaml +51 -0
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +119 -72
- package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +4 -2
- package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +76 -4
- package/dist/agents/skills/claude-code/harness-brainstorming/skill.yaml +2 -0
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +487 -234
- package/dist/agents/skills/claude-code/harness-code-review/skill.yaml +15 -2
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/SKILL.md +226 -0
- package/dist/agents/skills/claude-code/harness-codebase-cleanup/skill.yaml +64 -0
- package/dist/agents/skills/claude-code/harness-dependency-health/SKILL.md +35 -6
- package/dist/agents/skills/claude-code/harness-dependency-health/skill.yaml +1 -1
- package/dist/agents/skills/claude-code/harness-design/SKILL.md +265 -0
- package/dist/agents/skills/claude-code/harness-design/skill.yaml +53 -0
- package/dist/agents/skills/claude-code/harness-design-mobile/SKILL.md +336 -0
- package/dist/agents/skills/claude-code/harness-design-mobile/skill.yaml +49 -0
- package/dist/agents/skills/claude-code/harness-design-system/SKILL.md +282 -0
- package/dist/agents/skills/claude-code/harness-design-system/skill.yaml +50 -0
- package/dist/agents/skills/claude-code/harness-design-web/SKILL.md +360 -0
- package/dist/agents/skills/claude-code/harness-design-web/skill.yaml +52 -0
- package/dist/agents/skills/claude-code/harness-docs-pipeline/SKILL.md +460 -0
- package/dist/agents/skills/claude-code/harness-docs-pipeline/skill.yaml +69 -0
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +73 -8
- package/dist/agents/skills/claude-code/harness-execution/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-hotspot-detector/SKILL.md +32 -6
- package/dist/agents/skills/claude-code/harness-hotspot-detector/skill.yaml +1 -1
- package/dist/agents/skills/claude-code/harness-i18n/SKILL.md +484 -0
- package/dist/agents/skills/claude-code/harness-i18n/skill.yaml +54 -0
- package/dist/agents/skills/claude-code/harness-i18n-process/SKILL.md +388 -0
- package/dist/agents/skills/claude-code/harness-i18n-process/skill.yaml +43 -0
- package/dist/agents/skills/claude-code/harness-i18n-workflow/SKILL.md +512 -0
- package/dist/agents/skills/claude-code/harness-i18n-workflow/skill.yaml +53 -0
- package/dist/agents/skills/claude-code/harness-impact-analysis/SKILL.md +51 -6
- package/dist/agents/skills/claude-code/harness-integrity/SKILL.md +35 -1
- package/dist/agents/skills/claude-code/harness-knowledge-mapper/SKILL.md +46 -5
- package/dist/agents/skills/claude-code/harness-knowledge-mapper/skill.yaml +1 -1
- package/dist/agents/skills/claude-code/harness-onboarding/SKILL.md +19 -1
- package/dist/agents/skills/claude-code/harness-perf/SKILL.md +37 -8
- package/dist/agents/skills/claude-code/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/claude-code/harness-perf-tdd/SKILL.md +17 -4
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +57 -3
- package/dist/agents/skills/claude-code/harness-planning/skill.yaml +2 -0
- package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +29 -9
- package/dist/agents/skills/claude-code/harness-roadmap/SKILL.md +562 -0
- package/dist/agents/skills/claude-code/harness-roadmap/skill.yaml +43 -0
- package/dist/agents/skills/claude-code/harness-security-review/SKILL.md +36 -2
- package/dist/agents/skills/claude-code/harness-security-review/skill.yaml +8 -6
- package/dist/agents/skills/claude-code/harness-security-scan/skill.yaml +1 -1
- package/dist/agents/skills/claude-code/harness-soundness-review/SKILL.md +1267 -0
- package/dist/agents/skills/claude-code/harness-soundness-review/skill.yaml +48 -0
- package/dist/agents/skills/claude-code/harness-test-advisor/SKILL.md +35 -6
- package/dist/agents/skills/claude-code/harness-verification/SKILL.md +66 -0
- package/dist/agents/skills/claude-code/harness-verification/skill.yaml +1 -0
- package/dist/agents/skills/claude-code/harness-verify/SKILL.md +37 -0
- package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +15 -1
- package/dist/agents/skills/claude-code/validate-context-engineering/SKILL.md +12 -0
- package/dist/agents/skills/gemini-cli/harness-accessibility/SKILL.md +281 -0
- package/dist/agents/skills/gemini-cli/harness-accessibility/skill.yaml +51 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +119 -72
- package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +4 -2
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/SKILL.md +226 -0
- package/dist/agents/skills/gemini-cli/harness-codebase-cleanup/skill.yaml +64 -0
- package/dist/agents/skills/gemini-cli/harness-dependency-health/SKILL.md +35 -6
- package/dist/agents/skills/gemini-cli/harness-dependency-health/skill.yaml +1 -1
- package/dist/agents/skills/gemini-cli/harness-design/SKILL.md +265 -0
- package/dist/agents/skills/gemini-cli/harness-design/skill.yaml +53 -0
- package/dist/agents/skills/gemini-cli/harness-design-mobile/SKILL.md +336 -0
- package/dist/agents/skills/gemini-cli/harness-design-mobile/skill.yaml +49 -0
- package/dist/agents/skills/gemini-cli/harness-design-system/SKILL.md +282 -0
- package/dist/agents/skills/gemini-cli/harness-design-system/skill.yaml +50 -0
- package/dist/agents/skills/gemini-cli/harness-design-web/SKILL.md +360 -0
- package/dist/agents/skills/gemini-cli/harness-design-web/skill.yaml +52 -0
- package/dist/agents/skills/gemini-cli/harness-docs-pipeline/SKILL.md +460 -0
- package/dist/agents/skills/gemini-cli/harness-docs-pipeline/skill.yaml +69 -0
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/SKILL.md +32 -6
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/skill.yaml +1 -1
- package/dist/agents/skills/gemini-cli/harness-i18n/SKILL.md +484 -0
- package/dist/agents/skills/gemini-cli/harness-i18n/skill.yaml +54 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-process/SKILL.md +388 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-process/skill.yaml +43 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-workflow/SKILL.md +512 -0
- package/dist/agents/skills/gemini-cli/harness-i18n-workflow/skill.yaml +53 -0
- package/dist/agents/skills/gemini-cli/harness-impact-analysis/SKILL.md +51 -6
- package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/SKILL.md +46 -5
- package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/skill.yaml +1 -1
- package/dist/agents/skills/gemini-cli/harness-perf/SKILL.md +37 -8
- package/dist/agents/skills/gemini-cli/harness-perf/skill.yaml +3 -0
- package/dist/agents/skills/gemini-cli/harness-perf-tdd/SKILL.md +17 -4
- package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +29 -9
- package/dist/agents/skills/gemini-cli/harness-roadmap/SKILL.md +562 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap/skill.yaml +43 -0
- package/dist/agents/skills/gemini-cli/harness-security-review/skill.yaml +8 -6
- package/dist/agents/skills/gemini-cli/harness-security-scan/skill.yaml +1 -1
- package/dist/agents/skills/gemini-cli/harness-soundness-review/SKILL.md +1267 -0
- package/dist/agents/skills/gemini-cli/harness-soundness-review/skill.yaml +48 -0
- package/dist/agents/skills/gemini-cli/harness-test-advisor/SKILL.md +35 -6
- package/dist/agents/skills/node_modules/.bin/vitest +2 -2
- package/dist/agents/skills/shared/design-knowledge/anti-patterns/color.yaml +106 -0
- package/dist/agents/skills/shared/design-knowledge/anti-patterns/layout.yaml +109 -0
- package/dist/agents/skills/shared/design-knowledge/anti-patterns/motion.yaml +109 -0
- package/dist/agents/skills/shared/design-knowledge/anti-patterns/typography.yaml +112 -0
- package/dist/agents/skills/shared/design-knowledge/industries/creative.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/ecommerce.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/emerging-tech.yaml +83 -0
- package/dist/agents/skills/shared/design-knowledge/industries/fintech.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/healthcare.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/lifestyle.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/saas.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/industries/services.yaml +80 -0
- package/dist/agents/skills/shared/design-knowledge/palettes/curated.yaml +234 -0
- package/dist/agents/skills/shared/design-knowledge/platform-rules/android.yaml +125 -0
- package/dist/agents/skills/shared/design-knowledge/platform-rules/flutter.yaml +144 -0
- package/dist/agents/skills/shared/design-knowledge/platform-rules/ios.yaml +106 -0
- package/dist/agents/skills/shared/design-knowledge/platform-rules/web.yaml +102 -0
- package/dist/agents/skills/shared/design-knowledge/typography/pairings.yaml +274 -0
- package/dist/agents/skills/shared/i18n-knowledge/accessibility/intersection.yaml +142 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/encoding.yaml +67 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/formatting.yaml +106 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/layout.yaml +80 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/pluralization.yaml +80 -0
- package/dist/agents/skills/shared/i18n-knowledge/anti-patterns/string-handling.yaml +106 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/android-resources.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/apple-strings.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/backend-patterns.yaml +50 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/flutter-intl.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/i18next.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/react-intl.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/frameworks/vue-i18n.yaml +47 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/ecommerce.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/fintech.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/gaming.yaml +69 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/healthcare.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/industries/legal.yaml +66 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ar.yaml +41 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/de.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/en.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/es.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/fi.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/fr.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/he.yaml +41 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/hi.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/it.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ja.yaml +38 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ko.yaml +38 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/nl.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/pl.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/pt.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/ru.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/sv.yaml +32 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/th.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/tr.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/zh-Hans.yaml +38 -0
- package/dist/agents/skills/shared/i18n-knowledge/locales/zh-Hant.yaml +35 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/i18next-mcp.yaml +56 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/lingo-dev.yaml +56 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/lokalise.yaml +60 -0
- package/dist/agents/skills/shared/i18n-knowledge/mcp-interop/tolgee.yaml +60 -0
- package/dist/agents/skills/shared/i18n-knowledge/testing/locale-testing.yaml +107 -0
- package/dist/agents/skills/shared/i18n-knowledge/testing/pseudo-localization.yaml +86 -0
- package/dist/bin/harness.js +64 -4
- package/dist/{chunk-UDWGSL3T.js → chunk-3JWCBVUZ.js} +3 -3
- package/dist/{chunk-IUFFBBYV.js → chunk-LNI4T7R6.js} +179 -61
- package/dist/{chunk-USEYPS7F.js → chunk-SJECMKSS.js} +2250 -40
- package/dist/{dist-4MYPT3OE.js → dist-BDO5GFEM.js} +295 -14
- package/dist/{dist-RBZXXJHG.js → dist-NT3GXHQZ.js} +95 -1
- package/dist/index.d.ts +266 -7
- package/dist/index.js +7 -3
- package/dist/validate-cross-check-2OPGCGGU.js +7 -0
- package/package.json +7 -7
- 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
|
-
|
|
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
|
-
|
|
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("
|
|
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 =
|
|
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
|
|
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,
|
|
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: `${
|
|
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: ${
|
|
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,
|