openlore 2.0.6 → 2.0.8
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/README.md +140 -23
- package/dist/cli/commands/decisions.d.ts.map +1 -1
- package/dist/cli/commands/decisions.js +187 -174
- package/dist/cli/commands/decisions.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts +694 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +417 -203
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +14 -0
- package/dist/constants.js.map +1 -1
- package/dist/core/analyzer/artifact-generator.d.ts.map +1 -1
- package/dist/core/analyzer/artifact-generator.js +59 -4
- package/dist/core/analyzer/artifact-generator.js.map +1 -1
- package/dist/core/analyzer/call-graph.d.ts +19 -1
- package/dist/core/analyzer/call-graph.d.ts.map +1 -1
- package/dist/core/analyzer/call-graph.js +128 -28
- package/dist/core/analyzer/call-graph.js.map +1 -1
- package/dist/core/architecture/check.d.ts +63 -0
- package/dist/core/architecture/check.d.ts.map +1 -0
- package/dist/core/architecture/check.js +192 -0
- package/dist/core/architecture/check.js.map +1 -0
- package/dist/core/architecture/rules.d.ts +73 -0
- package/dist/core/architecture/rules.d.ts.map +1 -0
- package/dist/core/architecture/rules.js +201 -0
- package/dist/core/architecture/rules.js.map +1 -0
- package/dist/core/decisions/lock.d.ts +10 -0
- package/dist/core/decisions/lock.d.ts.map +1 -0
- package/dist/core/decisions/lock.js +77 -0
- package/dist/core/decisions/lock.js.map +1 -0
- package/dist/core/decisions/project.d.ts +59 -0
- package/dist/core/decisions/project.d.ts.map +1 -0
- package/dist/core/decisions/project.js +68 -0
- package/dist/core/decisions/project.js.map +1 -0
- package/dist/core/decisions/verifier.d.ts +10 -0
- package/dist/core/decisions/verifier.d.ts.map +1 -1
- package/dist/core/decisions/verifier.js +48 -5
- package/dist/core/decisions/verifier.js.map +1 -1
- package/dist/core/provenance/change-coupling.d.ts +68 -0
- package/dist/core/provenance/change-coupling.d.ts.map +1 -0
- package/dist/core/provenance/change-coupling.js +134 -0
- package/dist/core/provenance/change-coupling.js.map +1 -0
- package/dist/core/provenance/git-provenance.d.ts +67 -0
- package/dist/core/provenance/git-provenance.d.ts.map +1 -0
- package/dist/core/provenance/git-provenance.js +177 -0
- package/dist/core/provenance/git-provenance.js.map +1 -0
- package/dist/core/provenance/project.d.ts +37 -0
- package/dist/core/provenance/project.d.ts.map +1 -0
- package/dist/core/provenance/project.js +46 -0
- package/dist/core/provenance/project.js.map +1 -0
- package/dist/core/services/edge-store.d.ts +41 -0
- package/dist/core/services/edge-store.d.ts.map +1 -1
- package/dist/core/services/edge-store.js +251 -3
- package/dist/core/services/edge-store.js.map +1 -1
- package/dist/core/services/llm-service.d.ts +9 -0
- package/dist/core/services/llm-service.d.ts.map +1 -1
- package/dist/core/services/llm-service.js +15 -4
- package/dist/core/services/llm-service.js.map +1 -1
- package/dist/core/services/mcp-handlers/architecture.d.ts +19 -0
- package/dist/core/services/mcp-handlers/architecture.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/architecture.js +104 -0
- package/dist/core/services/mcp-handlers/architecture.js.map +1 -0
- package/dist/core/services/mcp-handlers/change-coupling.d.ts +16 -0
- package/dist/core/services/mcp-handlers/change-coupling.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/change-coupling.js +57 -0
- package/dist/core/services/mcp-handlers/change-coupling.js.map +1 -0
- package/dist/core/services/mcp-handlers/graph.d.ts +27 -0
- package/dist/core/services/mcp-handlers/graph.d.ts.map +1 -1
- package/dist/core/services/mcp-handlers/graph.js +98 -16
- package/dist/core/services/mcp-handlers/graph.js.map +1 -1
- package/dist/core/services/mcp-handlers/orient.d.ts.map +1 -1
- package/dist/core/services/mcp-handlers/orient.js +122 -2
- package/dist/core/services/mcp-handlers/orient.js.map +1 -1
- package/dist/core/services/mcp-handlers/reachability.d.ts +30 -0
- package/dist/core/services/mcp-handlers/reachability.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/reachability.js +222 -0
- package/dist/core/services/mcp-handlers/reachability.js.map +1 -0
- package/dist/core/services/mcp-handlers/structural-diff.d.ts +31 -0
- package/dist/core/services/mcp-handlers/structural-diff.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/structural-diff.js +268 -0
- package/dist/core/services/mcp-handlers/structural-diff.js.map +1 -0
- package/dist/core/services/mcp-handlers/test-impact.d.ts +34 -0
- package/dist/core/services/mcp-handlers/test-impact.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/test-impact.js +221 -0
- package/dist/core/services/mcp-handlers/test-impact.js.map +1 -0
- package/dist/core/services/mcp-handlers/tool-guard.d.ts +45 -0
- package/dist/core/services/mcp-handlers/tool-guard.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/tool-guard.js +81 -0
- package/dist/core/services/mcp-handlers/tool-guard.js.map +1 -0
- package/dist/core/services/mcp-handlers/utils.d.ts.map +1 -1
- package/dist/core/services/mcp-handlers/utils.js +15 -1
- package/dist/core/services/mcp-handlers/utils.js.map +1 -1
- package/dist/core/services/mcp-watcher.d.ts.map +1 -1
- package/dist/core/services/mcp-watcher.js +9 -0
- package/dist/core/services/mcp-watcher.js.map +1 -1
- package/package.json +9 -8
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import type { ImportMap } from './import-resolver-bridge.js';
|
|
15
15
|
export type EdgeConfidence = 'self_cls' | 'type_inference' | 'import' | 'http_endpoint' | 'same_file' | 'name_only' | 'type_name' | 'external';
|
|
16
16
|
/** Broad relationship kind */
|
|
17
|
-
export type EdgeKind = 'calls' | 'tested_by' | 'references' | 'depends_on';
|
|
17
|
+
export type EdgeKind = 'calls' | 'tested_by' | 'references' | 'depends_on' | 'affects' | 'authored_by' | 'changed_in_pr';
|
|
18
18
|
/** Semantic nature of the call at the call site */
|
|
19
19
|
export type CallType = 'direct' | 'method' | 'awaited' | 'constructor';
|
|
20
20
|
export interface FunctionNode {
|
|
@@ -73,6 +73,24 @@ export interface LayerViolation {
|
|
|
73
73
|
calleeLayer: string;
|
|
74
74
|
reason: string;
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* The layer a file belongs to, by the first matching prefix in declared order.
|
|
78
|
+
* Shared by the call-graph layer detector and the architecture guardrail (spec-23)
|
|
79
|
+
* so both agree on one layering convention.
|
|
80
|
+
*/
|
|
81
|
+
export declare function layerOf(filePath: string, layers: Record<string, string[]>): string | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Classify a single directed edge (from → to) against a layer ordering. Declared
|
|
84
|
+
* key order is top → bottom; a lower layer depending on an upper layer is a
|
|
85
|
+
* violation. Returns the offending layer pair, or null when the edge is legal,
|
|
86
|
+
* unclassified, or intra-layer. The canonical layer-direction primitive — reused
|
|
87
|
+
* by `detectLayerViolations` (call edges) and the spec-23 architecture checker
|
|
88
|
+
* (file dependency edges).
|
|
89
|
+
*/
|
|
90
|
+
export declare function classifyLayerEdge(fromFile: string, toFile: string, layers: Record<string, string[]>): {
|
|
91
|
+
fromLayer: string;
|
|
92
|
+
toLayer: string;
|
|
93
|
+
} | null;
|
|
76
94
|
/**
|
|
77
95
|
* A class or interface as a structural unit, grouping its methods.
|
|
78
96
|
* Derived from FunctionNode.className after the call graph is built.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-graph.d.ts","sourceRoot":"","sources":["../../../src/core/analyzer/call-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"call-graph.d.ts","sourceRoot":"","sources":["../../../src/core/analyzer/call-graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,13 +11,46 @@
|
|
|
11
11
|
* - Entry points — functions with no internal callers
|
|
12
12
|
* - Layer violations — cross-layer calls in the wrong direction
|
|
13
13
|
*/
|
|
14
|
-
import { dirname,
|
|
14
|
+
import { dirname, join as joinPath } from 'node:path';
|
|
15
15
|
import Parser from 'tree-sitter';
|
|
16
16
|
import { FunctionRegistryTrie } from './function-registry-trie.js';
|
|
17
17
|
import { inferTypesFromSource, resolveViaTypeInference } from './type-inference-engine.js';
|
|
18
18
|
import { extractAllHttpEdges } from './http-route-parser.js';
|
|
19
19
|
import { buildProjectedIac } from './iac/index.js';
|
|
20
|
+
import { isIacLanguage } from './iac/types.js';
|
|
20
21
|
import { logger } from '../../utils/logger.js';
|
|
22
|
+
/**
|
|
23
|
+
* The layer a file belongs to, by the first matching prefix in declared order.
|
|
24
|
+
* Shared by the call-graph layer detector and the architecture guardrail (spec-23)
|
|
25
|
+
* so both agree on one layering convention.
|
|
26
|
+
*/
|
|
27
|
+
export function layerOf(filePath, layers) {
|
|
28
|
+
for (const [layerName, prefixes] of Object.entries(layers)) {
|
|
29
|
+
if (prefixes.some(p => filePath.includes(p)))
|
|
30
|
+
return layerName;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Classify a single directed edge (from → to) against a layer ordering. Declared
|
|
36
|
+
* key order is top → bottom; a lower layer depending on an upper layer is a
|
|
37
|
+
* violation. Returns the offending layer pair, or null when the edge is legal,
|
|
38
|
+
* unclassified, or intra-layer. The canonical layer-direction primitive — reused
|
|
39
|
+
* by `detectLayerViolations` (call edges) and the spec-23 architecture checker
|
|
40
|
+
* (file dependency edges).
|
|
41
|
+
*/
|
|
42
|
+
export function classifyLayerEdge(fromFile, toFile, layers) {
|
|
43
|
+
const order = Object.keys(layers);
|
|
44
|
+
const fromLayer = layerOf(fromFile, layers);
|
|
45
|
+
const toLayer = layerOf(toFile, layers);
|
|
46
|
+
if (!fromLayer || !toLayer || fromLayer === toLayer)
|
|
47
|
+
return null;
|
|
48
|
+
const fi = order.indexOf(fromLayer);
|
|
49
|
+
const ti = order.indexOf(toLayer);
|
|
50
|
+
if (fi === -1 || ti === -1)
|
|
51
|
+
return null;
|
|
52
|
+
return fi > ti ? { fromLayer, toLayer } : null;
|
|
53
|
+
}
|
|
21
54
|
// ============================================================================
|
|
22
55
|
// CONSTANTS
|
|
23
56
|
// ============================================================================
|
|
@@ -186,6 +219,79 @@ function findEnclosingFunction(nodes, callPos) {
|
|
|
186
219
|
}
|
|
187
220
|
return best;
|
|
188
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Cross-domain code↔infra edges (spec-17).
|
|
224
|
+
*
|
|
225
|
+
* For each embedded IaC resource (Pulumi/CDK/CDKTF, declared inside a code file),
|
|
226
|
+
* find the narrowest enclosing code function in the same file by line containment
|
|
227
|
+
* and emit a `references` edge: enclosing function → resource. This is the single
|
|
228
|
+
* deterministic link that crosses the code↔infra boundary, so the existing graph
|
|
229
|
+
* traversal (which already walks `references` edges) answers "what infrastructure
|
|
230
|
+
* does this code provision?" and the reverse, end-to-end.
|
|
231
|
+
*
|
|
232
|
+
* Resources with no enclosing function (e.g. Pulumi declared at module top level)
|
|
233
|
+
* are left unlinked — there is no code unit to attribute them to. Standalone IaC
|
|
234
|
+
* (.tf/.yaml) has no co-located code functions, so nothing matches.
|
|
235
|
+
*/
|
|
236
|
+
function linkCodeToInfra(iacNodes, allNodes) {
|
|
237
|
+
// Index code (non-IaC, non-external) function nodes with known line ranges by file.
|
|
238
|
+
const codeByFile = new Map();
|
|
239
|
+
for (const n of allNodes.values()) {
|
|
240
|
+
if (n.isExternal)
|
|
241
|
+
continue;
|
|
242
|
+
if (isIacLanguage(n.language))
|
|
243
|
+
continue;
|
|
244
|
+
if (n.startLine === undefined || n.endLine === undefined)
|
|
245
|
+
continue;
|
|
246
|
+
const arr = codeByFile.get(n.filePath);
|
|
247
|
+
if (arr)
|
|
248
|
+
arr.push(n);
|
|
249
|
+
else
|
|
250
|
+
codeByFile.set(n.filePath, [n]);
|
|
251
|
+
}
|
|
252
|
+
if (codeByFile.size === 0)
|
|
253
|
+
return [];
|
|
254
|
+
const edges = [];
|
|
255
|
+
const seen = new Set();
|
|
256
|
+
// Deterministic: iterate resources in id order.
|
|
257
|
+
const sorted = [...iacNodes].sort((a, b) => a.id.localeCompare(b.id));
|
|
258
|
+
for (const res of sorted) {
|
|
259
|
+
if (!isIacLanguage(res.language))
|
|
260
|
+
continue;
|
|
261
|
+
if (res.startLine === undefined)
|
|
262
|
+
continue;
|
|
263
|
+
const candidates = codeByFile.get(res.filePath);
|
|
264
|
+
if (!candidates)
|
|
265
|
+
continue;
|
|
266
|
+
// Narrowest code function whose line range encloses the resource declaration.
|
|
267
|
+
let best;
|
|
268
|
+
let bestSpan = Infinity;
|
|
269
|
+
for (const fn of candidates) {
|
|
270
|
+
if (fn.startLine <= res.startLine && res.startLine <= fn.endLine) {
|
|
271
|
+
const span = fn.endLine - fn.startLine;
|
|
272
|
+
if (span < bestSpan) {
|
|
273
|
+
bestSpan = span;
|
|
274
|
+
best = fn;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (!best || best.id === res.id)
|
|
279
|
+
continue;
|
|
280
|
+
const key = `${best.id}\0${res.id}`;
|
|
281
|
+
if (seen.has(key))
|
|
282
|
+
continue;
|
|
283
|
+
seen.add(key);
|
|
284
|
+
edges.push({
|
|
285
|
+
callerId: best.id,
|
|
286
|
+
calleeId: res.id,
|
|
287
|
+
calleeName: res.name,
|
|
288
|
+
line: res.startLine,
|
|
289
|
+
confidence: 'import',
|
|
290
|
+
kind: 'references',
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
return edges;
|
|
294
|
+
}
|
|
189
295
|
// ============================================================================
|
|
190
296
|
// DOCSTRING / SIGNATURE EXTRACTION HELPERS
|
|
191
297
|
// ============================================================================
|
|
@@ -2274,6 +2380,13 @@ export class CallGraphBuilder {
|
|
|
2274
2380
|
allNodes.set(n.id, n);
|
|
2275
2381
|
edges.push(...iac.edges);
|
|
2276
2382
|
iacClasses = iac.classes;
|
|
2383
|
+
// Pass 2c.1: Cross-domain code↔infra edges (spec-17).
|
|
2384
|
+
// Embedded IaC (Pulumi/CDK/CDKTF) declares resources *inside* code files.
|
|
2385
|
+
// Link the enclosing code function → the resource it provisions with a
|
|
2386
|
+
// `references` edge, so analyze_impact/get_subgraph traverse the code↔infra
|
|
2387
|
+
// boundary end-to-end. Standalone IaC (.tf/.yaml) has no co-located code, so
|
|
2388
|
+
// no edge is created — those stay infra-only components, exactly as today.
|
|
2389
|
+
edges.push(...linkCodeToInfra(iac.nodes, allNodes));
|
|
2277
2390
|
}
|
|
2278
2391
|
catch {
|
|
2279
2392
|
// IaC extraction is best-effort; never fail the whole build
|
|
@@ -2338,7 +2451,10 @@ export class CallGraphBuilder {
|
|
|
2338
2451
|
const resolveSource = (rel) => {
|
|
2339
2452
|
// Strip .js extension: TS ESM imports use './foo.js' to refer to './foo.ts'
|
|
2340
2453
|
const stripped = rel.replace(/\.js$/, '');
|
|
2341
|
-
|
|
2454
|
+
// Form-preserving join (NOT resolve): the analyze pipeline passes repo-relative
|
|
2455
|
+
// paths, so resolve() would force an absolute path that never matches the
|
|
2456
|
+
// relative allFilePaths — silently zeroing out import-based tested_by edges.
|
|
2457
|
+
const base = joinPath(dir, stripped);
|
|
2342
2458
|
return allFilePaths.find(p => p === base || p === `${base}.ts` || p === `${base}.tsx` ||
|
|
2343
2459
|
p === `${base}.js` || p === `${base}.jsx` || p === `${base}/index.ts`);
|
|
2344
2460
|
};
|
|
@@ -2518,39 +2634,23 @@ export class CallGraphBuilder {
|
|
|
2518
2634
|
};
|
|
2519
2635
|
}
|
|
2520
2636
|
detectLayerViolations(edges, nodes, layers) {
|
|
2521
|
-
// Build ordered layer list (index 0 = top layer, higher index = lower layer)
|
|
2522
|
-
const layerOrder = Object.keys(layers);
|
|
2523
|
-
const getLayer = (filePath) => {
|
|
2524
|
-
for (const [layerName, prefixes] of Object.entries(layers)) {
|
|
2525
|
-
if (prefixes.some(p => filePath.includes(p)))
|
|
2526
|
-
return layerName;
|
|
2527
|
-
}
|
|
2528
|
-
return undefined;
|
|
2529
|
-
};
|
|
2530
2637
|
const violations = [];
|
|
2531
2638
|
for (const edge of edges) {
|
|
2532
2639
|
const caller = nodes.get(edge.callerId);
|
|
2533
2640
|
const callee = nodes.get(edge.calleeId);
|
|
2534
2641
|
if (!caller || !callee)
|
|
2535
2642
|
continue;
|
|
2536
|
-
|
|
2537
|
-
const
|
|
2538
|
-
if (!
|
|
2643
|
+
// Lower layer calling upper layer — violation (canonical primitive).
|
|
2644
|
+
const cls = classifyLayerEdge(caller.filePath, callee.filePath, layers);
|
|
2645
|
+
if (!cls)
|
|
2539
2646
|
continue;
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
callerId: edge.callerId,
|
|
2548
|
-
calleeId: edge.calleeId,
|
|
2549
|
-
callerLayer,
|
|
2550
|
-
calleeLayer,
|
|
2551
|
-
reason: `${callerLayer} calls ${calleeLayer} (${caller.name} → ${callee.name})`,
|
|
2552
|
-
});
|
|
2553
|
-
}
|
|
2647
|
+
violations.push({
|
|
2648
|
+
callerId: edge.callerId,
|
|
2649
|
+
calleeId: edge.calleeId,
|
|
2650
|
+
callerLayer: cls.fromLayer,
|
|
2651
|
+
calleeLayer: cls.toLayer,
|
|
2652
|
+
reason: `${cls.fromLayer} calls ${cls.toLayer} (${caller.name} → ${callee.name})`,
|
|
2653
|
+
});
|
|
2554
2654
|
}
|
|
2555
2655
|
return violations;
|
|
2556
2656
|
}
|