@theihtisham/agent-shadow-brain 1.1.1 → 2.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 (102) hide show
  1. package/README.md +738 -138
  2. package/dist/adapters/aider.d.ts +11 -0
  3. package/dist/adapters/aider.d.ts.map +1 -0
  4. package/dist/adapters/aider.js +149 -0
  5. package/dist/adapters/aider.js.map +1 -0
  6. package/dist/adapters/index.d.ts +3 -1
  7. package/dist/adapters/index.d.ts.map +1 -1
  8. package/dist/adapters/index.js +5 -3
  9. package/dist/adapters/index.js.map +1 -1
  10. package/dist/adapters/roo-code.d.ts +14 -0
  11. package/dist/adapters/roo-code.d.ts.map +1 -0
  12. package/dist/adapters/roo-code.js +186 -0
  13. package/dist/adapters/roo-code.js.map +1 -0
  14. package/dist/brain/adr-engine.d.ts +58 -0
  15. package/dist/brain/adr-engine.d.ts.map +1 -0
  16. package/dist/brain/adr-engine.js +400 -0
  17. package/dist/brain/adr-engine.js.map +1 -0
  18. package/dist/brain/auto-update.d.ts +9 -0
  19. package/dist/brain/auto-update.d.ts.map +1 -0
  20. package/dist/brain/auto-update.js +59 -0
  21. package/dist/brain/auto-update.js.map +1 -0
  22. package/dist/brain/code-metrics.d.ts +18 -0
  23. package/dist/brain/code-metrics.d.ts.map +1 -0
  24. package/dist/brain/code-metrics.js +224 -0
  25. package/dist/brain/code-metrics.js.map +1 -0
  26. package/dist/brain/code-similarity.d.ts +43 -0
  27. package/dist/brain/code-similarity.d.ts.map +1 -0
  28. package/dist/brain/code-similarity.js +227 -0
  29. package/dist/brain/code-similarity.js.map +1 -0
  30. package/dist/brain/context-completion.d.ts +39 -0
  31. package/dist/brain/context-completion.d.ts.map +1 -0
  32. package/dist/brain/context-completion.js +851 -0
  33. package/dist/brain/context-completion.js.map +1 -0
  34. package/dist/brain/custom-rules.d.ts +14 -0
  35. package/dist/brain/custom-rules.d.ts.map +1 -0
  36. package/dist/brain/custom-rules.js +108 -0
  37. package/dist/brain/custom-rules.js.map +1 -0
  38. package/dist/brain/dependency-graph.d.ts +35 -0
  39. package/dist/brain/dependency-graph.d.ts.map +1 -0
  40. package/dist/brain/dependency-graph.js +310 -0
  41. package/dist/brain/dependency-graph.js.map +1 -0
  42. package/dist/brain/learning-engine.d.ts +54 -0
  43. package/dist/brain/learning-engine.d.ts.map +1 -0
  44. package/dist/brain/learning-engine.js +855 -0
  45. package/dist/brain/learning-engine.js.map +1 -0
  46. package/dist/brain/mcp-server.d.ts +30 -0
  47. package/dist/brain/mcp-server.d.ts.map +1 -0
  48. package/dist/brain/mcp-server.js +408 -0
  49. package/dist/brain/mcp-server.js.map +1 -0
  50. package/dist/brain/multi-project.d.ts +13 -0
  51. package/dist/brain/multi-project.d.ts.map +1 -0
  52. package/dist/brain/multi-project.js +163 -0
  53. package/dist/brain/multi-project.js.map +1 -0
  54. package/dist/brain/neural-mesh.d.ts +69 -0
  55. package/dist/brain/neural-mesh.d.ts.map +1 -0
  56. package/dist/brain/neural-mesh.js +677 -0
  57. package/dist/brain/neural-mesh.js.map +1 -0
  58. package/dist/brain/notifier.d.ts +26 -0
  59. package/dist/brain/notifier.d.ts.map +1 -0
  60. package/dist/brain/notifier.js +151 -0
  61. package/dist/brain/notifier.js.map +1 -0
  62. package/dist/brain/orchestrator.d.ts +148 -1
  63. package/dist/brain/orchestrator.d.ts.map +1 -1
  64. package/dist/brain/orchestrator.js +428 -0
  65. package/dist/brain/orchestrator.js.map +1 -1
  66. package/dist/brain/perf-profiler.d.ts +14 -0
  67. package/dist/brain/perf-profiler.d.ts.map +1 -0
  68. package/dist/brain/perf-profiler.js +289 -0
  69. package/dist/brain/perf-profiler.js.map +1 -0
  70. package/dist/brain/pr-generator.d.ts +19 -0
  71. package/dist/brain/pr-generator.d.ts.map +1 -0
  72. package/dist/brain/pr-generator.js +199 -0
  73. package/dist/brain/pr-generator.js.map +1 -0
  74. package/dist/brain/project-config.d.ts +14 -0
  75. package/dist/brain/project-config.d.ts.map +1 -0
  76. package/dist/brain/project-config.js +121 -0
  77. package/dist/brain/project-config.js.map +1 -0
  78. package/dist/brain/semantic-analyzer.d.ts +46 -0
  79. package/dist/brain/semantic-analyzer.d.ts.map +1 -0
  80. package/dist/brain/semantic-analyzer.js +496 -0
  81. package/dist/brain/semantic-analyzer.js.map +1 -0
  82. package/dist/brain/team-mode.d.ts +27 -0
  83. package/dist/brain/team-mode.d.ts.map +1 -0
  84. package/dist/brain/team-mode.js +262 -0
  85. package/dist/brain/team-mode.js.map +1 -0
  86. package/dist/brain/type-safety.d.ts +13 -0
  87. package/dist/brain/type-safety.d.ts.map +1 -0
  88. package/dist/brain/type-safety.js +217 -0
  89. package/dist/brain/type-safety.js.map +1 -0
  90. package/dist/brain/vuln-scanner.d.ts +16 -0
  91. package/dist/brain/vuln-scanner.d.ts.map +1 -0
  92. package/dist/brain/vuln-scanner.js +279 -0
  93. package/dist/brain/vuln-scanner.js.map +1 -0
  94. package/dist/cli.js +813 -3
  95. package/dist/cli.js.map +1 -1
  96. package/dist/index.d.ts +24 -1
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +26 -1
  99. package/dist/index.js.map +1 -1
  100. package/dist/types.d.ts +320 -0
  101. package/dist/types.d.ts.map +1 -1
  102. package/package.json +88 -77
