@harness-engineering/cli 2.0.0 → 2.1.1
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/skills/claude-code/harness-compound/SKILL.md +153 -0
- package/dist/agents/skills/claude-code/harness-compound/skill.yaml +60 -0
- package/dist/agents/skills/claude-code/harness-knowledge-pipeline/SKILL.md +12 -1
- package/dist/agents/skills/claude-code/harness-observability/SKILL.md +2 -0
- package/dist/agents/skills/claude-code/harness-pulse/SKILL.md +138 -0
- package/dist/agents/skills/claude-code/harness-pulse/references/interview.md +77 -0
- package/dist/agents/skills/claude-code/harness-pulse/skill.yaml +61 -0
- package/dist/agents/skills/claude-code/harness-roadmap-pilot/SKILL.md +25 -1
- package/dist/agents/skills/codex/harness-compound/SKILL.md +153 -0
- package/dist/agents/skills/codex/harness-compound/skill.yaml +60 -0
- package/dist/agents/skills/codex/harness-knowledge-pipeline/SKILL.md +12 -1
- package/dist/agents/skills/codex/harness-observability/SKILL.md +2 -0
- package/dist/agents/skills/codex/harness-pulse/SKILL.md +138 -0
- package/dist/agents/skills/codex/harness-pulse/references/interview.md +77 -0
- package/dist/agents/skills/codex/harness-pulse/skill.yaml +61 -0
- package/dist/agents/skills/codex/harness-roadmap-pilot/SKILL.md +25 -1
- package/dist/agents/skills/cursor/harness-compound/SKILL.md +153 -0
- package/dist/agents/skills/cursor/harness-compound/skill.yaml +60 -0
- package/dist/agents/skills/cursor/harness-knowledge-pipeline/SKILL.md +12 -1
- package/dist/agents/skills/cursor/harness-observability/SKILL.md +2 -0
- package/dist/agents/skills/cursor/harness-pulse/SKILL.md +138 -0
- package/dist/agents/skills/cursor/harness-pulse/references/interview.md +77 -0
- package/dist/agents/skills/cursor/harness-pulse/skill.yaml +61 -0
- package/dist/agents/skills/cursor/harness-roadmap-pilot/SKILL.md +25 -1
- package/dist/agents/skills/gemini-cli/harness-compound/SKILL.md +153 -0
- package/dist/agents/skills/gemini-cli/harness-compound/skill.yaml +60 -0
- package/dist/agents/skills/gemini-cli/harness-knowledge-pipeline/SKILL.md +12 -1
- package/dist/agents/skills/gemini-cli/harness-observability/SKILL.md +2 -0
- package/dist/agents/skills/gemini-cli/harness-pulse/SKILL.md +138 -0
- package/dist/agents/skills/gemini-cli/harness-pulse/references/interview.md +77 -0
- package/dist/agents/skills/gemini-cli/harness-pulse/skill.yaml +61 -0
- package/dist/agents/skills/gemini-cli/harness-roadmap-pilot/SKILL.md +25 -1
- package/dist/agents/skills/package.json +1 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/bug-track-fixture/input.json +10 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/duplicate-detection-fixture/docs/solutions/bug-track/integration-issues/stalled-lease-cleanup.md +28 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/duplicate-detection-fixture/expected.json +4 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/duplicate-detection-fixture/input.json +10 -0
- package/dist/agents/skills/tests/fixtures/harness-compound/knowledge-track-fixture/input.json +10 -0
- package/dist/agents/skills/tests/harness-compound.test.ts +86 -0
- package/dist/{agents-md-6SAMHE7H.js → agents-md-L4X4MOWT.js} +3 -3
- package/dist/{architecture-5YR52NSV.js → architecture-WJRIYQ45.js} +4 -4
- package/dist/{assess-project-5X7TYQFM.js → assess-project-PHC2HO3V.js} +1 -1
- package/dist/bin/harness-mcp.js +16 -15
- package/dist/bin/harness.js +26 -25
- package/dist/{check-phase-gate-PLV2VDOL.js → check-phase-gate-646KY67H.js} +5 -4
- package/dist/{chunk-ZYLBIDLE.js → chunk-224XKVLP.js} +1 -1
- package/dist/{chunk-ELJ2MXMO.js → chunk-2QPHCR22.js} +9 -9
- package/dist/{chunk-SITVRO7K.js → chunk-2ZURBWEV.js} +9 -9
- package/dist/{chunk-2IBXUG6J.js → chunk-36X7TRUI.js} +2 -2
- package/dist/{chunk-6L2BU4BP.js → chunk-4HKVZO7R.js} +1 -1
- package/dist/{chunk-74YADB7T.js → chunk-7XQYOXTB.js} +96 -94
- package/dist/{chunk-S2WB4LE7.js → chunk-BMM3GXV6.js} +384 -28
- package/dist/{chunk-BYS3TQOO.js → chunk-CPYL6LJR.js} +1 -1
- package/dist/{chunk-QDRBWVVY.js → chunk-E7W3YOXL.js} +2 -2
- package/dist/{chunk-MTPHNOJW.js → chunk-FNCJ3UCU.js} +507 -244
- package/dist/{chunk-RYDPFIJY.js → chunk-JPWICLXQ.js} +1 -1
- package/dist/{chunk-RFYF7TJS.js → chunk-K4WRQTEF.js} +1835 -805
- package/dist/{chunk-DXGI7DL3.js → chunk-KTWKW6KJ.js} +1 -1
- package/dist/{chunk-JNKALGRM.js → chunk-KV7A5OZT.js} +5 -5
- package/dist/{chunk-KJD4J54I.js → chunk-LO7ZLV7S.js} +6 -1
- package/dist/{chunk-XHOGGZS7.js → chunk-QTUPHTTK.js} +1 -1
- package/dist/{chunk-R2CBBZA6.js → chunk-SVC7THFK.js} +1 -1
- package/dist/{chunk-PFM3BVVU.js → chunk-TNZYQTEE.js} +1 -1
- package/dist/{chunk-HT7HYYGT.js → chunk-VJQLUS5I.js} +1 -1
- package/dist/{chunk-6GXSJGSW.js → chunk-VKDBM3RX.js} +3 -3
- package/dist/{chunk-JZST2WZS.js → chunk-W4AFGFFB.js} +3 -3
- package/dist/{chunk-YJE23GRZ.js → chunk-YG4ZBGEH.js} +39 -5
- package/dist/{chunk-5ME3WG3G.js → chunk-YLOAQZLA.js} +5 -5
- package/dist/{chunk-7JQ7HLM4.js → chunk-YLTRFZAT.js} +8 -8
- package/dist/{chunk-BFBZK6BC.js → chunk-YWD6WXXM.js} +6 -6
- package/dist/chunk-ZCZD7FHU.js +16 -0
- package/dist/{ci-workflow-7T2XKB3P.js → ci-workflow-TOS5X527.js} +3 -3
- package/dist/{dist-77VNTHWV.js → dist-6RT2AVYU.js} +78 -2
- package/dist/{dist-42AYXCAK.js → dist-D27LJR2T.js} +7 -1
- package/dist/{docs-MSIJ6SDO.js → docs-HOJMQYDZ.js} +5 -4
- package/dist/{engine-F4P5RBE4.js → engine-D6UYH6DB.js} +3 -3
- package/dist/{entropy-GSUTIORR.js → entropy-LZ4IDGZR.js} +3 -3
- package/dist/{feedback-NST6T4HI.js → feedback-WV7EQVK7.js} +1 -1
- package/dist/{generate-agent-definitions-BOUGQIPA.js → generate-agent-definitions-ZHFFS6YG.js} +4 -4
- package/dist/glob-helper-FZPPTGJN.js +62 -0
- package/dist/{graph-loader-IAUPGLRV.js → graph-loader-5MKHAJJF.js} +1 -1
- package/dist/index.d.ts +44 -6
- package/dist/index.js +26 -25
- package/dist/{loader-6QTJC7IN.js → loader-Z23JTXIZ.js} +3 -3
- package/dist/{mcp-QFBGTUX6.js → mcp-QFZDPFNP.js} +16 -15
- package/dist/{performance-B2NAAIE5.js → performance-7ATLHTQU.js} +5 -4
- package/dist/{review-pipeline-6EYMBS6B.js → review-pipeline-COBGGXHJ.js} +3 -3
- package/dist/{runtime-VFZK6BCZ.js → runtime-KCBNQUXK.js} +3 -3
- package/dist/{scan-DB6FNYGG.js → scan-BIJYHOE7.js} +2 -1
- package/dist/{security-HRNTYHPM.js → security-MAPRIFQT.js} +1 -1
- package/dist/templates/orchestrator/harness.orchestrator.md +9 -1
- package/dist/{validate-YEMAFWJE.js → validate-74XTQR7Q.js} +4 -4
- package/dist/{validate-cross-check-DGHTJFVH.js → validate-cross-check-MI5MZ7MB.js} +3 -3
- package/package.json +7 -6
- package/dist/glob-helper-VCQXK5XY.js +0 -54
|
@@ -5,10 +5,12 @@ import {
|
|
|
5
5
|
// ../graph/dist/index.mjs
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { readFile, writeFile, mkdir, access } from "fs/promises";
|
|
8
|
-
import { createWriteStream } from "fs";
|
|
8
|
+
import { createReadStream, createWriteStream } from "fs";
|
|
9
|
+
import { createInterface } from "readline";
|
|
9
10
|
import { join } from "path";
|
|
10
11
|
import * as fs from "fs/promises";
|
|
11
12
|
import * as path from "path";
|
|
13
|
+
import { minimatch } from "minimatch";
|
|
12
14
|
import { execFile } from "child_process";
|
|
13
15
|
import { promisify } from "util";
|
|
14
16
|
import * as path2 from "path";
|
|
@@ -17,6 +19,7 @@ import * as path3 from "path";
|
|
|
17
19
|
import * as crypto from "crypto";
|
|
18
20
|
import * as fs3 from "fs/promises";
|
|
19
21
|
import * as path4 from "path";
|
|
22
|
+
import { z as z2 } from "zod";
|
|
20
23
|
import * as fs4 from "fs/promises";
|
|
21
24
|
import * as path5 from "path";
|
|
22
25
|
import * as fs5 from "fs/promises";
|
|
@@ -35,41 +38,101 @@ import * as fs10 from "fs/promises";
|
|
|
35
38
|
import * as path11 from "path";
|
|
36
39
|
import * as fs12 from "fs/promises";
|
|
37
40
|
import * as path13 from "path";
|
|
38
|
-
import { minimatch } from "minimatch";
|
|
41
|
+
import { minimatch as minimatch2 } from "minimatch";
|
|
39
42
|
import { relative as relative5 } from "path";
|
|
40
43
|
import * as fs13 from "fs/promises";
|
|
41
44
|
import * as path14 from "path";
|
|
42
|
-
function
|
|
45
|
+
function streamGraphNdjson(filePath, nodes, edges) {
|
|
43
46
|
return new Promise((resolve, reject) => {
|
|
44
47
|
const stream = createWriteStream(filePath, { encoding: "utf-8" });
|
|
45
48
|
stream.on("error", reject);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
stream.write(JSON.stringify(nodes[i]));
|
|
49
|
+
for (const node of nodes) {
|
|
50
|
+
stream.write(JSON.stringify({ kind: "node", ...node }));
|
|
51
|
+
stream.write("\n");
|
|
50
52
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
stream.write(JSON.stringify(edges[i]));
|
|
53
|
+
for (const edge of edges) {
|
|
54
|
+
stream.write(JSON.stringify({ kind: "edge", ...edge }));
|
|
55
|
+
stream.write("\n");
|
|
55
56
|
}
|
|
56
|
-
stream.write("]}");
|
|
57
57
|
stream.end(() => resolve());
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
+
function countNodesByType(nodes) {
|
|
61
|
+
const counts = {};
|
|
62
|
+
for (const node of nodes) {
|
|
63
|
+
counts[node.type] = (counts[node.type] ?? 0) + 1;
|
|
64
|
+
}
|
|
65
|
+
return counts;
|
|
66
|
+
}
|
|
60
67
|
async function saveGraph(dirPath, nodes, edges) {
|
|
61
68
|
await mkdir(dirPath, { recursive: true });
|
|
62
69
|
const metadata = {
|
|
63
70
|
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
64
71
|
lastScanTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
65
72
|
nodeCount: nodes.length,
|
|
66
|
-
edgeCount: edges.length
|
|
73
|
+
edgeCount: edges.length,
|
|
74
|
+
nodesByType: countNodesByType(nodes)
|
|
67
75
|
};
|
|
68
76
|
await Promise.all([
|
|
69
|
-
|
|
77
|
+
streamGraphNdjson(join(dirPath, "graph.json"), nodes, edges),
|
|
70
78
|
writeFile(join(dirPath, "metadata.json"), JSON.stringify(metadata, null, 2), "utf-8")
|
|
71
79
|
]);
|
|
72
80
|
}
|
|
81
|
+
async function loadGraphMetadata(dirPath) {
|
|
82
|
+
const metaPath = join(dirPath, "metadata.json");
|
|
83
|
+
try {
|
|
84
|
+
await access(metaPath);
|
|
85
|
+
} catch {
|
|
86
|
+
return { status: "not_found" };
|
|
87
|
+
}
|
|
88
|
+
let metadata;
|
|
89
|
+
try {
|
|
90
|
+
const content = await readFile(metaPath, "utf-8");
|
|
91
|
+
metadata = JSON.parse(content);
|
|
92
|
+
} catch {
|
|
93
|
+
return { status: "not_found" };
|
|
94
|
+
}
|
|
95
|
+
if (metadata.schemaVersion !== CURRENT_SCHEMA_VERSION) {
|
|
96
|
+
return {
|
|
97
|
+
status: "schema_mismatch",
|
|
98
|
+
found: metadata.schemaVersion,
|
|
99
|
+
expected: CURRENT_SCHEMA_VERSION
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return { status: "loaded", metadata };
|
|
103
|
+
}
|
|
104
|
+
async function streamReadGraph(filePath) {
|
|
105
|
+
const stream = createReadStream(filePath, { encoding: "utf-8" });
|
|
106
|
+
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
107
|
+
const nodes = [];
|
|
108
|
+
const edges = [];
|
|
109
|
+
try {
|
|
110
|
+
for await (const rawLine of rl) {
|
|
111
|
+
const line = rawLine.trim();
|
|
112
|
+
if (line === "") continue;
|
|
113
|
+
const record = JSON.parse(line);
|
|
114
|
+
if (record.kind === "node") {
|
|
115
|
+
const { kind: _kind, ...rest } = record;
|
|
116
|
+
nodes.push(rest);
|
|
117
|
+
} else if (record.kind === "edge") {
|
|
118
|
+
const { kind: _kind, ...rest } = record;
|
|
119
|
+
edges.push(rest);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch (err) {
|
|
123
|
+
if (err instanceof RangeError && /invalid string length/i.test(err.message)) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`Graph contains a record larger than V8 can hold in a single string (~512 MB). This usually means a node or edge has a multi-hundred-MB content/embedding field. Inspect ${filePath} for the offending record.`,
|
|
126
|
+
{ cause: err }
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
throw err;
|
|
130
|
+
} finally {
|
|
131
|
+
rl.close();
|
|
132
|
+
stream.close();
|
|
133
|
+
}
|
|
134
|
+
return { nodes, edges };
|
|
135
|
+
}
|
|
73
136
|
async function loadGraph(dirPath) {
|
|
74
137
|
const metaPath = join(dirPath, "metadata.json");
|
|
75
138
|
const graphPath = join(dirPath, "graph.json");
|
|
@@ -88,8 +151,8 @@ async function loadGraph(dirPath) {
|
|
|
88
151
|
expected: CURRENT_SCHEMA_VERSION
|
|
89
152
|
};
|
|
90
153
|
}
|
|
91
|
-
const
|
|
92
|
-
return { status: "loaded", graph
|
|
154
|
+
const graph = await streamReadGraph(graphPath);
|
|
155
|
+
return { status: "loaded", graph };
|
|
93
156
|
}
|
|
94
157
|
function safeMerge(target, source) {
|
|
95
158
|
for (const key of Object.keys(source)) {
|
|
@@ -224,6 +287,13 @@ function groupNodesByImpact(nodes, excludeId) {
|
|
|
224
287
|
}
|
|
225
288
|
return { tests, docs, code, other };
|
|
226
289
|
}
|
|
290
|
+
function resolveSkipDirs(options) {
|
|
291
|
+
const base = options?.skipDirs ? new Set(options.skipDirs) : new Set(DEFAULT_SKIP_DIRS);
|
|
292
|
+
if (options?.additionalSkipDirs) {
|
|
293
|
+
for (const name of options.additionalSkipDirs) base.add(name);
|
|
294
|
+
}
|
|
295
|
+
return base;
|
|
296
|
+
}
|
|
227
297
|
function isExported(lang, line, name) {
|
|
228
298
|
if (lang === "go") return /^[A-Z]/.test(name);
|
|
229
299
|
if (lang === "rust") return /^\s*pub\b/.test(line);
|
|
@@ -243,6 +313,44 @@ function isSupportedSourceFile(name) {
|
|
|
243
313
|
const ext = name.slice(name.lastIndexOf("."));
|
|
244
314
|
return SUPPORTED_EXTENSIONS.has(ext);
|
|
245
315
|
}
|
|
316
|
+
function isExcluded(relPath, patterns) {
|
|
317
|
+
if (patterns.length === 0) return false;
|
|
318
|
+
for (const pattern of patterns) {
|
|
319
|
+
if (minimatch(relPath, pattern, { dot: true, matchBase: false })) return true;
|
|
320
|
+
if (!pattern.includes("/") && minimatch(relPath, pattern, { dot: true, matchBase: true })) {
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
async function readGitignorePatterns(rootDir) {
|
|
327
|
+
let content;
|
|
328
|
+
try {
|
|
329
|
+
content = await fs.readFile(path.join(rootDir, ".gitignore"), "utf-8");
|
|
330
|
+
} catch {
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
const patterns = [];
|
|
334
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
335
|
+
const line = rawLine.trim();
|
|
336
|
+
if (line === "" || line.startsWith("#")) continue;
|
|
337
|
+
if (line.startsWith("!")) continue;
|
|
338
|
+
const rooted = line.startsWith("/");
|
|
339
|
+
const stripped = rooted ? line.slice(1) : line;
|
|
340
|
+
const isDirOnly = stripped.endsWith("/");
|
|
341
|
+
const core = isDirOnly ? stripped.slice(0, -1) : stripped;
|
|
342
|
+
if (core === "") continue;
|
|
343
|
+
if (rooted) {
|
|
344
|
+
patterns.push(isDirOnly ? `${core}/**` : core);
|
|
345
|
+
if (isDirOnly) patterns.push(`${core}/`);
|
|
346
|
+
} else {
|
|
347
|
+
patterns.push(`**/${core}`);
|
|
348
|
+
patterns.push(`**/${core}/**`);
|
|
349
|
+
if (isDirOnly) patterns.push(`**/${core}/`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return patterns;
|
|
353
|
+
}
|
|
246
354
|
function finalizeCommit(current) {
|
|
247
355
|
return {
|
|
248
356
|
hash: current.hash,
|
|
@@ -362,6 +470,25 @@ function parseFrontmatter(raw) {
|
|
|
362
470
|
body
|
|
363
471
|
};
|
|
364
472
|
}
|
|
473
|
+
function parseSolutionFrontmatter(raw) {
|
|
474
|
+
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
475
|
+
if (!match) return null;
|
|
476
|
+
const yamlBlock = match[1];
|
|
477
|
+
const body = match[2];
|
|
478
|
+
const frontmatter = {};
|
|
479
|
+
for (const line of yamlBlock.split(/\r?\n/)) {
|
|
480
|
+
const kvMatch = line.match(/^(\w+):\s*(.+)$/);
|
|
481
|
+
if (!kvMatch) continue;
|
|
482
|
+
const key = kvMatch[1];
|
|
483
|
+
const value = kvMatch[2].trim();
|
|
484
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
485
|
+
frontmatter[key] = value.slice(1, -1).split(",").map((s) => s.trim());
|
|
486
|
+
} else {
|
|
487
|
+
frontmatter[key] = value;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return { frontmatter, body };
|
|
491
|
+
}
|
|
365
492
|
function detectEarsPattern(text) {
|
|
366
493
|
const lower = text.toLowerCase();
|
|
367
494
|
if (/^if\b.+\bthen\b.+\bshall not\b/.test(lower)) return "unwanted";
|
|
@@ -1502,7 +1629,7 @@ function parseAntiPatterns(content) {
|
|
|
1502
1629
|
}
|
|
1503
1630
|
return patterns;
|
|
1504
1631
|
}
|
|
1505
|
-
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, 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, KnowledgeIngestor, 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, SKIP_DIRS, DiagramParser, HEURISTIC_PATTERNS, SCANNABLE_TYPES, KnowledgeLinker, StructuralDriftDetector, BUSINESS_NODE_TYPES, KnowledgeStagingAggregator, SKIP_DIRS2, 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, DesignConstraintAdapter, GraphFeedbackAdapter, DEFAULT_EDGE_TYPES, TaskIndependenceAnalyzer, ConflictPredictor, VERSION;
|
|
1632
|
+
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, 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, SKIP_DIRS, DiagramParser, HEURISTIC_PATTERNS, SCANNABLE_TYPES, KnowledgeLinker, StructuralDriftDetector, BUSINESS_NODE_TYPES, KnowledgeStagingAggregator, SKIP_DIRS2, 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, DesignConstraintAdapter, GraphFeedbackAdapter, DEFAULT_EDGE_TYPES, TaskIndependenceAnalyzer, ConflictPredictor, VERSION;
|
|
1506
1633
|
var init_dist = __esm({
|
|
1507
1634
|
"../graph/dist/index.mjs"() {
|
|
1508
1635
|
NODE_TYPES = [
|
|
@@ -1596,7 +1723,7 @@ var init_dist = __esm({
|
|
|
1596
1723
|
"caches"
|
|
1597
1724
|
];
|
|
1598
1725
|
OBSERVABILITY_TYPES = /* @__PURE__ */ new Set(["span", "metric", "log"]);
|
|
1599
|
-
CURRENT_SCHEMA_VERSION =
|
|
1726
|
+
CURRENT_SCHEMA_VERSION = 2;
|
|
1600
1727
|
NODE_STABILITY = {
|
|
1601
1728
|
File: "session",
|
|
1602
1729
|
Function: "session",
|
|
@@ -2026,6 +2153,72 @@ var init_dist = __esm({
|
|
|
2026
2153
|
"method",
|
|
2027
2154
|
"variable"
|
|
2028
2155
|
]);
|
|
2156
|
+
DEFAULT_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
2157
|
+
// VCS
|
|
2158
|
+
".git",
|
|
2159
|
+
".hg",
|
|
2160
|
+
".svn",
|
|
2161
|
+
// Package managers
|
|
2162
|
+
"node_modules",
|
|
2163
|
+
".pnpm-store",
|
|
2164
|
+
".yarn",
|
|
2165
|
+
"vendor",
|
|
2166
|
+
// JS/TS build outputs
|
|
2167
|
+
"dist",
|
|
2168
|
+
"build",
|
|
2169
|
+
"out",
|
|
2170
|
+
"_build",
|
|
2171
|
+
"bin",
|
|
2172
|
+
"obj",
|
|
2173
|
+
"target",
|
|
2174
|
+
"deps",
|
|
2175
|
+
// JS/TS framework / tooling caches
|
|
2176
|
+
".next",
|
|
2177
|
+
".nuxt",
|
|
2178
|
+
".svelte-kit",
|
|
2179
|
+
".turbo",
|
|
2180
|
+
".vite",
|
|
2181
|
+
".cache",
|
|
2182
|
+
".parcel-cache",
|
|
2183
|
+
".docusaurus",
|
|
2184
|
+
".wrangler",
|
|
2185
|
+
".astro",
|
|
2186
|
+
".remix",
|
|
2187
|
+
"storybook-static",
|
|
2188
|
+
// Test / coverage / reporter outputs
|
|
2189
|
+
"coverage",
|
|
2190
|
+
".nyc_output",
|
|
2191
|
+
".pytest_cache",
|
|
2192
|
+
"playwright-report",
|
|
2193
|
+
"test-results",
|
|
2194
|
+
".e2e",
|
|
2195
|
+
// Python
|
|
2196
|
+
"__pycache__",
|
|
2197
|
+
".venv",
|
|
2198
|
+
"venv",
|
|
2199
|
+
".tox",
|
|
2200
|
+
".mypy_cache",
|
|
2201
|
+
".ruff_cache",
|
|
2202
|
+
// JVM
|
|
2203
|
+
".gradle",
|
|
2204
|
+
".gradle-home",
|
|
2205
|
+
// IDE / editor
|
|
2206
|
+
".idea",
|
|
2207
|
+
".vscode",
|
|
2208
|
+
".vs",
|
|
2209
|
+
// Harness self
|
|
2210
|
+
".harness",
|
|
2211
|
+
// AI agent sandboxes (these often contain full repo clones — skipping them
|
|
2212
|
+
// prevents the walker from re-ingesting nested copies of the project)
|
|
2213
|
+
".claude",
|
|
2214
|
+
".cursor",
|
|
2215
|
+
".codex",
|
|
2216
|
+
".gemini",
|
|
2217
|
+
".aider",
|
|
2218
|
+
".agents",
|
|
2219
|
+
".agentastic",
|
|
2220
|
+
".playwright-mcp"
|
|
2221
|
+
]);
|
|
2029
2222
|
SKIP_METHOD_NAMES = /* @__PURE__ */ new Set(["constructor", "if", "for", "while", "switch"]);
|
|
2030
2223
|
FUNCTION_PATTERNS = {
|
|
2031
2224
|
python: /^def\s+(\w+)\s*\(/,
|
|
@@ -2077,10 +2270,16 @@ var init_dist = __esm({
|
|
|
2077
2270
|
]);
|
|
2078
2271
|
SKIP_EXTENSIONS = /* @__PURE__ */ new Set([".d.ts"]);
|
|
2079
2272
|
CodeIngestor = class {
|
|
2080
|
-
constructor(store) {
|
|
2273
|
+
constructor(store, options = {}) {
|
|
2081
2274
|
this.store = store;
|
|
2275
|
+
this.skipDirs = resolveSkipDirs(options);
|
|
2276
|
+
this.excludePatterns = options.excludePatterns ?? [];
|
|
2277
|
+
this.respectGitignore = options.respectGitignore ?? true;
|
|
2082
2278
|
}
|
|
2083
2279
|
store;
|
|
2280
|
+
skipDirs;
|
|
2281
|
+
excludePatterns;
|
|
2282
|
+
respectGitignore;
|
|
2084
2283
|
async ingest(rootDir) {
|
|
2085
2284
|
const start = Date.now();
|
|
2086
2285
|
const errors = [];
|
|
@@ -2170,19 +2369,55 @@ var init_dist = __esm({
|
|
|
2170
2369
|
}
|
|
2171
2370
|
files.add(relativePath);
|
|
2172
2371
|
}
|
|
2173
|
-
|
|
2372
|
+
/**
|
|
2373
|
+
* Walk `rootDir` iteratively (BFS via an explicit queue) and return absolute paths
|
|
2374
|
+
* of every supported source file that is not excluded by the configured filters.
|
|
2375
|
+
*
|
|
2376
|
+
* Iterative on purpose: a recursive walker burns one stack frame per nested
|
|
2377
|
+
* directory and crashes with `Maximum call stack size exceeded` on deeply nested
|
|
2378
|
+
* monorepos (issue #274). The queue-based form keeps memory bounded by the
|
|
2379
|
+
* frontier size rather than the deepest path.
|
|
2380
|
+
*/
|
|
2381
|
+
async findSourceFiles(rootDir) {
|
|
2174
2382
|
const results = [];
|
|
2175
|
-
const
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2383
|
+
const matchers = await this.buildExcludeMatchers(rootDir);
|
|
2384
|
+
const queue = [rootDir];
|
|
2385
|
+
while (queue.length > 0) {
|
|
2386
|
+
const dir = queue.pop();
|
|
2387
|
+
let entries;
|
|
2388
|
+
try {
|
|
2389
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
2390
|
+
} catch {
|
|
2391
|
+
continue;
|
|
2392
|
+
}
|
|
2393
|
+
for (const entry of entries) {
|
|
2394
|
+
const fullPath = path.join(dir, entry.name);
|
|
2395
|
+
const relPath = path.relative(rootDir, fullPath).replaceAll("\\", "/");
|
|
2396
|
+
if (entry.isDirectory()) {
|
|
2397
|
+
if (this.skipDirs.has(entry.name)) continue;
|
|
2398
|
+
if (isExcluded(`${relPath}/`, matchers)) continue;
|
|
2399
|
+
queue.push(fullPath);
|
|
2400
|
+
} else if (entry.isFile()) {
|
|
2401
|
+
if (!isSupportedSourceFile(entry.name)) continue;
|
|
2402
|
+
if (isExcluded(relPath, matchers)) continue;
|
|
2403
|
+
results.push(fullPath);
|
|
2404
|
+
}
|
|
2182
2405
|
}
|
|
2183
2406
|
}
|
|
2184
2407
|
return results;
|
|
2185
2408
|
}
|
|
2409
|
+
/**
|
|
2410
|
+
* Compose the exclude matchers from `excludePatterns` and (optionally) `.gitignore`.
|
|
2411
|
+
* Returns a list of minimatch-compatible patterns; an empty list means "no excludes".
|
|
2412
|
+
*/
|
|
2413
|
+
async buildExcludeMatchers(rootDir) {
|
|
2414
|
+
const patterns = [...this.excludePatterns];
|
|
2415
|
+
if (this.respectGitignore) {
|
|
2416
|
+
const gitignorePatterns = await readGitignorePatterns(rootDir);
|
|
2417
|
+
patterns.push(...gitignorePatterns);
|
|
2418
|
+
}
|
|
2419
|
+
return patterns;
|
|
2420
|
+
}
|
|
2186
2421
|
extractSymbols(content, fileId, relativePath) {
|
|
2187
2422
|
const results = [];
|
|
2188
2423
|
const lines = content.split("\n");
|
|
@@ -3032,6 +3267,46 @@ var init_dist = __esm({
|
|
|
3032
3267
|
return results;
|
|
3033
3268
|
}
|
|
3034
3269
|
};
|
|
3270
|
+
BUG_TRACK_CATEGORIES = [
|
|
3271
|
+
"build-errors",
|
|
3272
|
+
"test-failures",
|
|
3273
|
+
"runtime-errors",
|
|
3274
|
+
"performance-issues",
|
|
3275
|
+
"database-issues",
|
|
3276
|
+
"security-issues",
|
|
3277
|
+
"ui-bugs",
|
|
3278
|
+
"integration-issues",
|
|
3279
|
+
"logic-errors"
|
|
3280
|
+
];
|
|
3281
|
+
KNOWLEDGE_TRACK_CATEGORIES = [
|
|
3282
|
+
"architecture-patterns",
|
|
3283
|
+
"design-patterns",
|
|
3284
|
+
"tooling-decisions",
|
|
3285
|
+
"conventions",
|
|
3286
|
+
"dx",
|
|
3287
|
+
"best-practices"
|
|
3288
|
+
];
|
|
3289
|
+
ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
3290
|
+
SolutionBaseSchema = z2.object({
|
|
3291
|
+
module: z2.string().min(1),
|
|
3292
|
+
tags: z2.array(z2.string()),
|
|
3293
|
+
problem_type: z2.string().min(1),
|
|
3294
|
+
last_updated: z2.string().regex(ISO_DATE, "last_updated must be ISO date YYYY-MM-DD")
|
|
3295
|
+
});
|
|
3296
|
+
SolutionDocFrontmatterSchema = z2.discriminatedUnion("track", [
|
|
3297
|
+
SolutionBaseSchema.merge(
|
|
3298
|
+
z2.object({
|
|
3299
|
+
track: z2.literal("bug-track"),
|
|
3300
|
+
category: z2.enum(BUG_TRACK_CATEGORIES)
|
|
3301
|
+
})
|
|
3302
|
+
),
|
|
3303
|
+
SolutionBaseSchema.merge(
|
|
3304
|
+
z2.object({
|
|
3305
|
+
track: z2.literal("knowledge-track"),
|
|
3306
|
+
category: z2.enum(KNOWLEDGE_TRACK_CATEGORIES)
|
|
3307
|
+
})
|
|
3308
|
+
)
|
|
3309
|
+
]);
|
|
3035
3310
|
BUSINESS_KNOWLEDGE_TYPES = /* @__PURE__ */ new Set([
|
|
3036
3311
|
"business_rule",
|
|
3037
3312
|
"business_process",
|
|
@@ -3074,6 +3349,65 @@ var init_dist = __esm({
|
|
|
3074
3349
|
durationMs: Date.now() - start
|
|
3075
3350
|
};
|
|
3076
3351
|
}
|
|
3352
|
+
async ingestSolutions(solutionsDir) {
|
|
3353
|
+
const start = Date.now();
|
|
3354
|
+
const errors = [];
|
|
3355
|
+
let files;
|
|
3356
|
+
try {
|
|
3357
|
+
files = await this.findMarkdownFiles(solutionsDir);
|
|
3358
|
+
} catch {
|
|
3359
|
+
return emptyResult(Date.now() - start);
|
|
3360
|
+
}
|
|
3361
|
+
let nodesAdded = 0;
|
|
3362
|
+
for (const filePath of files) {
|
|
3363
|
+
try {
|
|
3364
|
+
const raw = await fs3.readFile(filePath, "utf-8");
|
|
3365
|
+
const parsed = parseSolutionFrontmatter(raw);
|
|
3366
|
+
if (!parsed) {
|
|
3367
|
+
errors.push(`${filePath}: no frontmatter found`);
|
|
3368
|
+
continue;
|
|
3369
|
+
}
|
|
3370
|
+
const validation = SolutionDocFrontmatterSchema.safeParse(parsed.frontmatter);
|
|
3371
|
+
if (!validation.success) {
|
|
3372
|
+
errors.push(`${filePath}: ${validation.error.message}`);
|
|
3373
|
+
continue;
|
|
3374
|
+
}
|
|
3375
|
+
if (validation.data.track !== "knowledge-track") continue;
|
|
3376
|
+
const relPath = path4.relative(solutionsDir, filePath).replaceAll("\\", "/");
|
|
3377
|
+
const filename = path4.basename(filePath, ".md");
|
|
3378
|
+
const nodeId = `bk:solutions:${validation.data.module}:${filename}`;
|
|
3379
|
+
const titleMatch = parsed.body.match(/^#\s+(.+)$/m);
|
|
3380
|
+
const name = titleMatch ? titleMatch[1].trim() : filename;
|
|
3381
|
+
const node = {
|
|
3382
|
+
id: nodeId,
|
|
3383
|
+
type: "business_concept",
|
|
3384
|
+
name,
|
|
3385
|
+
path: relPath,
|
|
3386
|
+
content: parsed.body.trim(),
|
|
3387
|
+
metadata: {
|
|
3388
|
+
domain: validation.data.module,
|
|
3389
|
+
tags: validation.data.tags,
|
|
3390
|
+
problem_type: validation.data.problem_type,
|
|
3391
|
+
last_updated: validation.data.last_updated,
|
|
3392
|
+
source: "solutions",
|
|
3393
|
+
category: validation.data.category
|
|
3394
|
+
}
|
|
3395
|
+
};
|
|
3396
|
+
this.store.addNode(node);
|
|
3397
|
+
nodesAdded++;
|
|
3398
|
+
} catch (err) {
|
|
3399
|
+
errors.push(`${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
return {
|
|
3403
|
+
nodesAdded,
|
|
3404
|
+
nodesUpdated: 0,
|
|
3405
|
+
edgesAdded: 0,
|
|
3406
|
+
edgesUpdated: 0,
|
|
3407
|
+
errors,
|
|
3408
|
+
durationMs: Date.now() - start
|
|
3409
|
+
};
|
|
3410
|
+
}
|
|
3077
3411
|
async createNodes(files, knowledgeDir, errors) {
|
|
3078
3412
|
const entries = [];
|
|
3079
3413
|
for (const filePath of files) {
|
|
@@ -5965,6 +6299,25 @@ var init_dist = __esm({
|
|
|
5965
6299
|
durationMs: 0
|
|
5966
6300
|
};
|
|
5967
6301
|
}
|
|
6302
|
+
const solutionsDir = path12.join(options.projectDir, "docs", "solutions");
|
|
6303
|
+
let solutionsResult;
|
|
6304
|
+
try {
|
|
6305
|
+
solutionsResult = await bkIngestor.ingestSolutions(solutionsDir);
|
|
6306
|
+
} catch {
|
|
6307
|
+
solutionsResult = {
|
|
6308
|
+
nodesAdded: 0,
|
|
6309
|
+
nodesUpdated: 0,
|
|
6310
|
+
edgesAdded: 0,
|
|
6311
|
+
edgesUpdated: 0,
|
|
6312
|
+
errors: [],
|
|
6313
|
+
durationMs: 0
|
|
6314
|
+
};
|
|
6315
|
+
}
|
|
6316
|
+
bkResult = {
|
|
6317
|
+
...bkResult,
|
|
6318
|
+
nodesAdded: bkResult.nodesAdded + solutionsResult.nodesAdded,
|
|
6319
|
+
errors: [...bkResult.errors, ...solutionsResult.errors]
|
|
6320
|
+
};
|
|
5968
6321
|
const decisionsDir = path12.join(options.projectDir, "docs", "knowledge", "decisions");
|
|
5969
6322
|
const decisionIngestor = new DecisionIngestor(this.store);
|
|
5970
6323
|
let decisionResult;
|
|
@@ -8667,7 +9020,7 @@ ${replyLines.join("\n")}`;
|
|
|
8667
9020
|
resolveLayer(filePath, layers) {
|
|
8668
9021
|
for (const layer of layers) {
|
|
8669
9022
|
for (const pattern of layer.patterns) {
|
|
8670
|
-
if (
|
|
9023
|
+
if (minimatch2(filePath, pattern)) {
|
|
8671
9024
|
return layer;
|
|
8672
9025
|
}
|
|
8673
9026
|
}
|
|
@@ -9359,6 +9712,7 @@ export {
|
|
|
9359
9712
|
GraphNodeSchema,
|
|
9360
9713
|
GraphEdgeSchema,
|
|
9361
9714
|
saveGraph,
|
|
9715
|
+
loadGraphMetadata,
|
|
9362
9716
|
loadGraph,
|
|
9363
9717
|
GraphStore,
|
|
9364
9718
|
VectorStore,
|
|
@@ -9368,6 +9722,8 @@ export {
|
|
|
9368
9722
|
project,
|
|
9369
9723
|
classifyNodeCategory,
|
|
9370
9724
|
groupNodesByImpact,
|
|
9725
|
+
DEFAULT_SKIP_DIRS,
|
|
9726
|
+
resolveSkipDirs,
|
|
9371
9727
|
CodeIngestor,
|
|
9372
9728
|
GitIngestor,
|
|
9373
9729
|
TopologicalLinker,
|