@monoes/graph 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/src/analyze.d.ts +23 -0
  2. package/dist/src/analyze.d.ts.map +1 -0
  3. package/dist/src/analyze.js +105 -0
  4. package/dist/src/analyze.js.map +1 -0
  5. package/dist/src/build.d.ts +8 -0
  6. package/dist/src/build.d.ts.map +1 -0
  7. package/dist/src/build.js +59 -0
  8. package/dist/src/build.js.map +1 -0
  9. package/dist/src/cache.d.ts +10 -0
  10. package/dist/src/cache.d.ts.map +1 -0
  11. package/dist/src/cache.js +34 -0
  12. package/dist/src/cache.js.map +1 -0
  13. package/dist/src/cluster.d.ts +8 -0
  14. package/dist/src/cluster.d.ts.map +1 -0
  15. package/dist/src/cluster.js +50 -0
  16. package/dist/src/cluster.js.map +1 -0
  17. package/dist/src/detect.d.ts +8 -0
  18. package/dist/src/detect.d.ts.map +1 -0
  19. package/dist/src/detect.js +108 -0
  20. package/dist/src/detect.js.map +1 -0
  21. package/dist/src/export.d.ts +21 -0
  22. package/dist/src/export.d.ts.map +1 -0
  23. package/dist/src/export.js +68 -0
  24. package/dist/src/export.js.map +1 -0
  25. package/dist/src/extract/index.d.ts +20 -0
  26. package/dist/src/extract/index.d.ts.map +1 -0
  27. package/dist/src/extract/index.js +158 -0
  28. package/dist/src/extract/index.js.map +1 -0
  29. package/dist/src/extract/languages/go.d.ts +3 -0
  30. package/dist/src/extract/languages/go.d.ts.map +1 -0
  31. package/dist/src/extract/languages/go.js +181 -0
  32. package/dist/src/extract/languages/go.js.map +1 -0
  33. package/dist/src/extract/languages/python.d.ts +3 -0
  34. package/dist/src/extract/languages/python.d.ts.map +1 -0
  35. package/dist/src/extract/languages/python.js +230 -0
  36. package/dist/src/extract/languages/python.js.map +1 -0
  37. package/dist/src/extract/languages/rust.d.ts +3 -0
  38. package/dist/src/extract/languages/rust.d.ts.map +1 -0
  39. package/dist/src/extract/languages/rust.js +195 -0
  40. package/dist/src/extract/languages/rust.js.map +1 -0
  41. package/dist/src/extract/languages/typescript.d.ts +3 -0
  42. package/dist/src/extract/languages/typescript.d.ts.map +1 -0
  43. package/dist/src/extract/languages/typescript.js +295 -0
  44. package/dist/src/extract/languages/typescript.js.map +1 -0
  45. package/dist/src/extract/tree-sitter-runner.d.ts +48 -0
  46. package/dist/src/extract/tree-sitter-runner.d.ts.map +1 -0
  47. package/dist/src/extract/tree-sitter-runner.js +128 -0
  48. package/dist/src/extract/tree-sitter-runner.js.map +1 -0
  49. package/dist/src/extract/types.d.ts +7 -0
  50. package/dist/src/extract/types.d.ts.map +1 -0
  51. package/dist/src/extract/types.js +2 -0
  52. package/dist/src/extract/types.js.map +1 -0
  53. package/dist/src/index.d.ts +11 -0
  54. package/dist/src/index.d.ts.map +1 -0
  55. package/dist/src/index.js +9 -0
  56. package/dist/src/index.js.map +1 -0
  57. package/dist/src/pipeline.d.ts +16 -0
  58. package/dist/src/pipeline.d.ts.map +1 -0
  59. package/dist/src/pipeline.js +143 -0
  60. package/dist/src/pipeline.js.map +1 -0
  61. package/dist/src/types.d.ts +99 -0
  62. package/dist/src/types.d.ts.map +1 -0
  63. package/dist/src/types.js +2 -0
  64. package/dist/src/types.js.map +1 -0
  65. package/dist/tsconfig.tsbuildinfo +1 -0
  66. package/package.json +44 -0
  67. package/src/analyze.ts +122 -0
  68. package/src/build.ts +62 -0
  69. package/src/cache.ts +38 -0
  70. package/src/cluster.ts +54 -0
  71. package/src/detect.ts +123 -0
  72. package/src/export.ts +78 -0
  73. package/src/extract/index.ts +190 -0
  74. package/src/extract/languages/go.ts +206 -0
  75. package/src/extract/languages/python.ts +270 -0
  76. package/src/extract/languages/rust.ts +230 -0
  77. package/src/extract/languages/typescript.ts +344 -0
  78. package/src/extract/tree-sitter-runner.ts +165 -0
  79. package/src/extract/types.ts +7 -0
  80. package/src/index.ts +10 -0
  81. package/src/pipeline.ts +166 -0
  82. package/src/types.ts +116 -0
