@harness-engineering/cli 1.25.5 → 1.25.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agents-md-COWXFHR5.js → agents-md-QPO3H5HX.js} +3 -3
- package/dist/{architecture-EYPG4ZMC.js → architecture-IJLXRHZA.js} +4 -4
- package/dist/{assess-project-JQPEVJIA.js → assess-project-QU6XIVJK.js} +1 -1
- package/dist/bin/harness-mcp.js +16 -15
- package/dist/bin/harness.js +26 -25
- package/dist/business-knowledge-6RHYJOB3.js +7 -0
- package/dist/{check-phase-gate-AJRMDGYW.js → check-phase-gate-TNY64AOS.js} +4 -4
- package/dist/{chunk-HWLHJSJQ.js → chunk-2DF6OZLG.js} +2 -2
- package/dist/{chunk-2OIPQMU5.js → chunk-AS5DQT4S.js} +9 -9
- package/dist/{chunk-YFIALHGI.js → chunk-D3XL2FLX.js} +5 -5
- package/dist/{chunk-4NK7Z3BP.js → chunk-E5Z6NTTQ.js} +1 -1
- package/dist/{chunk-KWQTMJ3B.js → chunk-FRDS4XGD.js} +1 -1
- package/dist/{chunk-KXUCIAM4.js → chunk-G5SNXUIK.js} +1 -1
- package/dist/{chunk-2TFT7XRX.js → chunk-GVNT2YC7.js} +9 -9
- package/dist/{chunk-UI6NWJJK.js → chunk-IQO7IINR.js} +1 -1
- package/dist/{chunk-ZYYVDA5K.js → chunk-IT2KORSK.js} +1 -1
- package/dist/{chunk-2X42NMPD.js → chunk-JJQ3TW2E.js} +227 -109
- package/dist/{chunk-BOQRTARD.js → chunk-JPZY7ZQX.js} +1 -1
- package/dist/{chunk-24ZGGCIW.js → chunk-K35D7HF3.js} +1 -1
- package/dist/{chunk-KDHZAL4B.js → chunk-K533WNZG.js} +38 -2
- package/dist/{chunk-WN6YIQ66.js → chunk-KVJZQ2MV.js} +1 -1
- package/dist/{chunk-Q6ZEUMOF.js → chunk-LTCEV7VF.js} +3 -3
- package/dist/{chunk-BVRWLK5U.js → chunk-LXPRO2FH.js} +2 -2
- package/dist/{chunk-2X336Q7J.js → chunk-MCDCZMKN.js} +1 -1
- package/dist/{chunk-UB6NZNJJ.js → chunk-MLOGYWLY.js} +2 -2
- package/dist/{chunk-K2SON7TI.js → chunk-NKQEMWGT.js} +333 -121
- package/dist/{chunk-PVRKHUTA.js → chunk-PCOU2UXU.js} +8 -8
- package/dist/chunk-RC5ZY3EV.js +82 -0
- package/dist/{chunk-2OM5TA56.js → chunk-SZ3Q4XEO.js} +212 -183
- package/dist/{chunk-5R2LFUU3.js → chunk-TQRCODRJ.js} +1 -1
- package/dist/{chunk-KVK3KAFQ.js → chunk-XVJRFP7W.js} +6 -6
- package/dist/{chunk-JD4FGVHH.js → chunk-YRBNAHH4.js} +4 -4
- package/dist/{chunk-KHMKAC6E.js → chunk-ZIYLIYN4.js} +115 -103
- package/dist/{ci-workflow-35KBJC2U.js → ci-workflow-FJYRFZYQ.js} +3 -3
- package/dist/{dist-RADHOOXG.js → dist-HPWNWCT6.js} +3 -1
- package/dist/{dist-UMONICND.js → dist-ZV6GO6FA.js} +2 -2
- package/dist/{docs-T5J2AJH6.js → docs-7DW3DI4Z.js} +4 -4
- package/dist/{engine-KWHV2LUX.js → engine-P7EE2IWO.js} +3 -3
- package/dist/{entropy-GEBHWBPR.js → entropy-HCXRTDFU.js} +3 -3
- package/dist/{feedback-I4QPE3RI.js → feedback-Y4FYN3NR.js} +1 -1
- package/dist/{generate-agent-definitions-3XNR77ET.js → generate-agent-definitions-3EHPIWBO.js} +4 -4
- package/dist/{graph-loader-JHQVQRUS.js → graph-loader-KXVS3YK3.js} +1 -1
- package/dist/index.d.ts +14 -8
- package/dist/index.js +26 -25
- package/dist/{loader-MN2CZXPG.js → loader-SKHF3JVV.js} +3 -3
- package/dist/{mcp-XSU77BZY.js → mcp-MWYIPDQU.js} +16 -15
- package/dist/{performance-7I5MCEFP.js → performance-ADWH5NJY.js} +4 -4
- package/dist/{review-pipeline-PWPKJXSN.js → review-pipeline-TLKE5OQD.js} +3 -3
- package/dist/{runtime-ZYEFJSGS.js → runtime-7LYAW7GU.js} +3 -3
- package/dist/{scan-MPJ6JHUY.js → scan-BGJ7TLLV.js} +1 -1
- package/dist/{security-OVTGS7DL.js → security-5XWINYVB.js} +1 -1
- package/dist/{validate-ACIP5BUO.js → validate-BFFHYHY7.js} +4 -4
- package/dist/{validate-cross-check-OWITNCHN.js → validate-cross-check-GQX7OVCR.js} +3 -3
- package/package.json +5 -5
|
@@ -5,6 +5,7 @@ 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
9
|
import { join } from "path";
|
|
9
10
|
import * as fs from "fs/promises";
|
|
10
11
|
import * as path from "path";
|
|
@@ -18,13 +19,32 @@ import * as fs3 from "fs/promises";
|
|
|
18
19
|
import * as path4 from "path";
|
|
19
20
|
import * as fs4 from "fs/promises";
|
|
20
21
|
import * as path5 from "path";
|
|
21
|
-
import { minimatch } from "minimatch";
|
|
22
|
-
import { relative as relative2 } from "path";
|
|
23
22
|
import * as fs5 from "fs/promises";
|
|
24
23
|
import * as path6 from "path";
|
|
24
|
+
import { minimatch } from "minimatch";
|
|
25
|
+
import { relative as relative3 } from "path";
|
|
26
|
+
import * as fs6 from "fs/promises";
|
|
27
|
+
import * as path7 from "path";
|
|
28
|
+
function streamGraphJson(filePath, nodes, edges) {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const stream = createWriteStream(filePath, { encoding: "utf-8" });
|
|
31
|
+
stream.on("error", reject);
|
|
32
|
+
stream.write('{"nodes":[');
|
|
33
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
34
|
+
if (i > 0) stream.write(",");
|
|
35
|
+
stream.write(JSON.stringify(nodes[i]));
|
|
36
|
+
}
|
|
37
|
+
stream.write('],"edges":[');
|
|
38
|
+
for (let i = 0; i < edges.length; i++) {
|
|
39
|
+
if (i > 0) stream.write(",");
|
|
40
|
+
stream.write(JSON.stringify(edges[i]));
|
|
41
|
+
}
|
|
42
|
+
stream.write("]}");
|
|
43
|
+
stream.end(resolve);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
25
46
|
async function saveGraph(dirPath, nodes, edges) {
|
|
26
47
|
await mkdir(dirPath, { recursive: true });
|
|
27
|
-
const graphData = { nodes, edges };
|
|
28
48
|
const metadata = {
|
|
29
49
|
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
30
50
|
lastScanTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -32,7 +52,7 @@ async function saveGraph(dirPath, nodes, edges) {
|
|
|
32
52
|
edgeCount: edges.length
|
|
33
53
|
};
|
|
34
54
|
await Promise.all([
|
|
35
|
-
|
|
55
|
+
streamGraphJson(join(dirPath, "graph.json"), nodes, edges),
|
|
36
56
|
writeFile(join(dirPath, "metadata.json"), JSON.stringify(metadata, null, 2), "utf-8")
|
|
37
57
|
]);
|
|
38
58
|
}
|
|
@@ -300,6 +320,30 @@ function parseFailureSection(section) {
|
|
|
300
320
|
}
|
|
301
321
|
};
|
|
302
322
|
}
|
|
323
|
+
function parseFrontmatter(raw) {
|
|
324
|
+
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
325
|
+
if (!match) return null;
|
|
326
|
+
const yamlBlock = match[1];
|
|
327
|
+
const body = match[2];
|
|
328
|
+
const frontmatter = {};
|
|
329
|
+
for (const line of yamlBlock.split("\n")) {
|
|
330
|
+
const kvMatch = line.match(/^(\w+):\s*(.+)$/);
|
|
331
|
+
if (!kvMatch) continue;
|
|
332
|
+
const key = kvMatch[1];
|
|
333
|
+
const value = kvMatch[2].trim();
|
|
334
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
335
|
+
frontmatter[key] = value.slice(1, -1).split(",").map((s) => s.trim());
|
|
336
|
+
} else {
|
|
337
|
+
frontmatter[key] = value;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (!frontmatter.type || typeof frontmatter.type !== "string") return null;
|
|
341
|
+
if (!frontmatter.domain || typeof frontmatter.domain !== "string") return null;
|
|
342
|
+
return {
|
|
343
|
+
frontmatter,
|
|
344
|
+
body
|
|
345
|
+
};
|
|
346
|
+
}
|
|
303
347
|
function detectEarsPattern(text) {
|
|
304
348
|
const lower = text.toLowerCase();
|
|
305
349
|
if (/^if\b.+\bthen\b.+\bshall not\b/.test(lower)) return "unwanted";
|
|
@@ -321,7 +365,7 @@ function sanitizeExternalText(text, maxLength = 2e3) {
|
|
|
321
365
|
}
|
|
322
366
|
function linkToCode(store, content, sourceNodeId, edgeType, options) {
|
|
323
367
|
let edgesCreated = 0;
|
|
324
|
-
for (const type of
|
|
368
|
+
for (const type of CODE_NODE_TYPES4) {
|
|
325
369
|
const nodes = store.findNodes({ type });
|
|
326
370
|
for (const node of nodes) {
|
|
327
371
|
if (node.name.length < 3) continue;
|
|
@@ -656,7 +700,7 @@ function isDTCGToken(obj) {
|
|
|
656
700
|
}
|
|
657
701
|
async function readFileOrNull(filePath) {
|
|
658
702
|
try {
|
|
659
|
-
return await
|
|
703
|
+
return await fs6.readFile(filePath, "utf-8");
|
|
660
704
|
} catch {
|
|
661
705
|
return null;
|
|
662
706
|
}
|
|
@@ -738,7 +782,7 @@ function parseAntiPatterns(content) {
|
|
|
738
782
|
}
|
|
739
783
|
return patterns;
|
|
740
784
|
}
|
|
741
|
-
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, REQUIREMENT_SECTIONS, SECTION_HEADING_RE, NUMBERED_ITEM_RE,
|
|
785
|
+
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, REQUIREMENT_SECTIONS, SECTION_HEADING_RE, NUMBERED_ITEM_RE, CODE_NODE_TYPES3, RequirementIngestor, CODE_NODE_TYPES4, SANITIZE_RULES, SyncManager, JiraConnector, SlackConnector, ConfluenceConnector, CIConnector, STOP_WORDS, FusionLayer, CODE_NODE_TYPES5, 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_TYPES6, Assembler, GraphConstraintAdapter, DesignIngestor, DesignConstraintAdapter, GraphFeedbackAdapter, DEFAULT_EDGE_TYPES, TaskIndependenceAnalyzer, ConflictPredictor, VERSION;
|
|
742
786
|
var init_dist = __esm({
|
|
743
787
|
"../graph/dist/index.mjs"() {
|
|
744
788
|
NODE_TYPES = [
|
|
@@ -780,6 +824,12 @@ var init_dist = __esm({
|
|
|
780
824
|
"design_constraint",
|
|
781
825
|
// Traceability
|
|
782
826
|
"requirement",
|
|
827
|
+
// Business Knowledge
|
|
828
|
+
"business_rule",
|
|
829
|
+
"business_process",
|
|
830
|
+
"business_concept",
|
|
831
|
+
"business_term",
|
|
832
|
+
"business_metric",
|
|
783
833
|
// Cache
|
|
784
834
|
"packed_summary"
|
|
785
835
|
];
|
|
@@ -816,6 +866,9 @@ var init_dist = __esm({
|
|
|
816
866
|
"requires",
|
|
817
867
|
"verified_by",
|
|
818
868
|
"tested_by",
|
|
869
|
+
// Business Knowledge relationships
|
|
870
|
+
"governs",
|
|
871
|
+
"measures",
|
|
819
872
|
// Cache relationships
|
|
820
873
|
"caches"
|
|
821
874
|
];
|
|
@@ -986,8 +1039,8 @@ var init_dist = __esm({
|
|
|
986
1039
|
}
|
|
987
1040
|
// --- Persistence ---
|
|
988
1041
|
async save(dirPath) {
|
|
989
|
-
const allNodes = Array.from(this.nodeMap.values())
|
|
990
|
-
const allEdges = Array.from(this.edgeMap.values())
|
|
1042
|
+
const allNodes = Array.from(this.nodeMap.values());
|
|
1043
|
+
const allEdges = Array.from(this.edgeMap.values());
|
|
991
1044
|
await saveGraph(dirPath, allNodes, allEdges);
|
|
992
1045
|
}
|
|
993
1046
|
async load(dirPath) {
|
|
@@ -1281,7 +1334,17 @@ var init_dist = __esm({
|
|
|
1281
1334
|
typescript: /(?:export\s+)?(?:const|let|var)\s+(\w+)/,
|
|
1282
1335
|
javascript: /(?:export\s+)?(?:const|let|var)\s+(\w+)/
|
|
1283
1336
|
};
|
|
1284
|
-
SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
1337
|
+
SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
1338
|
+
".ts",
|
|
1339
|
+
".tsx",
|
|
1340
|
+
".js",
|
|
1341
|
+
".jsx",
|
|
1342
|
+
".py",
|
|
1343
|
+
".go",
|
|
1344
|
+
".rs",
|
|
1345
|
+
".java",
|
|
1346
|
+
".groovy"
|
|
1347
|
+
]);
|
|
1285
1348
|
SKIP_EXTENSIONS = /* @__PURE__ */ new Set([".d.ts"]);
|
|
1286
1349
|
CodeIngestor = class {
|
|
1287
1350
|
constructor(store) {
|
|
@@ -1295,22 +1358,34 @@ var init_dist = __esm({
|
|
|
1295
1358
|
let edgesAdded = 0;
|
|
1296
1359
|
const files = await this.findSourceFiles(rootDir);
|
|
1297
1360
|
const nameToFiles = /* @__PURE__ */ new Map();
|
|
1298
|
-
const fileContents = /* @__PURE__ */ new Map();
|
|
1299
1361
|
for (const filePath of files) {
|
|
1300
1362
|
try {
|
|
1301
|
-
const result = await this.processFile(filePath, rootDir, nameToFiles
|
|
1363
|
+
const result = await this.processFile(filePath, rootDir, nameToFiles);
|
|
1302
1364
|
nodesAdded += result.nodesAdded;
|
|
1303
1365
|
edgesAdded += result.edgesAdded;
|
|
1304
1366
|
} catch (err) {
|
|
1305
1367
|
errors.push(`${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1306
1368
|
}
|
|
1307
1369
|
}
|
|
1308
|
-
const
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1370
|
+
for (const filePath of files) {
|
|
1371
|
+
try {
|
|
1372
|
+
const relativePath = path.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
1373
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
1374
|
+
const callsEdges = this.extractCallsEdgesForFile(relativePath, content, nameToFiles);
|
|
1375
|
+
for (const edge of callsEdges) {
|
|
1376
|
+
this.store.addEdge(edge);
|
|
1377
|
+
edgesAdded++;
|
|
1378
|
+
}
|
|
1379
|
+
} catch {
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
for (const filePath of files) {
|
|
1383
|
+
try {
|
|
1384
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
1385
|
+
edgesAdded += this.extractReqAnnotationsForFile(filePath, content, rootDir);
|
|
1386
|
+
} catch {
|
|
1387
|
+
}
|
|
1312
1388
|
}
|
|
1313
|
-
edgesAdded += this.extractReqAnnotations(fileContents, rootDir);
|
|
1314
1389
|
return {
|
|
1315
1390
|
nodesAdded,
|
|
1316
1391
|
nodesUpdated: 0,
|
|
@@ -1320,14 +1395,13 @@ var init_dist = __esm({
|
|
|
1320
1395
|
durationMs: Date.now() - start
|
|
1321
1396
|
};
|
|
1322
1397
|
}
|
|
1323
|
-
async processFile(filePath, rootDir, nameToFiles
|
|
1398
|
+
async processFile(filePath, rootDir, nameToFiles) {
|
|
1324
1399
|
let nodesAdded = 0;
|
|
1325
1400
|
let edgesAdded = 0;
|
|
1326
1401
|
const relativePath = path.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
1327
1402
|
const content = await fs.readFile(filePath, "utf-8");
|
|
1328
1403
|
const stat2 = await fs.stat(filePath);
|
|
1329
1404
|
const fileId = `file:${relativePath}`;
|
|
1330
|
-
fileContents.set(relativePath, content);
|
|
1331
1405
|
const fileNode = {
|
|
1332
1406
|
id: fileId,
|
|
1333
1407
|
type: "file",
|
|
@@ -1367,7 +1441,7 @@ var init_dist = __esm({
|
|
|
1367
1441
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
1368
1442
|
for (const entry of entries) {
|
|
1369
1443
|
const fullPath = path.join(dir, entry.name);
|
|
1370
|
-
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist") {
|
|
1444
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && entry.name !== "target" && entry.name !== "build" && entry.name !== ".git" && entry.name !== "__pycache__" && entry.name !== ".venv" && entry.name !== ".turbo" && entry.name !== ".harness" && entry.name !== ".next" && entry.name !== ".vscode" && entry.name !== ".idea" && entry.name !== "vendor" && entry.name !== "out" && entry.name !== ".gradle" && entry.name !== ".gradle-home" && entry.name !== "bin" && entry.name !== "obj" && entry.name !== "venv" && entry.name !== "_build" && entry.name !== "deps" && entry.name !== "coverage" && entry.name !== ".nyc_output") {
|
|
1371
1445
|
results.push(...await this.findSourceFiles(fullPath));
|
|
1372
1446
|
} else if (entry.isFile() && isSupportedSourceFile(entry.name)) {
|
|
1373
1447
|
results.push(fullPath);
|
|
@@ -1382,22 +1456,23 @@ var init_dist = __esm({
|
|
|
1382
1456
|
const ctx = { className: null, classId: null, insideClass: false, braceDepth: 0 };
|
|
1383
1457
|
for (let i = 0; i < lines.length; i++) {
|
|
1384
1458
|
const line = lines[i];
|
|
1385
|
-
|
|
1386
|
-
this.updatePythonClassContext(lines, i, ctx);
|
|
1387
|
-
}
|
|
1388
|
-
if (this.tryExtractFunction(line, lines, i, fileId, relativePath, ctx, results, lang))
|
|
1389
|
-
continue;
|
|
1390
|
-
if (this.tryExtractClass(line, lines, i, fileId, relativePath, ctx, results, lang)) continue;
|
|
1391
|
-
if (this.tryExtractInterface(line, lines, i, fileId, relativePath, ctx, results, lang))
|
|
1392
|
-
continue;
|
|
1393
|
-
if (this.tryEnterImplBlock(line, lang, relativePath, ctx)) continue;
|
|
1394
|
-
if (lang !== "python" && this.updateClassContext(line, ctx)) continue;
|
|
1395
|
-
if (this.tryExtractMethod(line, lines, i, fileId, relativePath, ctx, results, lang)) continue;
|
|
1396
|
-
if (ctx.insideClass) continue;
|
|
1397
|
-
this.tryExtractVariable(line, i, fileId, relativePath, results, lang);
|
|
1459
|
+
this.processSymbolLine(line, lines, i, fileId, relativePath, ctx, results, lang);
|
|
1398
1460
|
}
|
|
1399
1461
|
return results;
|
|
1400
1462
|
}
|
|
1463
|
+
processSymbolLine(line, lines, i, fileId, relativePath, ctx, results, lang) {
|
|
1464
|
+
if (lang === "python") {
|
|
1465
|
+
this.updatePythonClassContext(lines, i, ctx);
|
|
1466
|
+
}
|
|
1467
|
+
if (this.tryExtractFunction(line, lines, i, fileId, relativePath, ctx, results, lang)) return;
|
|
1468
|
+
if (this.tryExtractClass(line, lines, i, fileId, relativePath, ctx, results, lang)) return;
|
|
1469
|
+
if (this.tryExtractInterface(line, lines, i, fileId, relativePath, ctx, results, lang)) return;
|
|
1470
|
+
if (this.tryEnterImplBlock(line, lang, relativePath, ctx)) return;
|
|
1471
|
+
if (lang !== "python" && this.updateClassContext(line, ctx)) return;
|
|
1472
|
+
if (this.tryExtractMethod(line, lines, i, fileId, relativePath, ctx, results, lang)) return;
|
|
1473
|
+
if (ctx.insideClass) return;
|
|
1474
|
+
this.tryExtractVariable(line, i, fileId, relativePath, results, lang);
|
|
1475
|
+
}
|
|
1401
1476
|
matchFunction(line, lang) {
|
|
1402
1477
|
if (lang === "java") return null;
|
|
1403
1478
|
const pattern = FUNCTION_PATTERNS[lang];
|
|
@@ -1645,33 +1720,31 @@ var init_dist = __esm({
|
|
|
1645
1720
|
return false;
|
|
1646
1721
|
}
|
|
1647
1722
|
/**
|
|
1648
|
-
*
|
|
1723
|
+
* Scan a file for identifiers matching known callable names,
|
|
1649
1724
|
* then create file-to-file "calls" edges. Uses regex heuristic (not AST).
|
|
1650
1725
|
*/
|
|
1651
|
-
|
|
1726
|
+
extractCallsEdgesForFile(relativePath, content, nameToFiles) {
|
|
1652
1727
|
const edges = [];
|
|
1653
1728
|
const seen = /* @__PURE__ */ new Set();
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
});
|
|
1674
|
-
}
|
|
1729
|
+
const callerFileId = `file:${relativePath}`;
|
|
1730
|
+
const callPattern = /\b([a-zA-Z_$][\w$]*)\s*\(/g;
|
|
1731
|
+
let match;
|
|
1732
|
+
while ((match = callPattern.exec(content)) !== null) {
|
|
1733
|
+
const name = match[1];
|
|
1734
|
+
const targetFiles = nameToFiles.get(name);
|
|
1735
|
+
if (!targetFiles) continue;
|
|
1736
|
+
for (const targetFile of targetFiles) {
|
|
1737
|
+
if (targetFile === relativePath) continue;
|
|
1738
|
+
const targetFileId = `file:${targetFile}`;
|
|
1739
|
+
const key = `${callerFileId}|${targetFileId}`;
|
|
1740
|
+
if (seen.has(key)) continue;
|
|
1741
|
+
seen.add(key);
|
|
1742
|
+
edges.push({
|
|
1743
|
+
from: callerFileId,
|
|
1744
|
+
to: targetFileId,
|
|
1745
|
+
type: "calls",
|
|
1746
|
+
metadata: { confidence: "regex" }
|
|
1747
|
+
});
|
|
1675
1748
|
}
|
|
1676
1749
|
}
|
|
1677
1750
|
return edges;
|
|
@@ -1816,6 +1889,7 @@ var init_dist = __esm({
|
|
|
1816
1889
|
if (/\.go$/.test(filePath)) return "go";
|
|
1817
1890
|
if (/\.rs$/.test(filePath)) return "rust";
|
|
1818
1891
|
if (/\.java$/.test(filePath)) return "java";
|
|
1892
|
+
if (/\.groovy$/.test(filePath)) return "java";
|
|
1819
1893
|
return "unknown";
|
|
1820
1894
|
}
|
|
1821
1895
|
/**
|
|
@@ -1823,40 +1897,38 @@ var init_dist = __esm({
|
|
|
1823
1897
|
* linking requirement nodes to the annotated files.
|
|
1824
1898
|
* Format: // @req <feature-name>#<index>
|
|
1825
1899
|
*/
|
|
1826
|
-
|
|
1900
|
+
extractReqAnnotationsForFile(filePath, content, rootDir) {
|
|
1827
1901
|
const REQ_TAG = /(?:\/\/|#|\/\*)\s*@req\s+([\w-]+)#(\d+)/g;
|
|
1828
1902
|
const reqNodes = this.store.findNodes({ type: "requirement" });
|
|
1829
1903
|
let edgesAdded = 0;
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1904
|
+
let match;
|
|
1905
|
+
REQ_TAG.lastIndex = 0;
|
|
1906
|
+
while ((match = REQ_TAG.exec(content)) !== null) {
|
|
1907
|
+
const featureName = match[1];
|
|
1908
|
+
const reqIndex = parseInt(match[2], 10);
|
|
1909
|
+
const reqNode = reqNodes.find(
|
|
1910
|
+
(n) => n.metadata.featureName === featureName && n.metadata.index === reqIndex
|
|
1911
|
+
);
|
|
1912
|
+
if (!reqNode) {
|
|
1913
|
+
console.warn(
|
|
1914
|
+
`@req annotation references non-existent requirement: ${featureName}#${reqIndex} in ${filePath}`
|
|
1838
1915
|
);
|
|
1839
|
-
|
|
1840
|
-
console.warn(
|
|
1841
|
-
`@req annotation references non-existent requirement: ${featureName}#${reqIndex} in ${filePath}`
|
|
1842
|
-
);
|
|
1843
|
-
continue;
|
|
1844
|
-
}
|
|
1845
|
-
const relPath = path.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
1846
|
-
const fileNodeId = `file:${relPath}`;
|
|
1847
|
-
this.store.addEdge({
|
|
1848
|
-
from: reqNode.id,
|
|
1849
|
-
to: fileNodeId,
|
|
1850
|
-
type: "verified_by",
|
|
1851
|
-
confidence: 1,
|
|
1852
|
-
metadata: {
|
|
1853
|
-
method: "annotation",
|
|
1854
|
-
tag: `@req ${featureName}#${reqIndex}`,
|
|
1855
|
-
confidence: 1
|
|
1856
|
-
}
|
|
1857
|
-
});
|
|
1858
|
-
edgesAdded++;
|
|
1916
|
+
continue;
|
|
1859
1917
|
}
|
|
1918
|
+
const relPath = path.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
1919
|
+
const fileNodeId = `file:${relPath}`;
|
|
1920
|
+
this.store.addEdge({
|
|
1921
|
+
from: reqNode.id,
|
|
1922
|
+
to: fileNodeId,
|
|
1923
|
+
type: "verified_by",
|
|
1924
|
+
confidence: 1,
|
|
1925
|
+
metadata: {
|
|
1926
|
+
method: "annotation",
|
|
1927
|
+
tag: `@req ${featureName}#${reqIndex}`,
|
|
1928
|
+
confidence: 1
|
|
1929
|
+
}
|
|
1930
|
+
});
|
|
1931
|
+
edgesAdded++;
|
|
1860
1932
|
}
|
|
1861
1933
|
return edgesAdded;
|
|
1862
1934
|
}
|
|
@@ -2217,7 +2289,146 @@ var init_dist = __esm({
|
|
|
2217
2289
|
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
2218
2290
|
for (const entry of entries) {
|
|
2219
2291
|
const fullPath = path3.join(dir, entry.name);
|
|
2220
|
-
if (entry.isDirectory()) {
|
|
2292
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && entry.name !== "target" && entry.name !== "build" && entry.name !== ".git" && entry.name !== ".gradle" && entry.name !== ".harness" && entry.name !== "vendor" && entry.name !== "bin" && entry.name !== "obj" && entry.name !== "venv" && entry.name !== "_build" && entry.name !== "deps" && entry.name !== "coverage") {
|
|
2293
|
+
results.push(...await this.findMarkdownFiles(fullPath));
|
|
2294
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2295
|
+
results.push(fullPath);
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
return results;
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
BUSINESS_KNOWLEDGE_TYPES = /* @__PURE__ */ new Set([
|
|
2302
|
+
"business_rule",
|
|
2303
|
+
"business_process",
|
|
2304
|
+
"business_concept",
|
|
2305
|
+
"business_term",
|
|
2306
|
+
"business_metric"
|
|
2307
|
+
]);
|
|
2308
|
+
GOVERNS_SOURCE_TYPES = /* @__PURE__ */ new Set(["business_rule", "business_process"]);
|
|
2309
|
+
CODE_NODE_TYPES2 = [
|
|
2310
|
+
"file",
|
|
2311
|
+
"function",
|
|
2312
|
+
"class",
|
|
2313
|
+
"method",
|
|
2314
|
+
"interface",
|
|
2315
|
+
"variable"
|
|
2316
|
+
];
|
|
2317
|
+
MEASURABLE_TYPES = /* @__PURE__ */ new Set(["business_process", "business_concept"]);
|
|
2318
|
+
BusinessKnowledgeIngestor = class {
|
|
2319
|
+
constructor(store) {
|
|
2320
|
+
this.store = store;
|
|
2321
|
+
}
|
|
2322
|
+
store;
|
|
2323
|
+
async ingest(knowledgeDir) {
|
|
2324
|
+
const start = Date.now();
|
|
2325
|
+
const errors = [];
|
|
2326
|
+
let files;
|
|
2327
|
+
try {
|
|
2328
|
+
files = await this.findMarkdownFiles(knowledgeDir);
|
|
2329
|
+
} catch {
|
|
2330
|
+
return emptyResult(Date.now() - start);
|
|
2331
|
+
}
|
|
2332
|
+
const nodeEntries = await this.createNodes(files, knowledgeDir, errors);
|
|
2333
|
+
const edgesAdded = this.createEdges(nodeEntries);
|
|
2334
|
+
return {
|
|
2335
|
+
nodesAdded: nodeEntries.length,
|
|
2336
|
+
nodesUpdated: 0,
|
|
2337
|
+
edgesAdded,
|
|
2338
|
+
edgesUpdated: 0,
|
|
2339
|
+
errors,
|
|
2340
|
+
durationMs: Date.now() - start
|
|
2341
|
+
};
|
|
2342
|
+
}
|
|
2343
|
+
async createNodes(files, knowledgeDir, errors) {
|
|
2344
|
+
const entries = [];
|
|
2345
|
+
for (const filePath of files) {
|
|
2346
|
+
try {
|
|
2347
|
+
const entry = await this.parseAndAddNode(filePath, knowledgeDir);
|
|
2348
|
+
if (entry) entries.push(entry);
|
|
2349
|
+
} catch (err) {
|
|
2350
|
+
errors.push(`${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
return entries;
|
|
2354
|
+
}
|
|
2355
|
+
async parseAndAddNode(filePath, knowledgeDir) {
|
|
2356
|
+
const raw = await fs3.readFile(filePath, "utf-8");
|
|
2357
|
+
const parsed = parseFrontmatter(raw);
|
|
2358
|
+
if (!parsed) return null;
|
|
2359
|
+
const { frontmatter, body } = parsed;
|
|
2360
|
+
if (!BUSINESS_KNOWLEDGE_TYPES.has(frontmatter.type)) return null;
|
|
2361
|
+
const relPath = path4.relative(knowledgeDir, filePath).replaceAll("\\", "/");
|
|
2362
|
+
const domain = frontmatter.domain ?? relPath.split("/")[0] ?? "unknown";
|
|
2363
|
+
const filename = path4.basename(filePath, ".md");
|
|
2364
|
+
const nodeId = `bk:${domain}:${filename}`;
|
|
2365
|
+
const titleMatch = body.match(/^#\s+(.+)$/m);
|
|
2366
|
+
const name = titleMatch ? titleMatch[1].trim() : filename;
|
|
2367
|
+
const node = {
|
|
2368
|
+
id: nodeId,
|
|
2369
|
+
type: frontmatter.type,
|
|
2370
|
+
name,
|
|
2371
|
+
path: relPath,
|
|
2372
|
+
content: body.trim(),
|
|
2373
|
+
metadata: {
|
|
2374
|
+
domain,
|
|
2375
|
+
...frontmatter.tags && { tags: frontmatter.tags },
|
|
2376
|
+
...frontmatter.related && { related: frontmatter.related }
|
|
2377
|
+
}
|
|
2378
|
+
};
|
|
2379
|
+
this.store.addNode(node);
|
|
2380
|
+
return { nodeId, node, content: body };
|
|
2381
|
+
}
|
|
2382
|
+
createEdges(nodeEntries) {
|
|
2383
|
+
let edgesAdded = 0;
|
|
2384
|
+
for (const { nodeId, node, content } of nodeEntries) {
|
|
2385
|
+
if (GOVERNS_SOURCE_TYPES.has(node.type)) {
|
|
2386
|
+
edgesAdded += this.linkToNodes(content, nodeId, "governs", CODE_NODE_TYPES2);
|
|
2387
|
+
} else {
|
|
2388
|
+
edgesAdded += this.linkToNodes(content, nodeId, "documents", CODE_NODE_TYPES2);
|
|
2389
|
+
}
|
|
2390
|
+
if (node.type === "business_metric") {
|
|
2391
|
+
edgesAdded += this.linkToBusinessNodes(content, nodeId, "measures", MEASURABLE_TYPES);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
return edgesAdded;
|
|
2395
|
+
}
|
|
2396
|
+
linkToNodes(content, sourceNodeId, edgeType, targetTypes) {
|
|
2397
|
+
let count = 0;
|
|
2398
|
+
for (const nodeType of targetTypes) {
|
|
2399
|
+
const nodes = this.store.findNodes({ type: nodeType });
|
|
2400
|
+
for (const node of nodes) {
|
|
2401
|
+
if (node.name.length < 3) continue;
|
|
2402
|
+
const escaped = node.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2403
|
+
const namePattern = new RegExp(`\\b${escaped}\\b`, "i");
|
|
2404
|
+
if (namePattern.test(content)) {
|
|
2405
|
+
this.store.addEdge({ from: sourceNodeId, to: node.id, type: edgeType });
|
|
2406
|
+
count++;
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
return count;
|
|
2411
|
+
}
|
|
2412
|
+
linkToBusinessNodes(content, sourceNodeId, edgeType, targetTypes) {
|
|
2413
|
+
let count = 0;
|
|
2414
|
+
for (const node of this.store.findNodes({})) {
|
|
2415
|
+
if (!targetTypes.has(node.type)) continue;
|
|
2416
|
+
if (node.name.length < 3) continue;
|
|
2417
|
+
const escaped = node.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2418
|
+
const namePattern = new RegExp(`\\b${escaped}\\b`, "i");
|
|
2419
|
+
if (namePattern.test(content)) {
|
|
2420
|
+
this.store.addEdge({ from: sourceNodeId, to: node.id, type: edgeType });
|
|
2421
|
+
count++;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
return count;
|
|
2425
|
+
}
|
|
2426
|
+
async findMarkdownFiles(dir) {
|
|
2427
|
+
const results = [];
|
|
2428
|
+
const entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
2429
|
+
for (const entry of entries) {
|
|
2430
|
+
const fullPath = path4.join(dir, entry.name);
|
|
2431
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && entry.name !== "target" && entry.name !== "build" && entry.name !== ".git" && entry.name !== ".gradle" && entry.name !== ".harness" && entry.name !== "vendor" && entry.name !== "bin" && entry.name !== "obj" && entry.name !== "venv" && entry.name !== "_build" && entry.name !== "deps" && entry.name !== "coverage") {
|
|
2221
2432
|
results.push(...await this.findMarkdownFiles(fullPath));
|
|
2222
2433
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2223
2434
|
results.push(fullPath);
|
|
@@ -2233,7 +2444,7 @@ var init_dist = __esm({
|
|
|
2233
2444
|
];
|
|
2234
2445
|
SECTION_HEADING_RE = /^#{2,3}\s+(.+)$/;
|
|
2235
2446
|
NUMBERED_ITEM_RE = /^\s*(\d+)\.\s+(.+)$/;
|
|
2236
|
-
|
|
2447
|
+
CODE_NODE_TYPES3 = ["file", "function", "class", "method", "interface", "variable"];
|
|
2237
2448
|
RequirementIngestor = class {
|
|
2238
2449
|
constructor(store) {
|
|
2239
2450
|
this.store = store;
|
|
@@ -2251,8 +2462,8 @@ var init_dist = __esm({
|
|
|
2251
2462
|
let edgesAdded = 0;
|
|
2252
2463
|
let featureDirs;
|
|
2253
2464
|
try {
|
|
2254
|
-
const entries = await
|
|
2255
|
-
featureDirs = entries.filter((e) => e.isDirectory()).map((e) =>
|
|
2465
|
+
const entries = await fs4.readdir(specsDir, { withFileTypes: true });
|
|
2466
|
+
featureDirs = entries.filter((e) => e.isDirectory()).map((e) => path5.join(specsDir, e.name));
|
|
2256
2467
|
} catch {
|
|
2257
2468
|
return emptyResult(Date.now() - start);
|
|
2258
2469
|
}
|
|
@@ -2271,11 +2482,11 @@ var init_dist = __esm({
|
|
|
2271
2482
|
};
|
|
2272
2483
|
}
|
|
2273
2484
|
async ingestFeatureDir(featureDir, errors) {
|
|
2274
|
-
const featureName =
|
|
2275
|
-
const specPath =
|
|
2485
|
+
const featureName = path5.basename(featureDir);
|
|
2486
|
+
const specPath = path5.join(featureDir, "proposal.md").replaceAll("\\", "/");
|
|
2276
2487
|
let content;
|
|
2277
2488
|
try {
|
|
2278
|
-
content = await
|
|
2489
|
+
content = await fs4.readFile(specPath, "utf-8");
|
|
2279
2490
|
} catch {
|
|
2280
2491
|
return { nodesAdded: 0, edgesAdded: 0 };
|
|
2281
2492
|
}
|
|
@@ -2292,7 +2503,7 @@ var init_dist = __esm({
|
|
|
2292
2503
|
this.store.addNode({
|
|
2293
2504
|
id: specNodeId,
|
|
2294
2505
|
type: "document",
|
|
2295
|
-
name:
|
|
2506
|
+
name: path5.basename(specPath),
|
|
2296
2507
|
path: specPath,
|
|
2297
2508
|
metadata: { featureName }
|
|
2298
2509
|
});
|
|
@@ -2407,9 +2618,9 @@ var init_dist = __esm({
|
|
|
2407
2618
|
for (const node of fileNodes) {
|
|
2408
2619
|
if (!node.path) continue;
|
|
2409
2620
|
const normalizedPath = node.path.replace(/\\/g, "/");
|
|
2410
|
-
const isCodeMatch = normalizedPath.includes("packages/") &&
|
|
2621
|
+
const isCodeMatch = normalizedPath.includes("packages/") && path5.basename(normalizedPath).includes(featureName);
|
|
2411
2622
|
const isTestMatch = normalizedPath.includes("/tests/") && // platform-safe
|
|
2412
|
-
|
|
2623
|
+
path5.basename(normalizedPath).includes(featureName);
|
|
2413
2624
|
if (isCodeMatch && !isTestMatch) {
|
|
2414
2625
|
this.store.addEdge({
|
|
2415
2626
|
from: reqId,
|
|
@@ -2438,7 +2649,7 @@ var init_dist = __esm({
|
|
|
2438
2649
|
*/
|
|
2439
2650
|
linkByKeywordOverlap(reqId, reqText) {
|
|
2440
2651
|
let count = 0;
|
|
2441
|
-
for (const nodeType of
|
|
2652
|
+
for (const nodeType of CODE_NODE_TYPES3) {
|
|
2442
2653
|
const codeNodes = this.store.findNodes({ type: nodeType });
|
|
2443
2654
|
for (const node of codeNodes) {
|
|
2444
2655
|
if (node.name.length < 3) continue;
|
|
@@ -2460,7 +2671,7 @@ var init_dist = __esm({
|
|
|
2460
2671
|
return count;
|
|
2461
2672
|
}
|
|
2462
2673
|
};
|
|
2463
|
-
|
|
2674
|
+
CODE_NODE_TYPES4 = ["file", "function", "class", "method", "interface", "variable"];
|
|
2464
2675
|
SANITIZE_RULES = [
|
|
2465
2676
|
// Strip XML/HTML-like instruction tags that could be interpreted as system prompts
|
|
2466
2677
|
{
|
|
@@ -2486,7 +2697,7 @@ var init_dist = __esm({
|
|
|
2486
2697
|
SyncManager = class {
|
|
2487
2698
|
constructor(store, graphDir) {
|
|
2488
2699
|
this.store = store;
|
|
2489
|
-
this.metadataPath =
|
|
2700
|
+
this.metadataPath = path6.join(graphDir, "sync-metadata.json");
|
|
2490
2701
|
}
|
|
2491
2702
|
store;
|
|
2492
2703
|
registrations = /* @__PURE__ */ new Map();
|
|
@@ -2541,15 +2752,15 @@ var init_dist = __esm({
|
|
|
2541
2752
|
}
|
|
2542
2753
|
async loadMetadata() {
|
|
2543
2754
|
try {
|
|
2544
|
-
const raw = await
|
|
2755
|
+
const raw = await fs5.readFile(this.metadataPath, "utf-8");
|
|
2545
2756
|
return JSON.parse(raw);
|
|
2546
2757
|
} catch {
|
|
2547
2758
|
return { connectors: {} };
|
|
2548
2759
|
}
|
|
2549
2760
|
}
|
|
2550
2761
|
async saveMetadata(metadata) {
|
|
2551
|
-
await
|
|
2552
|
-
await
|
|
2762
|
+
await fs5.mkdir(path6.dirname(this.metadataPath), { recursive: true });
|
|
2763
|
+
await fs5.writeFile(this.metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
2553
2764
|
}
|
|
2554
2765
|
};
|
|
2555
2766
|
JiraConnector = class {
|
|
@@ -3002,7 +3213,7 @@ var init_dist = __esm({
|
|
|
3002
3213
|
return 0;
|
|
3003
3214
|
}
|
|
3004
3215
|
};
|
|
3005
|
-
|
|
3216
|
+
CODE_NODE_TYPES5 = ["file", "function", "class", "method", "interface", "variable"];
|
|
3006
3217
|
GraphEntropyAdapter = class {
|
|
3007
3218
|
constructor(store) {
|
|
3008
3219
|
this.store = store;
|
|
@@ -3082,7 +3293,7 @@ var init_dist = __esm({
|
|
|
3082
3293
|
}
|
|
3083
3294
|
findEntryPoints() {
|
|
3084
3295
|
const entryPoints = [];
|
|
3085
|
-
for (const nodeType of
|
|
3296
|
+
for (const nodeType of CODE_NODE_TYPES5) {
|
|
3086
3297
|
const nodes = this.store.findNodes({ type: nodeType });
|
|
3087
3298
|
for (const node of nodes) {
|
|
3088
3299
|
const isIndexFile = nodeType === "file" && node.name === "index.ts";
|
|
@@ -3118,7 +3329,7 @@ var init_dist = __esm({
|
|
|
3118
3329
|
}
|
|
3119
3330
|
collectUnreachableNodes(visited) {
|
|
3120
3331
|
const unreachableNodes = [];
|
|
3121
|
-
for (const nodeType of
|
|
3332
|
+
for (const nodeType of CODE_NODE_TYPES5) {
|
|
3122
3333
|
const nodes = this.store.findNodes({ type: nodeType });
|
|
3123
3334
|
for (const node of nodes) {
|
|
3124
3335
|
if (!visited.has(node.id)) {
|
|
@@ -3935,9 +4146,9 @@ var init_dist = __esm({
|
|
|
3935
4146
|
extractPaths(trimmed, add) {
|
|
3936
4147
|
const consumed = /* @__PURE__ */ new Set();
|
|
3937
4148
|
for (const match of trimmed.matchAll(FILE_PATH_RE)) {
|
|
3938
|
-
const
|
|
3939
|
-
add(
|
|
3940
|
-
consumed.add(
|
|
4149
|
+
const path8 = match[0];
|
|
4150
|
+
add(path8);
|
|
4151
|
+
consumed.add(path8);
|
|
3941
4152
|
}
|
|
3942
4153
|
return consumed;
|
|
3943
4154
|
}
|
|
@@ -4007,8 +4218,8 @@ var init_dist = __esm({
|
|
|
4007
4218
|
if (isPathLike && node.path.includes(raw)) {
|
|
4008
4219
|
return { raw, nodeId: node.id, node, confidence: 0.6, method: "path" };
|
|
4009
4220
|
}
|
|
4010
|
-
const
|
|
4011
|
-
if (
|
|
4221
|
+
const basename6 = node.path.split("/").pop() ?? "";
|
|
4222
|
+
if (basename6.includes(raw)) {
|
|
4012
4223
|
return { raw, nodeId: node.id, node, confidence: 0.6, method: "path" };
|
|
4013
4224
|
}
|
|
4014
4225
|
if (raw.length >= 4 && node.path.includes(raw)) {
|
|
@@ -4085,13 +4296,13 @@ var init_dist = __esm({
|
|
|
4085
4296
|
const context = Array.isArray(d?.context) ? d.context : [];
|
|
4086
4297
|
const firstEntity = entities[0];
|
|
4087
4298
|
const nodeType = firstEntity?.node.type ?? "node";
|
|
4088
|
-
const
|
|
4299
|
+
const path8 = firstEntity?.node.path ?? "unknown";
|
|
4089
4300
|
let neighborCount = 0;
|
|
4090
4301
|
const firstContext = context[0];
|
|
4091
4302
|
if (firstContext && Array.isArray(firstContext.nodes)) {
|
|
4092
4303
|
neighborCount = firstContext.nodes.length;
|
|
4093
4304
|
}
|
|
4094
|
-
return `**${entityName}** is a ${nodeType} at \`${
|
|
4305
|
+
return `**${entityName}** is a ${nodeType} at \`${path8}\`. Connected to ${neighborCount} nodes.`;
|
|
4095
4306
|
}
|
|
4096
4307
|
formatAnomaly(data) {
|
|
4097
4308
|
const d = data;
|
|
@@ -4361,7 +4572,7 @@ var init_dist = __esm({
|
|
|
4361
4572
|
debug: ["failure", "learning", "function", "method"],
|
|
4362
4573
|
plan: ["adr", "document", "module", "layer"]
|
|
4363
4574
|
};
|
|
4364
|
-
|
|
4575
|
+
CODE_NODE_TYPES6 = /* @__PURE__ */ new Set([
|
|
4365
4576
|
"file",
|
|
4366
4577
|
"function",
|
|
4367
4578
|
"class",
|
|
@@ -4571,7 +4782,7 @@ var init_dist = __esm({
|
|
|
4571
4782
|
*/
|
|
4572
4783
|
checkCoverage() {
|
|
4573
4784
|
const codeNodes = [];
|
|
4574
|
-
for (const type of
|
|
4785
|
+
for (const type of CODE_NODE_TYPES6) {
|
|
4575
4786
|
codeNodes.push(...this.store.findNodes({ type }));
|
|
4576
4787
|
}
|
|
4577
4788
|
const documented = [];
|
|
@@ -4622,8 +4833,8 @@ var init_dist = __esm({
|
|
|
4622
4833
|
const { edges } = this.computeDependencyGraph();
|
|
4623
4834
|
const violations = [];
|
|
4624
4835
|
for (const edge of edges) {
|
|
4625
|
-
const fromRelative =
|
|
4626
|
-
const toRelative =
|
|
4836
|
+
const fromRelative = relative3(rootDir, edge.from).replaceAll("\\", "/");
|
|
4837
|
+
const toRelative = relative3(rootDir, edge.to).replaceAll("\\", "/");
|
|
4627
4838
|
const fromLayer = this.resolveLayer(fromRelative, layers);
|
|
4628
4839
|
const toLayer = this.resolveLayer(toRelative, layers);
|
|
4629
4840
|
if (!fromLayer || !toLayer) continue;
|
|
@@ -4716,8 +4927,8 @@ var init_dist = __esm({
|
|
|
4716
4927
|
async ingestAll(designDir) {
|
|
4717
4928
|
const start = Date.now();
|
|
4718
4929
|
const [tokensResult, intentResult] = await Promise.all([
|
|
4719
|
-
this.ingestTokens(
|
|
4720
|
-
this.ingestDesignIntent(
|
|
4930
|
+
this.ingestTokens(path7.join(designDir, "tokens.json")),
|
|
4931
|
+
this.ingestDesignIntent(path7.join(designDir, "DESIGN.md"))
|
|
4721
4932
|
]);
|
|
4722
4933
|
const merged = mergeResults(tokensResult, intentResult);
|
|
4723
4934
|
return { ...merged, durationMs: Date.now() - start };
|
|
@@ -4947,10 +5158,10 @@ var init_dist = __esm({
|
|
|
4947
5158
|
includeTypes: ["file"]
|
|
4948
5159
|
});
|
|
4949
5160
|
for (const n of queryResult.nodes) {
|
|
4950
|
-
const
|
|
4951
|
-
if (!fileSet.has(
|
|
4952
|
-
if (!result.has(
|
|
4953
|
-
result.set(
|
|
5161
|
+
const path8 = n.path ?? n.id.replace(/^file:/, "");
|
|
5162
|
+
if (!fileSet.has(path8)) {
|
|
5163
|
+
if (!result.has(path8)) {
|
|
5164
|
+
result.set(path8, file);
|
|
4954
5165
|
}
|
|
4955
5166
|
}
|
|
4956
5167
|
}
|
|
@@ -5349,6 +5560,7 @@ export {
|
|
|
5349
5560
|
GitIngestor,
|
|
5350
5561
|
TopologicalLinker,
|
|
5351
5562
|
KnowledgeIngestor,
|
|
5563
|
+
BusinessKnowledgeIngestor,
|
|
5352
5564
|
RequirementIngestor,
|
|
5353
5565
|
linkToCode,
|
|
5354
5566
|
SyncManager,
|