@theihtisham/agent-shadow-brain 2.1.0 → 3.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 (56) hide show
  1. package/dist/brain/accessibility-checker.d.ts +10 -0
  2. package/dist/brain/accessibility-checker.d.ts.map +1 -0
  3. package/dist/brain/accessibility-checker.js +379 -0
  4. package/dist/brain/accessibility-checker.js.map +1 -0
  5. package/dist/brain/api-contract-analyzer.d.ts +19 -0
  6. package/dist/brain/api-contract-analyzer.d.ts.map +1 -0
  7. package/dist/brain/api-contract-analyzer.js +251 -0
  8. package/dist/brain/api-contract-analyzer.js.map +1 -0
  9. package/dist/brain/ast-analyzer.d.ts +23 -0
  10. package/dist/brain/ast-analyzer.d.ts.map +1 -0
  11. package/dist/brain/ast-analyzer.js +462 -0
  12. package/dist/brain/ast-analyzer.js.map +1 -0
  13. package/dist/brain/code-age-analyzer.d.ts +11 -0
  14. package/dist/brain/code-age-analyzer.d.ts.map +1 -0
  15. package/dist/brain/code-age-analyzer.js +152 -0
  16. package/dist/brain/code-age-analyzer.js.map +1 -0
  17. package/dist/brain/config-drift-detector.d.ts +13 -0
  18. package/dist/brain/config-drift-detector.d.ts.map +1 -0
  19. package/dist/brain/config-drift-detector.js +198 -0
  20. package/dist/brain/config-drift-detector.js.map +1 -0
  21. package/dist/brain/dead-code-eliminator.d.ts +16 -0
  22. package/dist/brain/dead-code-eliminator.d.ts.map +1 -0
  23. package/dist/brain/dead-code-eliminator.js +359 -0
  24. package/dist/brain/dead-code-eliminator.js.map +1 -0
  25. package/dist/brain/env-analyzer.d.ts +13 -0
  26. package/dist/brain/env-analyzer.d.ts.map +1 -0
  27. package/dist/brain/env-analyzer.js +277 -0
  28. package/dist/brain/env-analyzer.js.map +1 -0
  29. package/dist/brain/i18n-detector.d.ts +12 -0
  30. package/dist/brain/i18n-detector.d.ts.map +1 -0
  31. package/dist/brain/i18n-detector.js +242 -0
  32. package/dist/brain/i18n-detector.js.map +1 -0
  33. package/dist/brain/license-compliance.d.ts +13 -0
  34. package/dist/brain/license-compliance.d.ts.map +1 -0
  35. package/dist/brain/license-compliance.js +213 -0
  36. package/dist/brain/license-compliance.js.map +1 -0
  37. package/dist/brain/llm-client.d.ts.map +1 -1
  38. package/dist/brain/llm-client.js +3 -0
  39. package/dist/brain/llm-client.js.map +1 -1
  40. package/dist/brain/mutation-advisor.d.ts +11 -0
  41. package/dist/brain/mutation-advisor.d.ts.map +1 -0
  42. package/dist/brain/mutation-advisor.js +154 -0
  43. package/dist/brain/mutation-advisor.js.map +1 -0
  44. package/dist/brain/orchestrator.d.ts +48 -1
  45. package/dist/brain/orchestrator.d.ts.map +1 -1
  46. package/dist/brain/orchestrator.js +178 -2
  47. package/dist/brain/orchestrator.js.map +1 -1
  48. package/dist/cli.js +408 -3
  49. package/dist/cli.js.map +1 -1
  50. package/dist/index.d.ts +11 -1
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +12 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/types.d.ts +151 -2
  55. package/dist/types.d.ts.map +1 -1
  56. package/package.json +2 -2
