@blamechris/repo-memory 0.1.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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +85 -0
  3. package/dist/cache/gc.d.ts +14 -0
  4. package/dist/cache/gc.d.ts.map +1 -0
  5. package/dist/cache/gc.js +75 -0
  6. package/dist/cache/gc.js.map +1 -0
  7. package/dist/cache/hash.d.ts +10 -0
  8. package/dist/cache/hash.d.ts.map +1 -0
  9. package/dist/cache/hash.js +22 -0
  10. package/dist/cache/hash.js.map +1 -0
  11. package/dist/cache/invalidation.d.ts +29 -0
  12. package/dist/cache/invalidation.d.ts.map +1 -0
  13. package/dist/cache/invalidation.js +58 -0
  14. package/dist/cache/invalidation.js.map +1 -0
  15. package/dist/cache/ranking.d.ts +57 -0
  16. package/dist/cache/ranking.d.ts.map +1 -0
  17. package/dist/cache/ranking.js +196 -0
  18. package/dist/cache/ranking.js.map +1 -0
  19. package/dist/cache/store.d.ts +16 -0
  20. package/dist/cache/store.d.ts.map +1 -0
  21. package/dist/cache/store.js +70 -0
  22. package/dist/cache/store.js.map +1 -0
  23. package/dist/graph/dependency-graph.d.ts +26 -0
  24. package/dist/graph/dependency-graph.d.ts.map +1 -0
  25. package/dist/graph/dependency-graph.js +131 -0
  26. package/dist/graph/dependency-graph.js.map +1 -0
  27. package/dist/indexer/diff-analyzer.d.ts +8 -0
  28. package/dist/indexer/diff-analyzer.d.ts.map +1 -0
  29. package/dist/indexer/diff-analyzer.js +95 -0
  30. package/dist/indexer/diff-analyzer.js.map +1 -0
  31. package/dist/indexer/imports.d.ts +3 -0
  32. package/dist/indexer/imports.d.ts.map +1 -0
  33. package/dist/indexer/imports.js +123 -0
  34. package/dist/indexer/imports.js.map +1 -0
  35. package/dist/indexer/project-map.d.ts +20 -0
  36. package/dist/indexer/project-map.d.ts.map +1 -0
  37. package/dist/indexer/project-map.js +120 -0
  38. package/dist/indexer/project-map.js.map +1 -0
  39. package/dist/indexer/scanner.d.ts +7 -0
  40. package/dist/indexer/scanner.d.ts.map +1 -0
  41. package/dist/indexer/scanner.js +114 -0
  42. package/dist/indexer/scanner.js.map +1 -0
  43. package/dist/indexer/smart-summarizer.d.ts +6 -0
  44. package/dist/indexer/smart-summarizer.d.ts.map +1 -0
  45. package/dist/indexer/smart-summarizer.js +26 -0
  46. package/dist/indexer/smart-summarizer.js.map +1 -0
  47. package/dist/indexer/summarizer.d.ts +3 -0
  48. package/dist/indexer/summarizer.d.ts.map +1 -0
  49. package/dist/indexer/summarizer.js +145 -0
  50. package/dist/indexer/summarizer.js.map +1 -0
  51. package/dist/memory/session.d.ts +18 -0
  52. package/dist/memory/session.d.ts.map +1 -0
  53. package/dist/memory/session.js +75 -0
  54. package/dist/memory/session.js.map +1 -0
  55. package/dist/memory/task.d.ts +35 -0
  56. package/dist/memory/task.d.ts.map +1 -0
  57. package/dist/memory/task.js +120 -0
  58. package/dist/memory/task.js.map +1 -0
  59. package/dist/persistence/db.d.ts +4 -0
  60. package/dist/persistence/db.d.ts.map +1 -0
  61. package/dist/persistence/db.js +146 -0
  62. package/dist/persistence/db.js.map +1 -0
  63. package/dist/server.d.ts +3 -0
  64. package/dist/server.d.ts.map +1 -0
  65. package/dist/server.js +197 -0
  66. package/dist/server.js.map +1 -0
  67. package/dist/telemetry/tracker.d.ts +40 -0
  68. package/dist/telemetry/tracker.d.ts.map +1 -0
  69. package/dist/telemetry/tracker.js +136 -0
  70. package/dist/telemetry/tracker.js.map +1 -0
  71. package/dist/tools/force-reread.d.ts +9 -0
  72. package/dist/tools/force-reread.d.ts.map +1 -0
  73. package/dist/tools/force-reread.js +17 -0
  74. package/dist/tools/force-reread.js.map +1 -0
  75. package/dist/tools/get-changed-files.d.ts +8 -0
  76. package/dist/tools/get-changed-files.d.ts.map +1 -0
  77. package/dist/tools/get-changed-files.js +61 -0
  78. package/dist/tools/get-changed-files.js.map +1 -0
  79. package/dist/tools/get-dependency-graph.d.ts +17 -0
  80. package/dist/tools/get-dependency-graph.d.ts.map +1 -0
  81. package/dist/tools/get-dependency-graph.js +88 -0
  82. package/dist/tools/get-dependency-graph.js.map +1 -0
  83. package/dist/tools/get-file-summary.d.ts +12 -0
  84. package/dist/tools/get-file-summary.d.ts.map +1 -0
  85. package/dist/tools/get-file-summary.js +53 -0
  86. package/dist/tools/get-file-summary.js.map +1 -0
  87. package/dist/tools/get-project-map.d.ts +3 -0
  88. package/dist/tools/get-project-map.d.ts.map +1 -0
  89. package/dist/tools/get-project-map.js +5 -0
  90. package/dist/tools/get-project-map.js.map +1 -0
  91. package/dist/tools/get-token-report.d.ts +16 -0
  92. package/dist/tools/get-token-report.d.ts.map +1 -0
  93. package/dist/tools/get-token-report.js +44 -0
  94. package/dist/tools/get-token-report.js.map +1 -0
  95. package/dist/tools/invalidate.d.ts +5 -0
  96. package/dist/tools/invalidate.d.ts.map +1 -0
  97. package/dist/tools/invalidate.js +19 -0
  98. package/dist/tools/invalidate.js.map +1 -0
  99. package/dist/tools/task-context.d.ts +18 -0
  100. package/dist/tools/task-context.d.ts.map +1 -0
  101. package/dist/tools/task-context.js +28 -0
  102. package/dist/tools/task-context.js.map +1 -0
  103. package/dist/types.d.ts +21 -0
  104. package/dist/types.d.ts.map +1 -0
  105. package/dist/types.js +2 -0
  106. package/dist/types.js.map +1 -0
  107. package/dist/utils/validate-path.d.ts +10 -0
  108. package/dist/utils/validate-path.d.ts.map +1 -0
  109. package/dist/utils/validate-path.js +22 -0
  110. package/dist/utils/validate-path.js.map +1 -0
  111. package/package.json +62 -0