@@ -0,0 +1,224 @@
1
+ // src/brain/code-metrics.ts — Code metrics: LOC, complexity, language breakdown, churn
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ const LANGUAGE_MAP = {
5
+ '.ts': 'TypeScript', '.tsx': 'TypeScript', '.js': 'JavaScript', '.jsx': 'JavaScript',
6
+ '.py': 'Python', '.rb': 'Ruby', '.go': 'Go', '.rs': 'Rust', '.java': 'Java',
7
+ '.kt': 'Kotlin', '.swift': 'Swift', '.c': 'C', '.cpp': 'C++', '.h': 'C/C++',
8
+ '.cs': 'C#', '.php': 'PHP', '.scala': 'Scala', '.r': 'R', '.sql': 'SQL',
9
+ '.sh': 'Shell', '.bash': 'Shell', '.ps1': 'PowerShell',
10
+ '.html': 'HTML', '.css': 'CSS', '.scss': 'SCSS', '.less': 'LESS',
11
+ '.json': 'JSON', '.yaml': 'YAML', '.yml': 'YAML', '.toml': 'TOML',
12
+ '.md': 'Markdown', '.vue': 'Vue', '.svelte': 'Svelte',
13
+ };
14
+ const IGNORE_DIRS = new Set([
15
+ 'node_modules', '.git', 'dist', 'build', 'out', 'target', 'vendor',
16
+ '__pycache__', '.next', '.nuxt', 'coverage', '.cache', '.tox',
17
+ 'venv', '.venv', 'env', '.env', 'bin', 'obj', 'Pods', '.gradle',
18
+ ]);
19
+ export class CodeMetricsEngine {
20
+ constructor(projectDir, opts) {
21
+ this.projectDir = projectDir;
22
+ this.excludePaths = opts?.excludePaths || [];
23
+ this.complexityThreshold = opts?.complexityThreshold || 15;
24
+ }
25
+ compute(changes) {
26
+ const files = this.walkDir(this.projectDir);
27
+ const languages = {};
28
+ const fileTypes = {};
29
+ const largestFiles = [];
30
+ const complexityHotspots = [];
31
+ let totalLines = 0;
32
+ let codeLines = 0;
33
+ let commentLines = 0;
34
+ let blankLines = 0;
35
+ for (const filePath of files) {
36
+ const ext = path.extname(filePath);
37
+ const lang = LANGUAGE_MAP[ext] || 'Other';
38
+ const relPath = path.relative(this.projectDir, filePath);
39
+ fileTypes[ext] = (fileTypes[ext] || 0) + 1;
40
+ try {
41
+ const content = fs.readFileSync(filePath, 'utf-8');
42
+ const lines = content.split('\n');
43
+ const lineCount = lines.length;
44
+ // Classify lines
45
+ let fileCodeLines = 0;
46
+ let fileCommentLines = 0;
47
+ let fileBlankLines = 0;
48
+ for (const line of lines) {
49
+ const trimmed = line.trim();
50
+ if (trimmed === '') {
51
+ fileBlankLines++;
52
+ continue;
53
+ }
54
+ if (trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('/*') ||
55
+ trimmed.startsWith('*') || trimmed.startsWith('"""') || trimmed.startsWith("'''")) {
56
+ fileCommentLines++;
57
+ }
58
+ else {
59
+ fileCodeLines++;
60
+ }
61
+ }
62
+ totalLines += lineCount;
63
+ codeLines += fileCodeLines;
64
+ commentLines += fileCommentLines;
65
+ blankLines += fileBlankLines;
66
+ // Track language stats
67
+ if (!languages[lang])
68
+ languages[lang] = { files: 0, lines: 0, percentage: 0 };
69
+ languages[lang].files++;
70
+ languages[lang].lines += lineCount;
71
+ // Track largest files
72
+ largestFiles.push({ path: relPath, lines: lineCount });
73
+ // Estimate complexity for code files
74
+ if (['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.java', '.rs'].includes(ext)) {
75
+ const complexity = this.estimateComplexity(content);
76
+ const functions = this.countFunctions(content);
77
+ if (complexity >= this.complexityThreshold) {
78
+ complexityHotspots.push({ path: relPath, complexity, functions });
79
+ }
80
+ }
81
+ }
82
+ catch { /* binary or unreadable file */ }
83
+ }
84
+ // Calculate percentages
85
+ for (const lang of Object.values(languages)) {
86
+ lang.percentage = totalLines > 0 ? Math.round((lang.lines / totalLines) * 100) : 0;
87
+ }
88
+ // Sort largest files
89
+ largestFiles.sort((a, b) => b.lines - a.lines);
90
+ complexityHotspots.sort((a, b) => b.complexity - a.complexity);
91
+ return {
92
+ totalFiles: files.length,
93
+ totalLines,
94
+ codeLines,
95
+ commentLines,
96
+ blankLines,
97
+ languages,
98
+ largestFiles: largestFiles.slice(0, 20),
99
+ complexityHotspots: complexityHotspots.slice(0, 10),
100
+ fileTypes,
101
+ avgFileSize: files.length > 0 ? Math.round(totalLines / files.length) : 0,
102
+ timestamp: new Date(),
103
+ };
104
+ }
105
+ walkDir(dir, depth = 0) {
106
+ if (depth > 6)
107
+ return [];
108
+ const files = [];
109
+ try {
110
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
111
+ for (const entry of entries) {
112
+ if (entry.name.startsWith('.') && entry.name !== '.env.example')
113
+ continue;
114
+ const fullPath = path.join(dir, entry.name);
115
+ if (entry.isDirectory()) {
116
+ if (IGNORE_DIRS.has(entry.name))
117
+ continue;
118
+ if (this.excludePaths.some(p => fullPath.includes(p)))
119
+ continue;
120
+ files.push(...this.walkDir(fullPath, depth + 1));
121
+ }
122
+ else if (entry.isFile()) {
123
+ // Skip binary files
124
+ const ext = path.extname(entry.name);
125
+ if (['.png', '.jpg', '.jpeg', '.gif', '.ico', '.svg', '.woff', '.woff2',
126
+ '.ttf', '.eot', '.mp3', '.mp4', '.zip', '.gz', '.tar', '.exe',
127
+ '.dll', '.so', '.dylib', '.pyc', '.class', '.o', '.obj'].includes(ext)) {
128
+ continue;
129
+ }
130
+ files.push(fullPath);
131
+ }
132
+ }
133
+ }
134
+ catch { /* permission error */ }
135
+ return files;
136
+ }
137
+ estimateComplexity(content) {
138
+ // Cyclomatic complexity estimation: count decision points
139
+ const decisionPatterns = [
140
+ /\bif\b/g, /\belse\b/g, /\bfor\b/g, /\bwhile\b/g,
141
+ /\bcase\b/g, /\bcatch\b/g, /&&/g, /\|\|/g, /\?\?/g,
142
+ /\?\./g, /\bawait\b/g,
143
+ ];
144
+ let complexity = 1;
145
+ for (const pattern of decisionPatterns) {
146
+ const matches = content.match(pattern);
147
+ if (matches)
148
+ complexity += matches.length;
149
+ }
150
+ return complexity;
151
+ }
152
+ countFunctions(content) {
153
+ const patterns = [
154
+ /function\s+\w+/g,
155
+ /const\s+\w+\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>/g,
156
+ /(?:async\s+)?\w+\s*\([^)]*\)\s*:\s*\w+/g,
157
+ /def\s+\w+/g,
158
+ /func\s+\w+/g,
159
+ /fn\s+\w+/g,
160
+ /public\s+\w+\s+\w+\s*\(/g,
161
+ /private\s+\w+\s+\w+\s*\(/g,
162
+ ];
163
+ let count = 0;
164
+ for (const pattern of patterns) {
165
+ const matches = content.match(pattern);
166
+ if (matches)
167
+ count += matches.length;
168
+ }
169
+ return count;
170
+ }
171
+ formatConsole(metrics) {
172
+ let out = `\n Code Metrics — ${metrics.totalFiles} files, ${metrics.totalLines.toLocaleString()} lines\n`;
173
+ out += ` ${'─'.repeat(55)}\n\n`;
174
+ out += ` Code: ${metrics.codeLines.toLocaleString().padStart(8)} lines\n`;
175
+ out += ` Comments: ${metrics.commentLines.toLocaleString().padStart(8)} lines\n`;
176
+ out += ` Blank: ${metrics.blankLines.toLocaleString().padStart(8)} lines\n`;
177
+ out += ` Avg/ file: ${metrics.avgFileSize.toLocaleString().padStart(8)} lines\n`;
178
+ out += `\n Languages:\n`;
179
+ const sortedLangs = Object.entries(metrics.languages)
180
+ .sort((a, b) => b[1].lines - a[1].lines)
181
+ .slice(0, 8);
182
+ for (const [lang, data] of sortedLangs) {
183
+ const bar = '█'.repeat(Math.round(data.percentage / 5)) + '░'.repeat(Math.max(0, 20 - Math.round(data.percentage / 5)));
184
+ out += ` ${lang.padEnd(12)} ${bar} ${data.percentage}% (${data.files} files)\n`;
185
+ }
186
+ if (metrics.largestFiles.length > 0) {
187
+ out += `\n Largest files:\n`;
188
+ for (const f of metrics.largestFiles.slice(0, 5)) {
189
+ out += ` ${f.lines.toLocaleString().padStart(6)} lines ${f.path}\n`;
190
+ }
191
+ }
192
+ if (metrics.complexityHotspots.length > 0) {
193
+ out += `\n Complexity hotspots (>${this.complexityThreshold}):\n`;
194
+ for (const f of metrics.complexityHotspots.slice(0, 5)) {
195
+ out += ` complexity ${String(f.complexity).padStart(4)} ${f.functions} functions ${f.path}\n`;
196
+ }
197
+ }
198
+ return out;
199
+ }
200
+ formatJSON(metrics) {
201
+ return JSON.stringify(metrics, null, 2);
202
+ }
203
+ toMarkdown(metrics) {
204
+ let md = `# Code Metrics\n\n`;
205
+ md += `| Metric | Value |\n|---|---|\n`;
206
+ md += `| Total files | ${metrics.totalFiles} |\n`;
207
+ md += `| Total lines | ${metrics.totalLines.toLocaleString()} |\n`;
208
+ md += `| Code lines | ${metrics.codeLines.toLocaleString()} |\n`;
209
+ md += `| Comment lines | ${metrics.commentLines.toLocaleString()} |\n`;
210
+ md += `| Avg file size | ${metrics.avgFileSize} lines |\n\n`;
211
+ md += `## Languages\n\n| Language | Files | Lines | % |\n|---|---|---|---|\n`;
212
+ for (const [lang, data] of Object.entries(metrics.languages).sort((a, b) => b[1].lines - a[1].lines).slice(0, 10)) {
213
+ md += `| ${lang} | ${data.files} | ${data.lines.toLocaleString()} | ${data.percentage}% |\n`;
214
+ }
215
+ if (metrics.complexityHotspots.length > 0) {
216
+ md += `\n## Complexity Hotspots\n\n| File | Complexity | Functions |\n|---|---|---|\n`;
217
+ for (const f of metrics.complexityHotspots) {
218
+ md += `| ${f.path} | ${f.complexity} | ${f.functions} |\n`;
219
+ }
220
+ }
221
+ return md;
222
+ }
223
+ }
224
+ //# sourceMappingURL=code-metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-metrics.js","sourceRoot":"","sources":["../../src/brain/code-metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { DuplicateGroup } from '../types.js';
2
+ export declare class CodeSimilarityDetector {
3
+ private projectDir;
4
+ constructor(projectDir: string);
5
+ /**
6
+ * Scan all source files for duplicate code blocks.
7
+ * Returns groups of blocks whose pairwise similarity >= minSimilarity.
8
+ */
9
+ detectDuplicates(minSimilarity?: number): Promise<DuplicateGroup[]>;
10
+ /**
11
+ * Walk the project tree, read each source file, and extract code blocks.
12
+ */
13
+ private collectAllBlocks;
14
+ /**
15
+ * Split a single file into code blocks by tracking brace depth.
16
+ * Recognises the block type (function, method, class, generic block).
17
+ * Only returns blocks with >= 6 lines.
18
+ */
19
+ private extractBlocks;
20
+ /**
21
+ * Compute Jaccard similarity between two code blocks.
22
+ * Tokenises content into word tokens, then calculates |intersection| / |union|.
23
+ */
24
+ private computeSimilarity;
25
+ /**
26
+ * Split content into individual word tokens and return as a Set.
27
+ * Strips punctuation and normalises to lowercase for comparison.
28
+ */
29
+ private tokenize;
30
+ /**
31
+ * Generate a refactoring suggestion based on the types of the duplicate blocks.
32
+ */
33
+ private suggestRefactor;
34
+ /**
35
+ * Walk a directory tree, returning full paths of source files.
36
+ */
37
+ private walkDir;
38
+ /**
39
+ * Produce a unique key for a block (file path + line range).
40
+ */
41
+ private blockKey;
42
+ }
43
+ //# sourceMappingURL=code-similarity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-similarity.d.ts","sourceRoot":"","sources":["../../src/brain/code-similarity.ts"],"names":[],"mappings":"AAIA,OAAO,EAAa,cAAc,EAAE,MAAM,aAAa,CAAC;AASxD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,EAAE,MAAM;IAI9B;;;OAGG;IACG,gBAAgB,CAAC,aAAa,GAAE,MAAY,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IA6C9E;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiBxB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAoErB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAShB;;OAEG;IACH,OAAO,CAAC,eAAe;IA6BvB;;OAEG;IACH,OAAO,CAAC,OAAO;IA2Bf;;OAEG;IACH,OAAO,CAAC,QAAQ;CAGjB"}
@@ -0,0 +1,227 @@
1
+ // src/brain/code-similarity.ts — Detect duplicate/near-duplicate code blocks across a project
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx']);
5
+ const IGNORE_DIRS = new Set([
6
+ 'node_modules', '.git', 'dist', 'build', 'out', 'coverage',
7
+ '.cache', '.next', '.nuxt', 'vendor', '__pycache__',
8
+ ]);
9
+ export class CodeSimilarityDetector {
10
+ constructor(projectDir) {
11
+ this.projectDir = projectDir;
12
+ }
13
+ /**
14
+ * Scan all source files for duplicate code blocks.
15
+ * Returns groups of blocks whose pairwise similarity >= minSimilarity.
16
+ */
17
+ async detectDuplicates(minSimilarity = 0.8) {
18
+ const allBlocks = this.collectAllBlocks();
19
+ const groups = [];
20
+ // Only consider blocks with 6+ lines
21
+ const eligible = allBlocks.filter(b => (b.endLine - b.startLine + 1) >= 6);
22
+ // Track which blocks have already been grouped to avoid duplicates
23
+ const assigned = new Set();
24
+ for (let i = 0; i < eligible.length; i++) {
25
+ const keyA = this.blockKey(eligible[i]);
26
+ if (assigned.has(keyA))
27
+ continue;
28
+ const similar = [eligible[i]];
29
+ for (let j = i + 1; j < eligible.length; j++) {
30
+ const keyB = this.blockKey(eligible[j]);
31
+ if (assigned.has(keyB))
32
+ continue;
33
+ // Skip self-comparison (same file + same line range)
34
+ if (keyA === keyB)
35
+ continue;
36
+ const sim = this.computeSimilarity(eligible[i], eligible[j]);
37
+ if (sim >= minSimilarity) {
38
+ similar.push(eligible[j]);
39
+ assigned.add(keyB);
40
+ }
41
+ }
42
+ if (similar.length > 1) {
43
+ assigned.add(keyA);
44
+ groups.push({
45
+ blocks: similar,
46
+ similarity: minSimilarity,
47
+ suggestedRefactor: this.suggestRefactor(similar),
48
+ });
49
+ }
50
+ }
51
+ return groups;
52
+ }
53
+ // ── Private Helpers ────────────────────────────────────────────────────────
54
+ /**
55
+ * Walk the project tree, read each source file, and extract code blocks.
56
+ */
57
+ collectAllBlocks() {
58
+ const files = this.walkDir(this.projectDir);
59
+ const blocks = [];
60
+ for (const filePath of files) {
61
+ try {
62
+ const content = fs.readFileSync(filePath, 'utf-8');
63
+ const extracted = this.extractBlocks(filePath, content);
64
+ blocks.push(...extracted);
65
+ }
66
+ catch {
67
+ // unreadable file — skip
68
+ }
69
+ }
70
+ return blocks;
71
+ }
72
+ /**
73
+ * Split a single file into code blocks by tracking brace depth.
74
+ * Recognises the block type (function, method, class, generic block).
75
+ * Only returns blocks with >= 6 lines.
76
+ */
77
+ extractBlocks(filePath, content) {
78
+ const blocks = [];
79
+ const lines = content.split('\n');
80
+ let depth = 0;
81
+ let blockStart = -1;
82
+ let blockType = 'block';
83
+ let pendingType = 'block';
84
+ for (let i = 0; i < lines.length; i++) {
85
+ const line = lines[i];
86
+ // Detect what kind of block is about to open
87
+ if (depth === 0) {
88
+ const trimmed = line.trim();
89
+ if (/\bclass\b/.test(trimmed) && /\{/.test(trimmed)) {
90
+ pendingType = 'class';
91
+ }
92
+ else if (/\b(function\b|=>\s*\{|async\s+function\b|\*\s*\w+\s*\()/.test(trimmed) &&
93
+ /\{/.test(trimmed)) {
94
+ pendingType = 'function';
95
+ }
96
+ else if (/^\s*(public|private|protected|static|async|get|set|readonly)\s.*\{/.test(trimmed) ||
97
+ /^\s*\*?\s*\w+\s*\([^)]*\)\s*(?::\s*\w[^{]*)?\{/.test(trimmed)) {
98
+ pendingType = 'method';
99
+ }
100
+ else if (/\{/.test(trimmed)) {
101
+ pendingType = 'block';
102
+ }
103
+ }
104
+ // Track brace depth
105
+ const opens = (line.match(/\{/g) || []).length;
106
+ const closes = (line.match(/\}/g) || []).length;
107
+ const prevDepth = depth;
108
+ depth += opens - closes;
109
+ if (opens > 0 && prevDepth === 0) {
110
+ // Entering a top-level block
111
+ blockStart = i;
112
+ blockType = pendingType;
113
+ }
114
+ if (prevDepth > 0 && depth === 0 && blockStart >= 0) {
115
+ // Exiting a block
116
+ const endLine = i;
117
+ const lineCount = endLine - blockStart + 1;
118
+ if (lineCount >= 6) {
119
+ blocks.push({
120
+ file: filePath,
121
+ startLine: blockStart + 1, // 1-based
122
+ endLine: endLine + 1,
123
+ content: lines.slice(blockStart, endLine + 1).join('\n'),
124
+ type: blockType,
125
+ });
126
+ }
127
+ blockStart = -1;
128
+ blockType = 'block';
129
+ }
130
+ }
131
+ return blocks;
132
+ }
133
+ /**
134
+ * Compute Jaccard similarity between two code blocks.
135
+ * Tokenises content into word tokens, then calculates |intersection| / |union|.
136
+ */
137
+ computeSimilarity(a, b) {
138
+ const tokensA = this.tokenize(a.content);
139
+ const tokensB = this.tokenize(b.content);
140
+ if (tokensA.size === 0 && tokensB.size === 0)
141
+ return 1.0;
142
+ if (tokensA.size === 0 || tokensB.size === 0)
143
+ return 0.0;
144
+ let intersectionSize = 0;
145
+ for (const token of tokensA) {
146
+ if (tokensB.has(token))
147
+ intersectionSize++;
148
+ }
149
+ const unionSize = tokensA.size + tokensB.size - intersectionSize;
150
+ return unionSize === 0 ? 0 : intersectionSize / unionSize;
151
+ }
152
+ /**
153
+ * Split content into individual word tokens and return as a Set.
154
+ * Strips punctuation and normalises to lowercase for comparison.
155
+ */
156
+ tokenize(content) {
157
+ const words = content
158
+ .replace(/[^\w\s]/g, ' ')
159
+ .split(/\s+/)
160
+ .filter(w => w.length > 0)
161
+ .map(w => w.toLowerCase());
162
+ return new Set(words);
163
+ }
164
+ /**
165
+ * Generate a refactoring suggestion based on the types of the duplicate blocks.
166
+ */
167
+ suggestRefactor(blocks) {
168
+ const types = new Set(blocks.map(b => b.type));
169
+ const files = new Set(blocks.map(b => b.file));
170
+ if (types.has('class')) {
171
+ return 'Extract a shared base class or compose common behaviour into a mixin/trait';
172
+ }
173
+ if (types.has('method')) {
174
+ if (files.size > 1) {
175
+ return 'Extract shared method logic into a utility module and import it where needed';
176
+ }
177
+ return 'Extract shared method logic into a private helper method within the same class';
178
+ }
179
+ if (types.has('function')) {
180
+ if (files.size > 1) {
181
+ return 'Extract shared logic into a utility function in a common module and import it where needed';
182
+ }
183
+ return 'Extract shared logic into a utility function within the same module';
184
+ }
185
+ // Generic block
186
+ if (files.size > 1) {
187
+ return 'Extract shared logic into a utility function in a shared module';
188
+ }
189
+ return 'Extract shared logic into a utility function to reduce duplication';
190
+ }
191
+ /**
192
+ * Walk a directory tree, returning full paths of source files.
193
+ */
194
+ walkDir(dir) {
195
+ const results = [];
196
+ try {
197
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
198
+ for (const entry of entries) {
199
+ if (entry.name.startsWith('.'))
200
+ continue;
201
+ const fullPath = path.join(dir, entry.name);
202
+ if (entry.isDirectory()) {
203
+ if (IGNORE_DIRS.has(entry.name))
204
+ continue;
205
+ results.push(...this.walkDir(fullPath));
206
+ }
207
+ else if (entry.isFile()) {
208
+ const ext = path.extname(entry.name);
209
+ if (SOURCE_EXTENSIONS.has(ext)) {
210
+ results.push(fullPath);
211
+ }
212
+ }
213
+ }
214
+ }
215
+ catch {
216
+ // permission or access error — skip
217
+ }
218
+ return results;
219
+ }
220
+ /**
221
+ * Produce a unique key for a block (file path + line range).
222
+ */
223
+ blockKey(block) {
224
+ return `${block.file}:${block.startLine}-${block.endLine}`;
225
+ }
226
+ }
227
+ //# sourceMappingURL=code-similarity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-similarity.js","sourceRoot":"","sources":["../../src/brain/code-similarity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { ProjectKnowledge, BrainInsight } from '../types.js';
2
+ export declare class ContextCompletionEngine {
3
+ private projectDir;
4
+ constructor(projectDir: string);
5
+ /**
6
+ * Analyze the project directory to build a comprehensive ProjectKnowledge
7
+ * object containing name, conventions, architecture, patterns, and deps.
8
+ */
9
+ buildKnowledge(): Promise<ProjectKnowledge>;
10
+ /**
11
+ * Persist the knowledge object to `.shadow-brain/knowledge.json` inside
12
+ * the project directory.
13
+ */
14
+ saveKnowledge(knowledge: ProjectKnowledge): Promise<void>;
15
+ /**
16
+ * Identify missing project context items (README, .gitignore, tsconfig,
17
+ * CI/CD configs, etc.) and return them as prioritised BrainInsight array.
18
+ */
19
+ getContextGaps(knowledge: ProjectKnowledge): Promise<BrainInsight[]>;
20
+ private detectProjectName;
21
+ private detectConventions;
22
+ private summarizeEslint;
23
+ private summarizePrettier;
24
+ private summarizeEditorConfig;
25
+ private summarizeTsconfig;
26
+ private detectArchitecture;
27
+ private hasFileExtensionSync;
28
+ private detectPatterns;
29
+ private detectDependencies;
30
+ private parseCargoDeps;
31
+ private hasFile;
32
+ private hasFileExtension;
33
+ /**
34
+ * Recursively collect source files up to a limit.
35
+ * Skips node_modules, .git, dist, build, coverage, and hidden directories.
36
+ */
37
+ private collectSourceFiles;
38
+ }
39
+ //# sourceMappingURL=context-completion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-completion.d.ts","sourceRoot":"","sources":["../../src/brain/context-completion.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAuDlE,qBAAa,uBAAuB;IAClC,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,EAAE,MAAM;IAM9B;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAoBjD;;;OAGG;IACG,aAAa,CAAC,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/D;;;OAGG;IACG,cAAc,CAAC,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;YAwM5D,iBAAiB;YAqBjB,iBAAiB;IA0E/B,OAAO,CAAC,eAAe;IAkCvB,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,qBAAqB;IAU7B,OAAO,CAAC,iBAAiB;YA6BX,kBAAkB;IA0GhC,OAAO,CAAC,oBAAoB;YAMd,cAAc;YAoId,kBAAkB;IAsChC,OAAO,CAAC,cAAc;YAyBR,OAAO;YAIP,gBAAgB;IA8B9B;;;OAGG;YACW,kBAAkB;CA8CjC"}