@@ -0,0 +1,13 @@
1
+ import { BrainInsight } from '../types.js';
2
+ export declare class EnvAnalyzer {
3
+ private projectDir;
4
+ constructor(projectDir: string);
5
+ analyzeProject(maxFiles?: number): Promise<BrainInsight[]>;
6
+ private analyzeEnvFiles;
7
+ private analyzeCodeFile;
8
+ private crossReferenceEnv;
9
+ private looksLikeSecret;
10
+ private issueToInsight;
11
+ private collectFiles;
12
+ }
13
+ //# sourceMappingURL=env-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-analyzer.d.ts","sourceRoot":"","sources":["../../src/brain/env-analyzer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAY,MAAM,aAAa,CAAC;AAQrD,qBAAa,WAAW;IACtB,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,EAAE,MAAM;IAIxB,cAAc,CAAC,QAAQ,GAAE,MAAY,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAwBrE,OAAO,CAAC,eAAe;IAiFvB,OAAO,CAAC,eAAe;IAiEvB,OAAO,CAAC,iBAAiB;IAkDzB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,YAAY;CAqBrB"}
@@ -0,0 +1,277 @@
1
+ // src/brain/env-analyzer.ts — Environment variable analysis
2
+ // v3.0.0 — Detects hardcoded secrets, missing validation, inconsistent naming, unused vars
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ const IGNORE_DIRS = new Set([
6
+ 'node_modules', '.git', 'dist', 'build', 'out', 'coverage', '.next', '.nuxt', '.cache',
7
+ ]);
8
+ export class EnvAnalyzer {
9
+ constructor(projectDir) {
10
+ this.projectDir = projectDir;
11
+ }
12
+ async analyzeProject(maxFiles = 200) {
13
+ const issues = [];
14
+ // Phase 1: Check .env files
15
+ issues.push(...this.analyzeEnvFiles());
16
+ // Phase 2: Check source code for env usage
17
+ const codeFiles = this.collectFiles(this.projectDir, maxFiles);
18
+ const envVars = new Set();
19
+ const codeIssues = [];
20
+ for (const filePath of codeFiles) {
21
+ const { vars, issues: fileIssues } = this.analyzeCodeFile(filePath);
22
+ for (const v of vars)
23
+ envVars.add(v);
24
+ codeIssues.push(...fileIssues);
25
+ }
26
+ issues.push(...codeIssues);
27
+ // Phase 3: Cross-reference .env.example with .env usage
28
+ issues.push(...this.crossReferenceEnv(envVars));
29
+ return issues.map(issue => this.issueToInsight(issue));
30
+ }
31
+ analyzeEnvFiles() {
32
+ const issues = [];
33
+ const envFiles = ['.env', '.env.local', '.env.development', '.env.production', '.env.test', '.env.example'];
34
+ const envVars = new Map();
35
+ for (const envFile of envFiles) {
36
+ const fullPath = path.join(this.projectDir, envFile);
37
+ let content;
38
+ try {
39
+ content = fs.readFileSync(fullPath, 'utf-8');
40
+ }
41
+ catch {
42
+ continue;
43
+ }
44
+ const lines = content.split('\n');
45
+ for (let i = 0; i < lines.length; i++) {
46
+ const line = lines[i].trim();
47
+ if (!line || line.startsWith('#'))
48
+ continue;
49
+ const match = line.match(/^(\w+)=(.*)$/);
50
+ if (!match)
51
+ continue;
52
+ const name = match[1];
53
+ const value = match[2].replace(/^["']|["']$/g, '');
54
+ envVars.set(name, { file: envFile, line: i + 1, value });
55
+ // Check for hardcoded secrets
56
+ if (this.looksLikeSecret(name, value) && envFile !== '.env.example') {
57
+ issues.push({
58
+ variable: name,
59
+ file: envFile,
60
+ line: i + 1,
61
+ type: 'hardcoded-secret',
62
+ severity: 'critical',
63
+ suggestion: `Move ${name} to a secret manager (Vault, AWS Secrets Manager) or use CI/CD secrets. Never commit real secrets.`,
64
+ });
65
+ }
66
+ // Check for missing docs
67
+ const prevLine = i > 0 ? lines[i - 1].trim() : '';
68
+ if (!prevLine.startsWith('#') && envFile === '.env.example') {
69
+ issues.push({
70
+ variable: name,
71
+ file: envFile,
72
+ line: i + 1,
73
+ type: 'missing-docs',
74
+ severity: 'low',
75
+ suggestion: `Add a comment above ${name} explaining its purpose, format, and default value.`,
76
+ });
77
+ }
78
+ }
79
+ }
80
+ // Check for inconsistent naming
81
+ const varNames = [...envVars.keys()];
82
+ const styles = new Map();
83
+ for (const name of varNames) {
84
+ let style;
85
+ if (/^[A-Z][A-Z0-9_]*$/.test(name))
86
+ style = 'UPPER_SNAKE';
87
+ else if (/^[a-z][a-z0-9_]*$/.test(name))
88
+ style = 'lower_snake';
89
+ else if (/^[a-z][a-zA-Z0-9]*$/.test(name))
90
+ style = 'camelCase';
91
+ else
92
+ style = 'mixed';
93
+ if (!styles.has(style))
94
+ styles.set(style, []);
95
+ styles.get(style).push(name);
96
+ }
97
+ if (styles.size > 1) {
98
+ const hasUpper = styles.has('UPPER_SNAKE');
99
+ const nonUpper = [...styles.entries()].filter(([s]) => s !== 'UPPER_SNAKE');
100
+ if (hasUpper && nonUpper.length > 0) {
101
+ issues.push({
102
+ variable: nonUpper[0][1][0],
103
+ file: '.env',
104
+ line: 0,
105
+ type: 'inconsistent-naming',
106
+ severity: 'medium',
107
+ suggestion: `Use UPPER_SNAKE_CASE consistently for env vars. Inconsistent: ${nonUpper.flatMap(([, v]) => v).slice(0, 5).join(', ')}`,
108
+ });
109
+ }
110
+ }
111
+ return issues;
112
+ }
113
+ analyzeCodeFile(filePath) {
114
+ let content;
115
+ try {
116
+ content = fs.readFileSync(filePath, 'utf-8');
117
+ }
118
+ catch {
119
+ return { vars: [], issues: [] };
120
+ }
121
+ const vars = [];
122
+ const issues = [];
123
+ const relPath = path.relative(this.projectDir, filePath);
124
+ const lines = content.split('\n');
125
+ for (let i = 0; i < lines.length; i++) {
126
+ const line = lines[i];
127
+ // Detect process.env.X usage
128
+ const envMatch = line.match(/process\.env\.(\w+)/g);
129
+ if (envMatch) {
130
+ for (const m of envMatch) {
131
+ const varName = m.replace('process.env.', '');
132
+ vars.push(varName);
133
+ // Check for missing default/fallback
134
+ const hasFallback = line.includes('??') || line.includes('||') || line.includes('=') && !line.includes('process.env.');
135
+ if (!hasFallback) {
136
+ // Check if there's a validation line nearby
137
+ const nearbyLines = lines.slice(Math.max(0, i - 3), Math.min(lines.length, i + 3)).join('\n');
138
+ const hasValidation = /z\.object|joi|validate|required|assert/.test(nearbyLines);
139
+ if (!hasValidation && !line.includes('typeof')) {
140
+ issues.push({
141
+ variable: varName,
142
+ file: relPath,
143
+ line: i + 1,
144
+ type: 'missing-default',
145
+ severity: 'high',
146
+ suggestion: `Provide a default value or runtime validation for ${varName}: process.env.${varName} ?? 'default'`,
147
+ });
148
+ }
149
+ }
150
+ }
151
+ }
152
+ // Detect hardcoded secrets in code (not process.env)
153
+ const secretPatterns = [
154
+ { regex: /(?:api[_-]?key|apikey|secret|token|password|passwd|pwd)\s*[:=]\s*["'][^"']{8,}["']/gi, type: 'hardcoded-secret' },
155
+ { regex: /(?:mongodb|postgres|mysql|redis):\/\/[^\s"']+/gi, type: 'hardcoded-secret' },
156
+ { regex: /Bearer\s+[A-Za-z0-9\-._~+/]+=*/gi, type: 'hardcoded-secret' },
157
+ ];
158
+ for (const { regex, type } of secretPatterns) {
159
+ regex.lastIndex = 0;
160
+ if (regex.test(line) && !line.includes('process.env') && !line.includes('getenv') && !line.trim().startsWith('//')) {
161
+ issues.push({
162
+ variable: 'HARDCODED_SECRET',
163
+ file: relPath,
164
+ line: i + 1,
165
+ type,
166
+ severity: 'critical',
167
+ suggestion: 'Never hardcode secrets in source code. Use environment variables or a secret manager.',
168
+ });
169
+ }
170
+ }
171
+ }
172
+ return { vars, issues };
173
+ }
174
+ crossReferenceEnv(usedVars) {
175
+ const issues = [];
176
+ // Check .env.example
177
+ const examplePath = path.join(this.projectDir, '.env.example');
178
+ let exampleVars;
179
+ try {
180
+ const content = fs.readFileSync(examplePath, 'utf-8');
181
+ exampleVars = new Set(content.split('\n')
182
+ .map(l => l.trim())
183
+ .filter(l => l && !l.startsWith('#'))
184
+ .map(l => l.split('=')[0])
185
+ .filter(Boolean));
186
+ }
187
+ catch {
188
+ exampleVars = new Set();
189
+ }
190
+ // Vars used in code but not in .env.example
191
+ for (const v of usedVars) {
192
+ if (!exampleVars.has(v)) {
193
+ issues.push({
194
+ variable: v,
195
+ file: '.env.example',
196
+ line: 0,
197
+ type: 'missing-default',
198
+ severity: 'medium',
199
+ suggestion: `Add ${v} to .env.example so developers know it's required.`,
200
+ });
201
+ }
202
+ }
203
+ // Vars in .env.example but not used in code
204
+ for (const v of exampleVars) {
205
+ if (!usedVars.has(v)) {
206
+ issues.push({
207
+ variable: v,
208
+ file: '.env.example',
209
+ line: 0,
210
+ type: 'unused',
211
+ severity: 'low',
212
+ suggestion: `${v} is in .env.example but not referenced in code. Consider removing it.`,
213
+ });
214
+ }
215
+ }
216
+ return issues;
217
+ }
218
+ looksLikeSecret(name, value) {
219
+ const secretNames = /secret|password|passwd|pwd|token|api[_-]?key|private[_-]?key|auth|credential/i;
220
+ if (!secretNames.test(name))
221
+ return false;
222
+ // Non-empty, non-placeholder values
223
+ if (!value || value === '' || value === 'changeme' || value === 'xxx' || value === 'your-key-here')
224
+ return false;
225
+ if (value.length < 8)
226
+ return false;
227
+ return true;
228
+ }
229
+ issueToInsight(issue) {
230
+ return {
231
+ type: 'env',
232
+ priority: issue.severity === 'critical' ? 'critical' : issue.severity === 'high' ? 'high' : issue.severity === 'medium' ? 'medium' : 'low',
233
+ title: `[env] ${issue.type}: ${issue.variable} in ${issue.file}${issue.line ? ':' + issue.line : ''}`,
234
+ content: `Environment variable issue in ${issue.file}${issue.line ? ':' + issue.line : ''}\n` +
235
+ ` Variable: ${issue.variable}\n` +
236
+ ` Type: ${issue.type}\n` +
237
+ ` Severity: ${issue.severity}\n` +
238
+ ` Fix: ${issue.suggestion}`,
239
+ files: [issue.file],
240
+ timestamp: new Date(),
241
+ confidence: issue.type === 'hardcoded-secret' ? 0.95 : 0.8,
242
+ metadata: { variable: issue.variable, envIssueType: issue.type },
243
+ };
244
+ }
245
+ collectFiles(dir, maxFiles) {
246
+ const results = [];
247
+ const walk = (currentDir, depth) => {
248
+ if (results.length >= maxFiles || depth > 10)
249
+ return;
250
+ let entries;
251
+ try {
252
+ entries = fs.readdirSync(currentDir, { withFileTypes: true });
253
+ }
254
+ catch {
255
+ return;
256
+ }
257
+ for (const entry of entries) {
258
+ if (results.length >= maxFiles)
259
+ return;
260
+ if (entry.name.startsWith('.'))
261
+ continue;
262
+ const fullPath = path.join(currentDir, entry.name);
263
+ if (entry.isDirectory()) {
264
+ if (IGNORE_DIRS.has(entry.name))
265
+ continue;
266
+ walk(fullPath, depth + 1);
267
+ }
268
+ else if (entry.isFile() && /\.(ts|tsx|js|jsx)$/.test(entry.name)) {
269
+ results.push(fullPath);
270
+ }
271
+ }
272
+ };
273
+ walk(dir, 0);
274
+ return results;
275
+ }
276
+ }
277
+ //# sourceMappingURL=env-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-analyzer.js","sourceRoot":"","sources":["../../src/brain/env-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { BrainInsight, I18nIssue } from '../types.js';
2
+ export declare class I18nDetector {
3
+ private projectDir;
4
+ constructor(projectDir: string);
5
+ analyzeProject(maxFiles?: number): Promise<BrainInsight[]>;
6
+ private detectI18nLibrary;
7
+ analyzeFile(filePath: string, hasI18n: boolean): I18nIssue[];
8
+ private isCodeNotText;
9
+ private issueToInsight;
10
+ private collectFiles;
11
+ }
12
+ //# sourceMappingURL=i18n-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n-detector.d.ts","sourceRoot":"","sources":["../../src/brain/i18n-detector.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAoDtD,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,EAAE,MAAM;IAIxB,cAAc,CAAC,QAAQ,GAAE,MAAY,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAerE,OAAO,CAAC,iBAAiB;IAgBzB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE;IAoH5D,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,YAAY;CAqBrB"}
@@ -0,0 +1,242 @@
1
+ // src/brain/i18n-detector.ts — Internationalization (i18n) readiness checker
2
+ // v3.0.0 — Detects hardcoded strings, date/number format issues, missing RTL support
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ const IGNORE_DIRS = new Set([
6
+ 'node_modules', '.git', 'dist', 'build', 'out', 'coverage', '.next', '.nuxt', '.cache',
7
+ '__tests__', '__test__', 'test', 'tests', 'spec',
8
+ ]);
9
+ const CODE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.vue', '.svelte']);
10
+ // Common English words that suggest hardcoded UI text
11
+ const UI_PATTERNS = [
12
+ // String literals in JSX/HTML attributes that look like user-facing text
13
+ /placeholder\s*=\s*["']([A-Z][^"']{3,})["']/g,
14
+ /title\s*=\s*["']([A-Z][^"']{3,})["']/g,
15
+ /label\s*=\s*["']([A-Z][^"']{3,})["']/g,
16
+ /aria-label\s*=\s*["']([A-Z][^"']{3,})["']/g,
17
+ /alt\s*=\s*["']([A-Z][^"']{3,})["']/g,
18
+ // Button text in JSX
19
+ />\s*([A-Z][a-z]+(\s+[A-Z]?[a-z]+){1,5})\s*</g,
20
+ // Error messages as string literals
21
+ /throw\s+new\s+\w+Error\s*\(\s*["']([A-Z][^"']{10,})["']/g,
22
+ // Alert/confirm messages
23
+ /\balert\s*\(\s*["']([A-Z][^"']{5,})["']/g,
24
+ /\bconfirm\s*\(\s*["']([A-Z][^"']{5,})["']/g,
25
+ // console.log with descriptive text (might be user-facing in some contexts)
26
+ /toast\s*\(\s*["']([A-Z][^"']{5,})["']/g,
27
+ /notification\s*\.\s*(success|error|warning|info)\s*\(\s*["']([A-Z][^"']{5,})["']/g,
28
+ ];
29
+ // Date format patterns that aren't i18n-aware
30
+ const DATE_PATTERNS = [
31
+ { regex: /\bnew\s+Date\(\s*\)\.to(Locale)?DateString\s*\(\s*\)/g, type: 'date-format' },
32
+ { regex: /\btoLocaleDateString\s*\(\s*["']en["']/g, type: 'date-format' },
33
+ { regex: /\bgetMonth\(\)\s*\+\s*1/g, type: 'date-format' },
34
+ { regex: /\bgetFullYear\(\)\s*-\s*\d{2}/g, type: 'date-format' },
35
+ ];
36
+ // Number format patterns
37
+ const NUMBER_PATTERNS = [
38
+ { regex: /\btoFixed\s*\(\s*\d+\s*\)/g, type: 'number-format' },
39
+ { regex: /\b\.toLocaleString\s*\(\s*\)/g, type: 'number-format' },
40
+ ];
41
+ // String concatenation with variables (likely needs interpolation)
42
+ const CONCAT_PATTERNS = [
43
+ /["'][A-Za-z\s]+\s*["']\s*\+\s*\w+/g,
44
+ /\w+\s*\+\s*["']\s+[A-Za-z\s]+["']/g,
45
+ /`[^`]*\$\{[^}]+\}[^`]*[A-Za-z]{3,}[^`]*`/g, // template literals with text
46
+ ];
47
+ export class I18nDetector {
48
+ constructor(projectDir) {
49
+ this.projectDir = projectDir;
50
+ }
51
+ async analyzeProject(maxFiles = 150) {
52
+ const files = this.collectFiles(this.projectDir, maxFiles);
53
+ const allIssues = [];
54
+ // Check if i18n library is already present
55
+ const hasI18n = this.detectI18nLibrary();
56
+ for (const filePath of files) {
57
+ const issues = this.analyzeFile(filePath, hasI18n);
58
+ allIssues.push(...issues);
59
+ }
60
+ return allIssues.map(issue => this.issueToInsight(issue, hasI18n));
61
+ }
62
+ detectI18nLibrary() {
63
+ const pkgPath = path.join(this.projectDir, 'package.json');
64
+ try {
65
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
66
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
67
+ return !!(allDeps['i18next'] || allDeps['react-i18next'] || allDeps['vue-i18n'] ||
68
+ allDeps['@angular/localize'] || allDeps['svelte-i18n'] || allDeps['next-intl'] ||
69
+ allDeps['next-i18next'] || allDeps['react-intl'] || allDeps['formatjs'] ||
70
+ allDeps['lingui'] || allDeps['@lingui/core']);
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ analyzeFile(filePath, hasI18n) {
77
+ let content;
78
+ try {
79
+ content = fs.readFileSync(filePath, 'utf-8');
80
+ }
81
+ catch {
82
+ return [];
83
+ }
84
+ const issues = [];
85
+ const lines = content.split('\n');
86
+ const relPath = path.relative(this.projectDir, filePath);
87
+ // Skip test files
88
+ if (relPath.includes('.test.') || relPath.includes('.spec.') || relPath.includes('__tests__')) {
89
+ return issues;
90
+ }
91
+ // Detect hardcoded UI strings
92
+ for (let i = 0; i < lines.length; i++) {
93
+ const line = lines[i];
94
+ const lineNum = i + 1;
95
+ // Check for UI text patterns
96
+ for (const pattern of UI_PATTERNS) {
97
+ pattern.lastIndex = 0;
98
+ const match = pattern.exec(line);
99
+ if (match) {
100
+ const text = match[1] || match[0];
101
+ // Skip if it looks like code, not text
102
+ if (this.isCodeNotText(text))
103
+ continue;
104
+ issues.push({
105
+ type: 'hardcoded-string',
106
+ file: relPath,
107
+ line: lineNum,
108
+ content: text.slice(0, 100),
109
+ suggestion: hasI18n
110
+ ? `Replace with i18n translation key: t('key')`
111
+ : `Extract to a translations file or use an i18n library`,
112
+ severity: 'medium',
113
+ });
114
+ }
115
+ }
116
+ // Check for string concatenation
117
+ for (const concatPattern of CONCAT_PATTERNS) {
118
+ concatPattern.lastIndex = 0;
119
+ if (concatPattern.test(line)) {
120
+ // Avoid duplicates
121
+ const existing = issues.find(iss => iss.line === lineNum && iss.type === 'concatenation');
122
+ if (!existing) {
123
+ issues.push({
124
+ type: 'concatenation',
125
+ file: relPath,
126
+ line: lineNum,
127
+ content: line.trim().slice(0, 100),
128
+ suggestion: 'Use ICU message format or interpolation for proper i18n: `{variable}` instead of string concatenation',
129
+ severity: 'high',
130
+ });
131
+ }
132
+ }
133
+ }
134
+ }
135
+ // Check date format issues
136
+ for (const { regex, type } of DATE_PATTERNS) {
137
+ regex.lastIndex = 0;
138
+ let match;
139
+ while ((match = regex.exec(content)) !== null) {
140
+ const line = content.substring(0, match.index).split('\n').length;
141
+ issues.push({
142
+ type,
143
+ file: relPath,
144
+ line,
145
+ content: match[0],
146
+ suggestion: 'Use Intl.DateTimeFormat with explicit locale or i18n library date formatting',
147
+ severity: 'low',
148
+ });
149
+ }
150
+ }
151
+ // Check number format issues
152
+ for (const { regex, type } of NUMBER_PATTERNS) {
153
+ regex.lastIndex = 0;
154
+ let match;
155
+ while ((match = regex.exec(content)) !== null) {
156
+ const line = content.substring(0, match.index).split('\n').length;
157
+ issues.push({
158
+ type,
159
+ file: relPath,
160
+ line,
161
+ content: match[0],
162
+ suggestion: 'Use Intl.NumberFormat with locale for proper number formatting (decimals, separators, currency)',
163
+ severity: 'low',
164
+ });
165
+ }
166
+ }
167
+ // Check for pluralization issues (hardcoded "s" for plural)
168
+ const pluralRegex = /\+\s*["']s["']\s*|\?\s*["']s["']\s*:\s*["']["']/g;
169
+ let pluralMatch;
170
+ while ((pluralMatch = pluralRegex.exec(content)) !== null) {
171
+ const line = content.substring(0, pluralMatch.index).split('\n').length;
172
+ issues.push({
173
+ type: 'pluralization',
174
+ file: relPath,
175
+ line,
176
+ content: pluralMatch[0],
177
+ suggestion: 'Use ICU plural format: `{count, plural, one {item} other {items}}` for proper pluralization across languages',
178
+ severity: 'medium',
179
+ });
180
+ }
181
+ return issues;
182
+ }
183
+ isCodeNotText(text) {
184
+ // Skip if it looks like code identifiers
185
+ if (/^[a-z_]+(\.[a-z_]+)*$/.test(text))
186
+ return true;
187
+ if (/^\d+$/.test(text))
188
+ return true;
189
+ if (/^(true|false|null|undefined|void|async|await|return|const|let|var)$/.test(text))
190
+ return true;
191
+ return false;
192
+ }
193
+ issueToInsight(issue, hasI18n) {
194
+ return {
195
+ type: 'i18n',
196
+ priority: issue.severity === 'high' ? 'high' : issue.severity === 'medium' ? 'medium' : 'low',
197
+ title: `[i18n] ${issue.type}: ${issue.content.slice(0, 60)}`,
198
+ content: `i18n issue in ${issue.file}:${issue.line}\n` +
199
+ ` Type: ${issue.type}\n` +
200
+ ` Content: ${issue.content}\n` +
201
+ ` Severity: ${issue.severity}\n` +
202
+ ` Fix: ${issue.suggestion}\n` +
203
+ (hasI18n ? '' : ' Note: No i18n library detected. Consider adding i18next, react-intl, or next-intl.'),
204
+ files: [issue.file],
205
+ timestamp: new Date(),
206
+ confidence: 0.85,
207
+ metadata: { i18nType: issue.type, hasI18nLibrary: hasI18n },
208
+ };
209
+ }
210
+ collectFiles(dir, maxFiles) {
211
+ const results = [];
212
+ const walk = (currentDir, depth) => {
213
+ if (results.length >= maxFiles || depth > 10)
214
+ return;
215
+ let entries;
216
+ try {
217
+ entries = fs.readdirSync(currentDir, { withFileTypes: true });
218
+ }
219
+ catch {
220
+ return;
221
+ }
222
+ for (const entry of entries) {
223
+ if (results.length >= maxFiles)
224
+ return;
225
+ if (entry.name.startsWith('.'))
226
+ continue;
227
+ const fullPath = path.join(currentDir, entry.name);
228
+ if (entry.isDirectory()) {
229
+ if (IGNORE_DIRS.has(entry.name))
230
+ continue;
231
+ walk(fullPath, depth + 1);
232
+ }
233
+ else if (entry.isFile() && CODE_EXTENSIONS.has(path.extname(entry.name))) {
234
+ results.push(fullPath);
235
+ }
236
+ }
237
+ };
238
+ walk(dir, 0);
239
+ return results;
240
+ }
241
+ }
242
+ //# sourceMappingURL=i18n-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n-detector.js","sourceRoot":"","sources":["../../src/brain/i18n-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { BrainInsight } from '../types.js';
2
+ export declare class LicenseCompliance {
3
+ private projectDir;
4
+ constructor(projectDir: string);
5
+ analyzeProject(): Promise<BrainInsight[]>;
6
+ private readPackageJson;
7
+ private getPackageLicense;
8
+ private detectConflicts;
9
+ private getProjectLicense;
10
+ private getRestrictedRecommendation;
11
+ private issueToInsight;
12
+ }
13
+ //# sourceMappingURL=license-compliance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license-compliance.d.ts","sourceRoot":"","sources":["../../src/brain/license-compliance.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAgB,MAAM,aAAa,CAAC;AA+BzD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,EAAE,MAAM;IAIxB,cAAc,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAuE/C,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,iBAAiB;IAyBzB,OAAO,CAAC,eAAe;IA8BvB,OAAO,CAAC,iBAAiB;IAoBzB,OAAO,CAAC,2BAA2B;IAenC,OAAO,CAAC,cAAc;CAkBvB"}