@@ -0,0 +1,70 @@
1
+ import { getDatabase } from '../persistence/db.js';
2
+ function rowToEntry(row) {
3
+ return {
4
+ path: row.path,
5
+ hash: row.hash,
6
+ lastChecked: row.last_checked,
7
+ summary: row.summary_json ? JSON.parse(row.summary_json) : null,
8
+ };
9
+ }
10
+ export class CacheStore {
11
+ projectRoot;
12
+ constructor(projectRoot) {
13
+ this.projectRoot = projectRoot;
14
+ }
15
+ getEntry(path) {
16
+ const db = getDatabase(this.projectRoot);
17
+ const row = db
18
+ .prepare('SELECT path, hash, last_checked, summary_json FROM files WHERE path = ?')
19
+ .get(path);
20
+ return row ? rowToEntry(row) : null;
21
+ }
22
+ setEntry(path, hash, summary) {
23
+ const db = getDatabase(this.projectRoot);
24
+ const summaryJson = summary ? JSON.stringify(summary) : null;
25
+ const now = Date.now();
26
+ db.prepare(`INSERT INTO files (path, hash, last_checked, summary_json)
27
+ VALUES (?, ?, ?, ?)
28
+ ON CONFLICT(path) DO UPDATE SET
29
+ hash = excluded.hash,
30
+ last_checked = excluded.last_checked,
31
+ summary_json = excluded.summary_json`).run(path, hash, now, summaryJson);
32
+ }
33
+ getAllEntries() {
34
+ const db = getDatabase(this.projectRoot);
35
+ const rows = db
36
+ .prepare('SELECT path, hash, last_checked, summary_json FROM files')
37
+ .all();
38
+ return rows.map(rowToEntry);
39
+ }
40
+ deleteEntry(path) {
41
+ const db = getDatabase(this.projectRoot);
42
+ db.prepare('DELETE FROM files WHERE path = ?').run(path);
43
+ }
44
+ setEntries(entries) {
45
+ const db = getDatabase(this.projectRoot);
46
+ const now = Date.now();
47
+ const stmt = db.prepare(`INSERT INTO files (path, hash, last_checked, summary_json)
48
+ VALUES (?, ?, ?, ?)
49
+ ON CONFLICT(path) DO UPDATE SET
50
+ hash = excluded.hash,
51
+ last_checked = excluded.last_checked,
52
+ summary_json = excluded.summary_json`);
53
+ const runBatch = db.transaction(() => {
54
+ for (const entry of entries) {
55
+ const summaryJson = entry.summary ? JSON.stringify(entry.summary) : null;
56
+ stmt.run(entry.path, entry.hash, now, summaryJson);
57
+ }
58
+ });
59
+ runBatch();
60
+ }
61
+ getStaleEntries(maxAge) {
62
+ const db = getDatabase(this.projectRoot);
63
+ const cutoff = Date.now() - maxAge;
64
+ const rows = db
65
+ .prepare('SELECT path, hash, last_checked, summary_json FROM files WHERE last_checked < ?')
66
+ .all(cutoff);
67
+ return rows.map(rowToEntry);
68
+ }
69
+ }
70
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/cache/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export declare class DependencyGraph {
2
+ private readonly projectRoot;
3
+ private outgoing;
4
+ private incoming;
5
+ constructor(projectRoot: string);
6
+ /** Load graph from SQLite imports table into memory. */
7
+ load(): void;
8
+ /** Update edges for a single file (incremental). */
9
+ updateFile(filePath: string, contents: string): void;
10
+ /** Get direct dependencies of a file. */
11
+ getDependencies(path: string): string[];
12
+ /** Get direct dependents of a file. */
13
+ getDependents(path: string): string[];
14
+ /** Get transitive dependencies using BFS with optional depth limit. */
15
+ getTransitiveDependencies(path: string, maxDepth?: number): string[];
16
+ /** Get transitive dependents using BFS with optional depth limit. */
17
+ getTransitiveDependents(path: string, maxDepth?: number): string[];
18
+ /** Get the most connected nodes sorted by total degree (in + out). */
19
+ getMostConnected(limit?: number): Array<{
20
+ path: string;
21
+ connections: number;
22
+ }>;
23
+ private addEdge;
24
+ private bfs;
25
+ }
26
+ //# sourceMappingURL=dependency-graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-graph.d.ts","sourceRoot":"","sources":["../../src/graph/dependency-graph.ts"],"names":[],"mappings":"AAGA,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,QAAQ,CAA2B;gBAE/B,WAAW,EAAE,MAAM;IAM/B,wDAAwD;IACxD,IAAI,IAAI,IAAI;IAcZ,oDAAoD;IACpD,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAuCpD,yCAAyC;IACzC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAKvC,uCAAuC;IACvC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAKrC,uEAAuE;IACvE,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAIpE,qEAAqE;IACrE,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAIlE,sEAAsE;IACtE,gBAAgB,CAAC,KAAK,GAAE,MAAW,GAAG,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAgBlF,OAAO,CAAC,OAAO;IAgBf,OAAO,CAAC,GAAG;CAkCZ"}
@@ -0,0 +1,131 @@
1
+ import { getDatabase } from '../persistence/db.js';
2
+ import { extractImports } from '../indexer/imports.js';
3
+ export class DependencyGraph {
4
+ projectRoot;
5
+ outgoing; // source → targets
6
+ incoming; // target → sources
7
+ constructor(projectRoot) {
8
+ this.projectRoot = projectRoot;
9
+ this.outgoing = new Map();
10
+ this.incoming = new Map();
11
+ }
12
+ /** Load graph from SQLite imports table into memory. */
13
+ load() {
14
+ const db = getDatabase(this.projectRoot);
15
+ const rows = db
16
+ .prepare('SELECT source, target FROM imports')
17
+ .all();
18
+ this.outgoing.clear();
19
+ this.incoming.clear();
20
+ for (const row of rows) {
21
+ this.addEdge(row.source, row.target);
22
+ }
23
+ }
24
+ /** Update edges for a single file (incremental). */
25
+ updateFile(filePath, contents) {
26
+ const db = getDatabase(this.projectRoot);
27
+ // Remove old outgoing edges from in-memory maps
28
+ const oldTargets = this.outgoing.get(filePath);
29
+ if (oldTargets) {
30
+ for (const target of oldTargets) {
31
+ const sources = this.incoming.get(target);
32
+ if (sources) {
33
+ sources.delete(filePath);
34
+ if (sources.size === 0) {
35
+ this.incoming.delete(target);
36
+ }
37
+ }
38
+ }
39
+ this.outgoing.delete(filePath);
40
+ }
41
+ // Delete old rows from DB
42
+ db.prepare('DELETE FROM imports WHERE source = ?').run(filePath);
43
+ // Extract new imports
44
+ const imports = extractImports(filePath, contents, this.projectRoot);
45
+ // Insert new rows and update in-memory maps
46
+ const insert = db.prepare('INSERT OR REPLACE INTO imports (source, target, specifiers, import_type) VALUES (?, ?, ?, ?)');
47
+ const insertAll = db.transaction(() => {
48
+ for (const ref of imports) {
49
+ insert.run(ref.source, ref.target, JSON.stringify(ref.specifiers), ref.type);
50
+ this.addEdge(ref.source, ref.target);
51
+ }
52
+ });
53
+ insertAll();
54
+ }
55
+ /** Get direct dependencies of a file. */
56
+ getDependencies(path) {
57
+ const targets = this.outgoing.get(path);
58
+ return targets ? [...targets] : [];
59
+ }
60
+ /** Get direct dependents of a file. */
61
+ getDependents(path) {
62
+ const sources = this.incoming.get(path);
63
+ return sources ? [...sources] : [];
64
+ }
65
+ /** Get transitive dependencies using BFS with optional depth limit. */
66
+ getTransitiveDependencies(path, maxDepth) {
67
+ return this.bfs(path, this.outgoing, maxDepth);
68
+ }
69
+ /** Get transitive dependents using BFS with optional depth limit. */
70
+ getTransitiveDependents(path, maxDepth) {
71
+ return this.bfs(path, this.incoming, maxDepth);
72
+ }
73
+ /** Get the most connected nodes sorted by total degree (in + out). */
74
+ getMostConnected(limit = 10) {
75
+ const allNodes = new Set();
76
+ for (const key of this.outgoing.keys())
77
+ allNodes.add(key);
78
+ for (const key of this.incoming.keys())
79
+ allNodes.add(key);
80
+ const result = [];
81
+ for (const node of allNodes) {
82
+ const outDegree = this.outgoing.get(node)?.size ?? 0;
83
+ const inDegree = this.incoming.get(node)?.size ?? 0;
84
+ result.push({ path: node, connections: outDegree + inDegree });
85
+ }
86
+ result.sort((a, b) => b.connections - a.connections);
87
+ return result.slice(0, limit);
88
+ }
89
+ addEdge(source, target) {
90
+ let targets = this.outgoing.get(source);
91
+ if (!targets) {
92
+ targets = new Set();
93
+ this.outgoing.set(source, targets);
94
+ }
95
+ targets.add(target);
96
+ let sources = this.incoming.get(target);
97
+ if (!sources) {
98
+ sources = new Set();
99
+ this.incoming.set(target, sources);
100
+ }
101
+ sources.add(source);
102
+ }
103
+ bfs(start, adjacency, maxDepth) {
104
+ const visited = new Set();
105
+ const queue = [];
106
+ const neighbors = adjacency.get(start);
107
+ if (!neighbors)
108
+ return [];
109
+ for (const neighbor of neighbors) {
110
+ queue.push({ node: neighbor, depth: 1 });
111
+ }
112
+ while (queue.length > 0) {
113
+ const { node, depth } = queue.shift();
114
+ if (visited.has(node) || node === start)
115
+ continue;
116
+ visited.add(node);
117
+ if (maxDepth !== undefined && depth >= maxDepth)
118
+ continue;
119
+ const next = adjacency.get(node);
120
+ if (next) {
121
+ for (const n of next) {
122
+ if (!visited.has(n) && n !== start) {
123
+ queue.push({ node: n, depth: depth + 1 });
124
+ }
125
+ }
126
+ }
127
+ }
128
+ return [...visited];
129
+ }
130
+ }
131
+ //# sourceMappingURL=dependency-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-graph.js","sourceRoot":"","sources":["../../src/graph/dependency-graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface DiffAnalysis {
2
+ structural: boolean;
3
+ affectedExports: string[];
4
+ affectedImports: string[];
5
+ lineCountChanged: boolean;
6
+ }
7
+ export declare function analyzeDiff(filePath: string, projectRoot: string): DiffAnalysis;
8
+ //# sourceMappingURL=diff-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-analyzer.d.ts","sourceRoot":"","sources":["../../src/indexer/diff-analyzer.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAyCD,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,YAAY,CAsEd"}
@@ -0,0 +1,95 @@
1
+ import { execFileSync } from 'child_process';
2
+ const EXPORT_PATTERN = /export\s+(?:default\s+)?(?:const|function|class|interface|type|enum)\b/;
3
+ const IMPORT_PATTERN = /import\s+.*?\s+from\s+['"]|import\s+['"]/;
4
+ const DECLARATION_PATTERN = /(?:function|class|interface|type|enum)\s+\w+/;
5
+ function extractAffectedExports(lines) {
6
+ const results = [];
7
+ const re = /export\s+(?:default\s+)?(?:const|let|var|function\s*\*?|class|interface|type|enum|abstract\s+class)\s+(\w+)/;
8
+ for (const line of lines) {
9
+ const match = re.exec(line);
10
+ if (match) {
11
+ results.push(match[1]);
12
+ }
13
+ }
14
+ return [...new Set(results)];
15
+ }
16
+ function extractAffectedImports(lines) {
17
+ const results = [];
18
+ const fromRe = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/;
19
+ const sideEffectRe = /import\s+['"]([^'"]+)['"]/;
20
+ for (const line of lines) {
21
+ const fromMatch = fromRe.exec(line);
22
+ if (fromMatch) {
23
+ results.push(fromMatch[1]);
24
+ continue;
25
+ }
26
+ const sideMatch = sideEffectRe.exec(line);
27
+ if (sideMatch) {
28
+ results.push(sideMatch[1]);
29
+ }
30
+ }
31
+ return [...new Set(results)];
32
+ }
33
+ export function analyzeDiff(filePath, projectRoot) {
34
+ let diffOutput;
35
+ try {
36
+ diffOutput = execFileSync('git', ['diff', 'HEAD', '--', filePath], {
37
+ cwd: projectRoot,
38
+ encoding: 'utf-8',
39
+ timeout: 10_000,
40
+ });
41
+ }
42
+ catch {
43
+ return {
44
+ structural: true,
45
+ affectedExports: [],
46
+ affectedImports: [],
47
+ lineCountChanged: true,
48
+ };
49
+ }
50
+ if (!diffOutput.trim()) {
51
+ return {
52
+ structural: true,
53
+ affectedExports: [],
54
+ affectedImports: [],
55
+ lineCountChanged: true,
56
+ };
57
+ }
58
+ const diffLines = diffOutput.split('\n');
59
+ const changedLines = [];
60
+ let addedLines = 0;
61
+ let removedLines = 0;
62
+ for (const line of diffLines) {
63
+ if (line.startsWith('@@') || line.startsWith('diff ') ||
64
+ line.startsWith('index ') || line.startsWith('---') ||
65
+ line.startsWith('+++')) {
66
+ continue;
67
+ }
68
+ if (line.startsWith('+')) {
69
+ addedLines++;
70
+ changedLines.push(line.slice(1));
71
+ }
72
+ else if (line.startsWith('-')) {
73
+ removedLines++;
74
+ changedLines.push(line.slice(1));
75
+ }
76
+ }
77
+ const lineCountChanged = addedLines !== removedLines;
78
+ let structural = false;
79
+ for (const line of changedLines) {
80
+ if (EXPORT_PATTERN.test(line) || IMPORT_PATTERN.test(line) ||
81
+ DECLARATION_PATTERN.test(line)) {
82
+ structural = true;
83
+ break;
84
+ }
85
+ }
86
+ const affectedExports = extractAffectedExports(changedLines);
87
+ const affectedImports = extractAffectedImports(changedLines);
88
+ return {
89
+ structural,
90
+ affectedExports,
91
+ affectedImports,
92
+ lineCountChanged,
93
+ };
94
+ }
95
+ //# sourceMappingURL=diff-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-analyzer.js","sourceRoot":"","sources":["../../src/indexer/diff-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ImportRef } from '../types.js';
2
+ export declare function extractImports(filePath: string, contents: string, projectRoot: string): ImportRef[];
3
+ //# sourceMappingURL=imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/indexer/imports.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAmB7C,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,SAAS,EAAE,CAuHb"}
@@ -0,0 +1,123 @@
1
+ import { dirname, join, normalize, relative } from 'path';
2
+ function isRelativeImport(specifier) {
3
+ return specifier.startsWith('./') || specifier.startsWith('../');
4
+ }
5
+ function resolveTarget(importSpecifier, filePath, projectRoot) {
6
+ if (!isRelativeImport(importSpecifier)) {
7
+ return importSpecifier;
8
+ }
9
+ const fileDir = dirname(join(projectRoot, filePath));
10
+ const resolved = normalize(join(fileDir, importSpecifier));
11
+ return relative(projectRoot, resolved);
12
+ }
13
+ export function extractImports(filePath, contents, projectRoot) {
14
+ const results = [];
15
+ const source = filePath;
16
+ // Static imports: import { Foo, Bar } from './module'
17
+ const namedImportRe = /import\s+(?:type\s+)?\{([^}]*)\}\s+from\s+['"]([^'"]+)['"]/g;
18
+ let match;
19
+ while ((match = namedImportRe.exec(contents)) !== null) {
20
+ const specifiers = match[1]
21
+ .split(',')
22
+ .map((s) => s.trim().split(/\s+as\s+/)[0].trim())
23
+ .filter(Boolean);
24
+ results.push({
25
+ source,
26
+ target: resolveTarget(match[2], filePath, projectRoot),
27
+ specifiers,
28
+ type: 'static',
29
+ });
30
+ }
31
+ // Default imports: import Foo from './module'
32
+ const defaultImportRe = /import\s+([A-Za-z_$][\w$]*)\s+from\s+['"]([^'"]+)['"]/g;
33
+ while ((match = defaultImportRe.exec(contents)) !== null) {
34
+ // Skip if this is a type import or already caught by named/namespace
35
+ const fullMatch = match[0];
36
+ if (fullMatch.includes('{') || fullMatch.includes('*'))
37
+ continue;
38
+ results.push({
39
+ source,
40
+ target: resolveTarget(match[2], filePath, projectRoot),
41
+ specifiers: [match[1]],
42
+ type: 'static',
43
+ });
44
+ }
45
+ // Namespace imports: import * as Foo from './module'
46
+ const namespaceImportRe = /import\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s+['"]([^'"]+)['"]/g;
47
+ while ((match = namespaceImportRe.exec(contents)) !== null) {
48
+ results.push({
49
+ source,
50
+ target: resolveTarget(match[2], filePath, projectRoot),
51
+ specifiers: [`* as ${match[1]}`],
52
+ type: 'static',
53
+ });
54
+ }
55
+ // Side-effect imports: import './module'
56
+ const sideEffectRe = /import\s+['"]([^'"]+)['"]/g;
57
+ while ((match = sideEffectRe.exec(contents)) !== null) {
58
+ // Make sure this isn't part of a larger import statement
59
+ // Check that the character before 'import' is not a word char or }
60
+ const beforeIndex = match.index - 1;
61
+ if (beforeIndex >= 0) {
62
+ const before = contents[beforeIndex];
63
+ if (before && /\w/.test(before))
64
+ continue;
65
+ }
66
+ // Ensure it's not from-style import (those have "from" before the string)
67
+ const precedingText = contents.slice(Math.max(0, match.index - 5), match.index);
68
+ if (/from\s*$/.test(precedingText))
69
+ continue;
70
+ results.push({
71
+ source,
72
+ target: resolveTarget(match[1], filePath, projectRoot),
73
+ specifiers: [],
74
+ type: 'static',
75
+ });
76
+ }
77
+ // Dynamic imports: import('./module')
78
+ const dynamicImportRe = /import\(\s*['"]([^'"]+)['"]\s*\)/g;
79
+ while ((match = dynamicImportRe.exec(contents)) !== null) {
80
+ results.push({
81
+ source,
82
+ target: resolveTarget(match[1], filePath, projectRoot),
83
+ specifiers: [],
84
+ type: 'dynamic',
85
+ });
86
+ }
87
+ // Re-exports: export { Foo } from './module'
88
+ const reExportNamedRe = /export\s+\{([^}]*)\}\s+from\s+['"]([^'"]+)['"]/g;
89
+ while ((match = reExportNamedRe.exec(contents)) !== null) {
90
+ const specifiers = match[1]
91
+ .split(',')
92
+ .map((s) => s.trim().split(/\s+as\s+/)[0].trim())
93
+ .filter(Boolean);
94
+ results.push({
95
+ source,
96
+ target: resolveTarget(match[2], filePath, projectRoot),
97
+ specifiers,
98
+ type: 're-export',
99
+ });
100
+ }
101
+ // Re-exports: export * from './module'
102
+ const reExportAllRe = /export\s+\*\s+from\s+['"]([^'"]+)['"]/g;
103
+ while ((match = reExportAllRe.exec(contents)) !== null) {
104
+ results.push({
105
+ source,
106
+ target: resolveTarget(match[1], filePath, projectRoot),
107
+ specifiers: ['*'],
108
+ type: 're-export',
109
+ });
110
+ }
111
+ // require() calls
112
+ const requireRe = /require\(\s*['"]([^'"]+)['"]\s*\)/g;
113
+ while ((match = requireRe.exec(contents)) !== null) {
114
+ results.push({
115
+ source,
116
+ target: resolveTarget(match[1], filePath, projectRoot),
117
+ specifiers: [],
118
+ type: 'static',
119
+ });
120
+ }
121
+ return results;
122
+ }
123
+ //# sourceMappingURL=imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.js","sourceRoot":"","sources":["../../src/indexer/imports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAG1D,SAAS,gBAAgB,CAAC,SAAiB;IACzC,OAAO,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,aAAa,CACpB,eAAuB,EACvB,QAAgB,EAChB,WAAmB;IAEnB,IAAI,CAAC,gBAAgB,CAAC,eAAe,CAAC,EAAE,CAAC;QACvC,OAAO,eAAe,CAAC;IACzB,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC;IAC3D,OAAO,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,QAAgB,EAChB,QAAgB,EAChB,WAAmB;IAEnB,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,QAAQ,CAAC;IAExB,sDAAsD;IACtD,MAAM,aAAa,GACjB,6DAA6D,CAAC;IAChE,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACvD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC;aACxB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aAChD,MAAM,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC;YACtD,UAAU;YACV,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;IACL,CAAC;IAED,8CAA8C;IAC9C,MAAM,eAAe,GACnB,wDAAwD,CAAC;IAC3D,OAAO,CAAC,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACzD,qEAAqE;QACrE,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QACjE,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC;YACtD,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;IACL,CAAC;IAED,qDAAqD;IACrD,MAAM,iBAAiB,GACrB,kEAAkE,CAAC;IACrE,OAAO,CAAC,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC;YACtD,UAAU,EAAE,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAChC,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;IACL,CAAC;IAED,yCAAyC;IACzC,MAAM,YAAY,GAAG,4BAA4B,CAAC;IAClD,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACtD,yDAAyD;QACzD,mEAAmE;QACnE,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;QACpC,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;YACrC,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;gBAAE,SAAS;QAC5C,CAAC;QACD,0EAA0E;QAC1E,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAChF,IAAI,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC;YAAE,SAAS;QAC7C,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC;YACtD,UAAU,EAAE,EAAE;YACd,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;IACL,CAAC;IAED,sCAAsC;IACtC,MAAM,eAAe,GAAG,mCAAmC,CAAC;IAC5D,OAAO,CAAC,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC;YACtD,UAAU,EAAE,EAAE;YACd,IAAI,EAAE,SAAS;SAChB,CAAC,CAAC;IACL,CAAC;IAED,6CAA6C;IAC7C,MAAM,eAAe,GACnB,iDAAiD,CAAC;IACpD,OAAO,CAAC,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACzD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC;aACxB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aAChD,MAAM,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC;YACtD,UAAU;YACV,IAAI,EAAE,WAAW;SAClB,CAAC,CAAC;IACL,CAAC;IAED,uCAAuC;IACvC,MAAM,aAAa,GAAG,wCAAwC,CAAC;IAC/D,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC;YACtD,UAAU,EAAE,CAAC,GAAG,CAAC;YACjB,IAAI,EAAE,WAAW;SAClB,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB;IAClB,MAAM,SAAS,GAAG,oCAAoC,CAAC;IACvD,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC;YACtD,UAAU,EAAE,EAAE;YACd,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,20 @@
1
+ export interface DirectoryNode {
2
+ name: string;
3
+ path: string;
4
+ files: Array<{
5
+ name: string;
6
+ purpose: string;
7
+ }>;
8
+ children: DirectoryNode[];
9
+ fileCount: number;
10
+ }
11
+ export interface ProjectMap {
12
+ tree: DirectoryNode;
13
+ entryPoints: string[];
14
+ totalFiles: number;
15
+ languageBreakdown: Record<string, number>;
16
+ }
17
+ export declare function buildProjectMap(projectRoot: string, options?: {
18
+ depth?: number;
19
+ }): Promise<ProjectMap>;
20
+ //# sourceMappingURL=project-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-map.d.ts","sourceRoot":"","sources":["../../src/indexer/project-map.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAmID,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,UAAU,CAAC,CAWrB"}
@@ -0,0 +1,120 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join, dirname, basename, extname } from 'node:path';
3
+ import { scanProject } from './scanner.js';
4
+ import { summarizeFile } from './summarizer.js';
5
+ import { CacheStore } from '../cache/store.js';
6
+ import { hashContents } from '../cache/hash.js';
7
+ async function getSummaries(projectRoot, files) {
8
+ const cache = new CacheStore(projectRoot);
9
+ const entries = [];
10
+ for (const relativePath of files) {
11
+ const cached = cache.getEntry(relativePath);
12
+ if (cached?.summary) {
13
+ entries.push({ relativePath, summary: cached.summary });
14
+ continue;
15
+ }
16
+ const absolutePath = join(projectRoot, relativePath);
17
+ let contents;
18
+ try {
19
+ contents = await readFile(absolutePath, 'utf-8');
20
+ }
21
+ catch {
22
+ continue;
23
+ }
24
+ const summary = summarizeFile(relativePath, contents);
25
+ const hash = hashContents(contents);
26
+ cache.setEntry(relativePath, hash, summary);
27
+ entries.push({ relativePath, summary });
28
+ }
29
+ return entries;
30
+ }
31
+ function buildTree(entries, rootName, maxDepth) {
32
+ const root = {
33
+ name: rootName,
34
+ path: '.',
35
+ files: [],
36
+ children: [],
37
+ fileCount: 0,
38
+ };
39
+ const dirMap = new Map();
40
+ dirMap.set('.', root);
41
+ function getOrCreateDir(dirPath, currentDepth) {
42
+ if (dirPath === '.')
43
+ return root;
44
+ if (maxDepth !== undefined && currentDepth > maxDepth)
45
+ return null;
46
+ const existing = dirMap.get(dirPath);
47
+ if (existing)
48
+ return existing;
49
+ const parentPath = dirname(dirPath);
50
+ const parentDepth = parentPath === '.' ? 0 : parentPath.split('/').length;
51
+ const parent = getOrCreateDir(parentPath, parentDepth);
52
+ if (!parent)
53
+ return null;
54
+ const node = {
55
+ name: basename(dirPath),
56
+ path: dirPath,
57
+ files: [],
58
+ children: [],
59
+ fileCount: 0,
60
+ };
61
+ dirMap.set(dirPath, node);
62
+ parent.children.push(node);
63
+ return node;
64
+ }
65
+ for (const entry of entries) {
66
+ const dirPath = dirname(entry.relativePath);
67
+ const depth = dirPath === '.' ? 0 : dirPath.split('/').length;
68
+ const dir = getOrCreateDir(dirPath, depth);
69
+ if (!dir)
70
+ continue;
71
+ dir.files.push({
72
+ name: basename(entry.relativePath),
73
+ purpose: entry.summary.purpose,
74
+ });
75
+ }
76
+ function computeFileCounts(node) {
77
+ let count = node.files.length;
78
+ for (const child of node.children) {
79
+ count += computeFileCounts(child);
80
+ }
81
+ node.fileCount = count;
82
+ return count;
83
+ }
84
+ computeFileCounts(root);
85
+ function sortTree(node) {
86
+ node.files.sort((a, b) => a.name.localeCompare(b.name));
87
+ node.children.sort((a, b) => a.name.localeCompare(b.name));
88
+ for (const child of node.children) {
89
+ sortTree(child);
90
+ }
91
+ }
92
+ sortTree(root);
93
+ return root;
94
+ }
95
+ function computeLanguageBreakdown(files) {
96
+ const breakdown = {};
97
+ for (const file of files) {
98
+ const ext = extname(file) || '(no extension)';
99
+ breakdown[ext] = (breakdown[ext] ?? 0) + 1;
100
+ }
101
+ return breakdown;
102
+ }
103
+ function findEntryPoints(entries) {
104
+ return entries
105
+ .filter((e) => e.summary.purpose === 'entry point')
106
+ .map((e) => e.relativePath)
107
+ .sort();
108
+ }
109
+ export async function buildProjectMap(projectRoot, options) {
110
+ const files = await scanProject(projectRoot);
111
+ const entries = await getSummaries(projectRoot, files);
112
+ const rootName = basename(projectRoot);
113
+ return {
114
+ tree: buildTree(entries, rootName, options?.depth),
115
+ entryPoints: findEntryPoints(entries),
116
+ totalFiles: files.length,
117
+ languageBreakdown: computeLanguageBreakdown(files),
118
+ };
119
+ }
120
+ //# sourceMappingURL=project-map.js.map