@@ -0,0 +1,23 @@
1
+ import type Graph from 'graphology';
2
+ import type { GodNode, SurpriseEdge, GraphAnalysis, GraphStats } from './types.js';
3
+ /**
4
+ * Find the most connected nodes (god nodes) — core abstractions of the codebase.
5
+ * Sorted by total degree (in + out), descending.
6
+ */
7
+ export declare function godNodes(graph: Graph, topN?: number): GodNode[];
8
+ /**
9
+ * Find surprising cross-community connections.
10
+ * An edge is surprising when its endpoints belong to different communities.
11
+ * Scored by the product of their degrees — high degree on both sides = high surprise.
12
+ */
13
+ export declare function surprisingConnections(graph: Graph, topN?: number): SurpriseEdge[];
14
+ /**
15
+ * Compute high-level graph statistics.
16
+ */
17
+ export declare function graphStats(graph: Graph, graphPath?: string): GraphStats;
18
+ /**
19
+ * Build a complete GraphAnalysis object from an annotated graph.
20
+ * Assumes community detection has already been run (nodes have `community` attribute).
21
+ */
22
+ export declare function buildAnalysis(graph: Graph, graphPath?: string): GraphAnalysis;
23
+ //# sourceMappingURL=analyze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAc,MAAM,YAAY,CAAC;AAE/F;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,SAAK,GAAG,OAAO,EAAE,CAkB3D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,SAAK,GAAG,YAAY,EAAE,CAuB7E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAsCvE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAiB7E"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Find the most connected nodes (god nodes) — core abstractions of the codebase.
3
+ * Sorted by total degree (in + out), descending.
4
+ */
5
+ export function godNodes(graph, topN = 15) {
6
+ const nodes = [];
7
+ graph.forEachNode((id, attrs) => {
8
+ nodes.push({
9
+ id,
10
+ label: attrs.label || id,
11
+ degree: graph.degree(id),
12
+ community: attrs.community,
13
+ sourceFile: attrs.sourceFile || '',
14
+ neighbors: graph
15
+ .neighbors(id)
16
+ .slice(0, 8)
17
+ .map((n) => graph.getNodeAttribute(n, 'label') || n),
18
+ });
19
+ });
20
+ return nodes.sort((a, b) => b.degree - a.degree).slice(0, topN);
21
+ }
22
+ /**
23
+ * Find surprising cross-community connections.
24
+ * An edge is surprising when its endpoints belong to different communities.
25
+ * Scored by the product of their degrees — high degree on both sides = high surprise.
26
+ */
27
+ export function surprisingConnections(graph, topN = 20) {
28
+ const surprises = [];
29
+ graph.forEachEdge((_, attrs, source, target) => {
30
+ const cu = graph.getNodeAttribute(source, 'community');
31
+ const cv = graph.getNodeAttribute(target, 'community');
32
+ if (cu !== undefined && cv !== undefined && cu !== cv) {
33
+ surprises.push({
34
+ from: graph.getNodeAttribute(source, 'label') || source,
35
+ fromCommunity: cu,
36
+ fromFile: graph.getNodeAttribute(source, 'sourceFile') || '',
37
+ to: graph.getNodeAttribute(target, 'label') || target,
38
+ toCommunity: cv,
39
+ toFile: graph.getNodeAttribute(target, 'sourceFile') || '',
40
+ relation: attrs.relation || '',
41
+ confidence: attrs.confidence ?? 'AMBIGUOUS',
42
+ score: graph.degree(source) * graph.degree(target),
43
+ });
44
+ }
45
+ });
46
+ return surprises.sort((a, b) => b.score - a.score).slice(0, topN);
47
+ }
48
+ /**
49
+ * Compute high-level graph statistics.
50
+ */
51
+ export function graphStats(graph, graphPath) {
52
+ const confidence = {};
53
+ const relations = {};
54
+ const fileTypes = {};
55
+ const commSet = new Set();
56
+ graph.forEachEdge((_, attrs) => {
57
+ const c = attrs.confidence || 'UNKNOWN';
58
+ confidence[c] = (confidence[c] ?? 0) + 1;
59
+ const r = attrs.relation || 'unknown';
60
+ relations[r] = (relations[r] ?? 0) + 1;
61
+ });
62
+ graph.forEachNode((_, attrs) => {
63
+ const ft = attrs.fileType || 'unknown';
64
+ fileTypes[ft] = (fileTypes[ft] ?? 0) + 1;
65
+ const c = attrs.community;
66
+ if (c !== undefined)
67
+ commSet.add(c);
68
+ });
69
+ const topRelations = Object.fromEntries(Object.entries(relations)
70
+ .sort(([, a], [, b]) => b - a)
71
+ .slice(0, 10));
72
+ return {
73
+ nodes: graph.order,
74
+ edges: graph.size,
75
+ communities: commSet.size,
76
+ confidence: confidence,
77
+ fileTypes,
78
+ topRelations,
79
+ isDirected: graph.type === 'directed',
80
+ graphPath,
81
+ };
82
+ }
83
+ /**
84
+ * Build a complete GraphAnalysis object from an annotated graph.
85
+ * Assumes community detection has already been run (nodes have `community` attribute).
86
+ */
87
+ export function buildAnalysis(graph, graphPath) {
88
+ // Reconstruct communities map from node attributes
89
+ const communities = {};
90
+ graph.forEachNode((id, attrs) => {
91
+ const c = attrs.community;
92
+ if (c !== undefined) {
93
+ if (!communities[c])
94
+ communities[c] = [];
95
+ communities[c].push(id);
96
+ }
97
+ });
98
+ return {
99
+ godNodes: godNodes(graph),
100
+ surprises: surprisingConnections(graph),
101
+ communities,
102
+ stats: graphStats(graph, graphPath),
103
+ };
104
+ }
105
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/analyze.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import Graph from 'graphology';
2
+ import type { ExtractionResult } from './types.js';
3
+ /**
4
+ * Build a graphology Graph from extracted nodes and edges.
5
+ * Deduplicates nodes by id, merges parallel edges with higher weight.
6
+ */
7
+ export declare function buildGraph(extraction: ExtractionResult): Graph;
8
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,gBAAgB,GAAG,KAAK,CAsD9D"}
@@ -0,0 +1,59 @@
1
+ import Graph from 'graphology';
2
+ /**
3
+ * Build a graphology Graph from extracted nodes and edges.
4
+ * Deduplicates nodes by id, merges parallel edges with higher weight.
5
+ */
6
+ export function buildGraph(extraction) {
7
+ const graph = new Graph({ type: 'directed', multi: false });
8
+ // Add all nodes — merge attributes if already present (dedup by id)
9
+ for (const node of extraction.nodes) {
10
+ if (!graph.hasNode(node.id)) {
11
+ graph.addNode(node.id, { ...node });
12
+ }
13
+ else {
14
+ graph.mergeNodeAttributes(node.id, { ...node });
15
+ }
16
+ }
17
+ // Add edges — skip self-loops, auto-stub missing endpoints
18
+ for (const edge of extraction.edges) {
19
+ if (edge.source === edge.target)
20
+ continue;
21
+ // Create stub nodes for referenced endpoints not in the extraction
22
+ if (!graph.hasNode(edge.source)) {
23
+ graph.addNode(edge.source, {
24
+ id: edge.source,
25
+ label: edge.source,
26
+ fileType: 'unknown',
27
+ sourceFile: '',
28
+ });
29
+ }
30
+ if (!graph.hasNode(edge.target)) {
31
+ graph.addNode(edge.target, {
32
+ id: edge.target,
33
+ label: edge.target,
34
+ fileType: 'unknown',
35
+ sourceFile: '',
36
+ });
37
+ }
38
+ try {
39
+ graph.addEdge(edge.source, edge.target, {
40
+ relation: edge.relation,
41
+ confidence: edge.confidence,
42
+ confidenceScore: edge.confidenceScore,
43
+ weight: edge.weight ?? 1,
44
+ sourceFile: edge.sourceFile,
45
+ sourceLocation: edge.sourceLocation,
46
+ });
47
+ }
48
+ catch {
49
+ // Edge already exists — bump its weight
50
+ const existing = graph.edge(edge.source, edge.target);
51
+ if (existing) {
52
+ const prev = graph.getEdgeAttribute(existing, 'weight') ?? 1;
53
+ graph.setEdgeAttribute(existing, 'weight', prev + 1);
54
+ }
55
+ }
56
+ }
57
+ return graph;
58
+ }
59
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAG/B;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,UAA4B;IACrD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAE5D,oEAAoE;IACpE,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;YAAE,SAAS;QAE1C,mEAAmE;QACnE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;gBACzB,EAAE,EAAE,IAAI,CAAC,MAAM;gBACf,KAAK,EAAE,IAAI,CAAC,MAAM;gBAClB,QAAQ,EAAE,SAAS;gBACnB,UAAU,EAAE,EAAE;aACf,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;gBACzB,EAAE,EAAE,IAAI,CAAC,MAAM;gBACf,KAAK,EAAE,IAAI,CAAC,MAAM;gBAClB,QAAQ,EAAE,SAAS;gBACnB,UAAU,EAAE,EAAE;aACf,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC;YACH,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;gBACtC,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC;gBACxB,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,cAAc,EAAE,IAAI,CAAC,cAAc;aACpC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;YACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACtD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,GAAI,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAY,IAAI,CAAC,CAAC;gBACzE,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ExtractionResult } from './types.js';
2
+ export declare class FileCache {
3
+ private cacheDir;
4
+ constructor(outputDir: string);
5
+ key(filePath: string, content: string): string;
6
+ get(key: string): ExtractionResult | null;
7
+ set(key: string, result: ExtractionResult): void;
8
+ has(key: string): boolean;
9
+ }
10
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;gBAEb,SAAS,EAAE,MAAM;IAK7B,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAM9C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAUzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAKhD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG1B"}
@@ -0,0 +1,34 @@
1
+ import { createHash } from 'crypto';
2
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
3
+ import { join } from 'path';
4
+ export class FileCache {
5
+ cacheDir;
6
+ constructor(outputDir) {
7
+ this.cacheDir = join(outputDir, 'cache');
8
+ mkdirSync(this.cacheDir, { recursive: true });
9
+ }
10
+ key(filePath, content) {
11
+ return createHash('sha256')
12
+ .update(filePath + content)
13
+ .digest('hex');
14
+ }
15
+ get(key) {
16
+ const p = join(this.cacheDir, `${key}.json`);
17
+ if (!existsSync(p))
18
+ return null;
19
+ try {
20
+ return JSON.parse(readFileSync(p, 'utf-8'));
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ set(key, result) {
27
+ const p = join(this.cacheDir, `${key}.json`);
28
+ writeFileSync(p, JSON.stringify(result), 'utf-8');
29
+ }
30
+ has(key) {
31
+ return existsSync(join(this.cacheDir, `${key}.json`));
32
+ }
33
+ }
34
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,MAAM,OAAO,SAAS;IACZ,QAAQ,CAAS;IAEzB,YAAY,SAAiB;QAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACzC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,GAAG,CAAC,QAAgB,EAAE,OAAe;QACnC,OAAO,UAAU,CAAC,QAAQ,CAAC;aACxB,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC;aAC1B,MAAM,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAChC,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAqB,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,MAAwB;QACvC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;QAC7C,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import type Graph from 'graphology';
2
+ /**
3
+ * Run Louvain community detection on the graph.
4
+ * Assigns the `community` attribute to each node in-place.
5
+ * Returns a map from communityId → list of nodeIds.
6
+ */
7
+ export declare function detectCommunities(graph: Graph): Promise<Record<number, string[]>>;
8
+ //# sourceMappingURL=cluster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/cluster.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAqBvF"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Run Louvain community detection on the graph.
3
+ * Assigns the `community` attribute to each node in-place.
4
+ * Returns a map from communityId → list of nodeIds.
5
+ */
6
+ export async function detectCommunities(graph) {
7
+ try {
8
+ const { default: louvain } = await import('graphology-communities-louvain');
9
+ const assignment = louvain(graph);
10
+ // Write community id back onto each node
11
+ for (const [nodeId, communityId] of Object.entries(assignment)) {
12
+ graph.setNodeAttribute(nodeId, 'community', communityId);
13
+ }
14
+ // Build communityId → members map
15
+ const communities = {};
16
+ for (const [nodeId, communityId] of Object.entries(assignment)) {
17
+ if (!communities[communityId])
18
+ communities[communityId] = [];
19
+ communities[communityId].push(nodeId);
20
+ }
21
+ return communities;
22
+ }
23
+ catch {
24
+ // Louvain unavailable — fall back to directory-based clustering
25
+ return fallbackCluster(graph);
26
+ }
27
+ }
28
+ /**
29
+ * Fallback: group nodes by the directory portion of their sourceFile attribute.
30
+ * Deterministic and zero-dependency.
31
+ */
32
+ function fallbackCluster(graph) {
33
+ const dirMap = new Map();
34
+ let nextId = 0;
35
+ const communities = {};
36
+ graph.forEachNode((id, attrs) => {
37
+ const file = attrs.sourceFile || '';
38
+ const parts = file.split('/');
39
+ const dir = parts.length > 1 ? parts.slice(0, -1).join('/') : 'root';
40
+ if (!dirMap.has(dir))
41
+ dirMap.set(dir, nextId++);
42
+ const cid = dirMap.get(dir);
43
+ graph.setNodeAttribute(id, 'community', cid);
44
+ if (!communities[cid])
45
+ communities[cid] = [];
46
+ communities[cid].push(id);
47
+ });
48
+ return communities;
49
+ }
50
+ //# sourceMappingURL=cluster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster.js","sourceRoot":"","sources":["../../src/cluster.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAY;IAClD,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAC;QAC5E,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAA2B,CAAC;QAE5D,yCAAyC;QACzC,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/D,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;QAC3D,CAAC;QAED,kCAAkC;QAClC,MAAM,WAAW,GAA6B,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/D,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC;gBAAE,WAAW,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;YAC7D,WAAW,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;QAChE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,KAAY;IACnC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,WAAW,GAA6B,EAAE,CAAC;IAEjD,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE;QAC9B,MAAM,IAAI,GAAI,KAAK,CAAC,UAAqB,IAAI,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAErE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;QAE7B,KAAK,CAAC,gBAAgB,CAAC,EAAE,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;QAC7C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;YAAE,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAC7C,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { BuildOptions, ClassifiedFile } from './types.js';
2
+ /**
3
+ * Recursively collects and classifies all files under rootPath, applying
4
+ * exclusion rules for directories, file size limits, and optional language
5
+ * filtering from BuildOptions.
6
+ */
7
+ export declare function collectFiles(rootPath: string, options?: BuildOptions): ClassifiedFile[];
8
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/detect.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAY,MAAM,YAAY,CAAC;AAwCzE;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,YAAiB,GACzB,cAAc,EAAE,CAwElB"}
@@ -0,0 +1,108 @@
1
+ import { readdirSync, statSync } from 'fs';
2
+ import { join, extname, relative } from 'path';
3
+ const DEFAULT_MAX_FILE_SIZE = 500 * 1024; // 500KB
4
+ const EXCLUDED_DIRS = new Set([
5
+ 'node_modules',
6
+ '.git',
7
+ 'dist',
8
+ 'build',
9
+ '.monobrain',
10
+ '__pycache__',
11
+ '.pytest_cache',
12
+ 'target',
13
+ '.cache',
14
+ ]);
15
+ // Maps file extension to [fileType, language]
16
+ const EXTENSION_MAP = {
17
+ '.ts': ['code', 'typescript'],
18
+ '.tsx': ['code', 'typescript'],
19
+ '.js': ['code', 'javascript'],
20
+ '.jsx': ['code', 'javascript'],
21
+ '.py': ['code', 'python'],
22
+ '.go': ['code', 'go'],
23
+ '.rs': ['code', 'rust'],
24
+ '.java': ['code', 'java'],
25
+ '.c': ['code', 'c'],
26
+ '.cpp': ['code', 'cpp'],
27
+ '.h': ['code', 'c'],
28
+ '.cs': ['code', 'csharp'],
29
+ '.rb': ['code', 'ruby'],
30
+ '.php': ['code', 'php'],
31
+ '.swift': ['code', 'swift'],
32
+ '.kt': ['code', 'kotlin'],
33
+ '.scala': ['code', 'scala'],
34
+ '.md': ['document', 'markdown'],
35
+ '.txt': ['document', 'text'],
36
+ '.rst': ['document', 'rst'],
37
+ };
38
+ /**
39
+ * Recursively collects and classifies all files under rootPath, applying
40
+ * exclusion rules for directories, file size limits, and optional language
41
+ * filtering from BuildOptions.
42
+ */
43
+ export function collectFiles(rootPath, options = {}) {
44
+ const maxFileSizeBytes = options.maxFileSizeBytes ?? DEFAULT_MAX_FILE_SIZE;
45
+ const codeOnly = options.codeOnly ?? false;
46
+ const languageFilter = options.languages ? new Set(options.languages) : null;
47
+ const excludePatterns = options.excludePatterns ?? [];
48
+ const results = [];
49
+ function walkDir(dirPath) {
50
+ let entries;
51
+ try {
52
+ entries = readdirSync(dirPath);
53
+ }
54
+ catch {
55
+ // Skip unreadable directories
56
+ return;
57
+ }
58
+ for (const entry of entries) {
59
+ const fullPath = join(dirPath, entry);
60
+ // Check against custom exclude patterns (matched against relative path)
61
+ const relPath = relative(rootPath, fullPath);
62
+ if (excludePatterns.some((pat) => relPath.includes(pat))) {
63
+ continue;
64
+ }
65
+ let stat;
66
+ try {
67
+ stat = statSync(fullPath);
68
+ }
69
+ catch {
70
+ continue;
71
+ }
72
+ if (stat.isDirectory()) {
73
+ // Skip excluded directory names
74
+ if (EXCLUDED_DIRS.has(entry))
75
+ continue;
76
+ walkDir(fullPath);
77
+ continue;
78
+ }
79
+ if (!stat.isFile())
80
+ continue;
81
+ // Enforce file size limit
82
+ if (stat.size > maxFileSizeBytes)
83
+ continue;
84
+ const ext = extname(entry).toLowerCase();
85
+ const mapping = EXTENSION_MAP[ext];
86
+ if (!mapping) {
87
+ // Unknown extension — skip rather than emit 'unknown' noise
88
+ continue;
89
+ }
90
+ const [fileType, language] = mapping;
91
+ // Apply codeOnly filter
92
+ if (codeOnly && fileType !== 'code')
93
+ continue;
94
+ // Apply language filter
95
+ if (languageFilter && !languageFilter.has(language))
96
+ continue;
97
+ results.push({
98
+ path: fullPath,
99
+ fileType,
100
+ language,
101
+ sizeBytes: stat.size,
102
+ });
103
+ }
104
+ }
105
+ walkDir(rootPath);
106
+ return results;
107
+ }
108
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import Graph from 'graphology';
2
+ /**
3
+ * Serialize a graphology graph to disk as a JSON file.
4
+ * Creates the output directory if it does not exist.
5
+ * Returns the absolute path to the written file.
6
+ */
7
+ export declare function saveGraph(graph: Graph, outputDir: string, projectPath: string): string;
8
+ /**
9
+ * Deserialize a graph from a previously saved JSON file.
10
+ * Silently skips edges whose endpoints are missing from the node list.
11
+ */
12
+ export declare function loadGraph(graphPath: string): Graph;
13
+ /**
14
+ * Return true when a graph.json already exists in the given output directory.
15
+ */
16
+ export declare function graphExists(outputDir: string): boolean;
17
+ /**
18
+ * Return the canonical path to graph.json inside an output directory.
19
+ */
20
+ export declare function getGraphPath(outputDir: string): string;
21
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/export.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,YAAY,CAAC;AAG/B;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAsBtF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAyBlD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtD"}
@@ -0,0 +1,68 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import Graph from 'graphology';
4
+ /**
5
+ * Serialize a graphology graph to disk as a JSON file.
6
+ * Creates the output directory if it does not exist.
7
+ * Returns the absolute path to the written file.
8
+ */
9
+ export function saveGraph(graph, outputDir, projectPath) {
10
+ mkdirSync(outputDir, { recursive: true });
11
+ const graphPath = join(outputDir, 'graph.json');
12
+ const nodes = [];
13
+ graph.forEachNode((id, attrs) => nodes.push({ id, ...attrs }));
14
+ const links = [];
15
+ graph.forEachEdge((_, attrs, source, target) => links.push({ source, target, ...attrs }));
16
+ const serialized = {
17
+ version: '1.0.0',
18
+ builtAt: new Date().toISOString(),
19
+ projectPath,
20
+ nodes,
21
+ links,
22
+ directed: graph.type === 'directed',
23
+ multigraph: graph.multi,
24
+ };
25
+ writeFileSync(graphPath, JSON.stringify(serialized, null, 2), 'utf-8');
26
+ return graphPath;
27
+ }
28
+ /**
29
+ * Deserialize a graph from a previously saved JSON file.
30
+ * Silently skips edges whose endpoints are missing from the node list.
31
+ */
32
+ export function loadGraph(graphPath) {
33
+ const raw = readFileSync(graphPath, 'utf-8');
34
+ const data = JSON.parse(raw);
35
+ const graph = new Graph({
36
+ type: data.directed ? 'directed' : 'undirected',
37
+ multi: false,
38
+ });
39
+ for (const node of data.nodes) {
40
+ const { id, ...attrs } = node;
41
+ graph.addNode(id, attrs);
42
+ }
43
+ for (const link of data.links) {
44
+ const { source, target, ...attrs } = link;
45
+ if (!graph.hasNode(source) || !graph.hasNode(target))
46
+ continue;
47
+ try {
48
+ graph.addEdge(source, target, attrs);
49
+ }
50
+ catch {
51
+ // Duplicate edge — ignore
52
+ }
53
+ }
54
+ return graph;
55
+ }
56
+ /**
57
+ * Return true when a graph.json already exists in the given output directory.
58
+ */
59
+ export function graphExists(outputDir) {
60
+ return existsSync(join(outputDir, 'graph.json'));
61
+ }
62
+ /**
63
+ * Return the canonical path to graph.json inside an output directory.
64
+ */
65
+ export function getGraphPath(outputDir) {
66
+ return join(outputDir, 'graph.json');
67
+ }
68
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { ClassifiedFile, ExtractionResult, BuildOptions } from '../types.js';
2
+ /**
3
+ * Extract graph nodes and edges from all classified files.
4
+ *
5
+ * Reads each file, checks the on-disk cache keyed by SHA-256 content hash,
6
+ * dispatches to the appropriate language extractor, and merges all results
7
+ * into a single ExtractionResult (nodes deduplicated by id, edges by source+target+relation).
8
+ *
9
+ * @param files - Classified files to process (from the classify layer)
10
+ * @param outputDir - Directory used for cache storage (.monobrain/graph by default)
11
+ * @param options - Build options (languages filter, maxFileSizeBytes, etc.)
12
+ */
13
+ export declare function extractAll(files: ClassifiedFile[], outputDir: string, options?: BuildOptions): Promise<ExtractionResult>;
14
+ export type { LanguageExtractor } from './types.js';
15
+ export { typescriptExtractor } from './languages/typescript.js';
16
+ export { pythonExtractor } from './languages/python.js';
17
+ export { goExtractor } from './languages/go.js';
18
+ export { rustExtractor } from './languages/rust.js';
19
+ export { isTreeSitterAvailable, tryLoadParser, walk, parseFile, parseFileFromDisk } from './tree-sitter-runner.js';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extract/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAwB,MAAM,aAAa,CAAC;AA+ExG;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,cAAc,EAAE,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,gBAAgB,CAAC,CAqF3B;AAGD,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC"}