@barissozen/csns 0.6.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 (200) hide show
  1. package/.env.example +8 -0
  2. package/LICENSE +21 -0
  3. package/README.md +364 -0
  4. package/dist/agent/agent-runner.d.ts +48 -0
  5. package/dist/agent/agent-runner.d.ts.map +1 -0
  6. package/dist/agent/agent-runner.js +180 -0
  7. package/dist/agent/agent-runner.js.map +1 -0
  8. package/dist/agent/architect.d.ts +34 -0
  9. package/dist/agent/architect.d.ts.map +1 -0
  10. package/dist/agent/architect.js +156 -0
  11. package/dist/agent/architect.js.map +1 -0
  12. package/dist/agent/codebase-reader.d.ts +35 -0
  13. package/dist/agent/codebase-reader.d.ts.map +1 -0
  14. package/dist/agent/codebase-reader.js +305 -0
  15. package/dist/agent/codebase-reader.js.map +1 -0
  16. package/dist/agent/context-builder.d.ts +39 -0
  17. package/dist/agent/context-builder.d.ts.map +1 -0
  18. package/dist/agent/context-builder.js +163 -0
  19. package/dist/agent/context-builder.js.map +1 -0
  20. package/dist/agent/index.d.ts +14 -0
  21. package/dist/agent/index.d.ts.map +1 -0
  22. package/dist/agent/index.js +12 -0
  23. package/dist/agent/index.js.map +1 -0
  24. package/dist/agent/output-parser.d.ts +27 -0
  25. package/dist/agent/output-parser.d.ts.map +1 -0
  26. package/dist/agent/output-parser.js +154 -0
  27. package/dist/agent/output-parser.js.map +1 -0
  28. package/dist/agent/process-spawner.d.ts +56 -0
  29. package/dist/agent/process-spawner.d.ts.map +1 -0
  30. package/dist/agent/process-spawner.js +153 -0
  31. package/dist/agent/process-spawner.js.map +1 -0
  32. package/dist/agent/tracer/index.d.ts +8 -0
  33. package/dist/agent/tracer/index.d.ts.map +1 -0
  34. package/dist/agent/tracer/index.js +6 -0
  35. package/dist/agent/tracer/index.js.map +1 -0
  36. package/dist/agent/tracer/reverse-engineer.d.ts +113 -0
  37. package/dist/agent/tracer/reverse-engineer.d.ts.map +1 -0
  38. package/dist/agent/tracer/reverse-engineer.js +695 -0
  39. package/dist/agent/tracer/reverse-engineer.js.map +1 -0
  40. package/dist/agent/tracer/runtime-tracer.d.ts +61 -0
  41. package/dist/agent/tracer/runtime-tracer.d.ts.map +1 -0
  42. package/dist/agent/tracer/runtime-tracer.js +484 -0
  43. package/dist/agent/tracer/runtime-tracer.js.map +1 -0
  44. package/dist/agent/tracer/semantic-analyzer.d.ts +24 -0
  45. package/dist/agent/tracer/semantic-analyzer.d.ts.map +1 -0
  46. package/dist/agent/tracer/semantic-analyzer.js +132 -0
  47. package/dist/agent/tracer/semantic-analyzer.js.map +1 -0
  48. package/dist/agent/tracer/static-analyzer.d.ts +44 -0
  49. package/dist/agent/tracer/static-analyzer.d.ts.map +1 -0
  50. package/dist/agent/tracer/static-analyzer.js +453 -0
  51. package/dist/agent/tracer/static-analyzer.js.map +1 -0
  52. package/dist/agent/tracer/tracer-agent.d.ts +61 -0
  53. package/dist/agent/tracer/tracer-agent.d.ts.map +1 -0
  54. package/dist/agent/tracer/tracer-agent.js +252 -0
  55. package/dist/agent/tracer/tracer-agent.js.map +1 -0
  56. package/dist/bin/csns.d.ts +24 -0
  57. package/dist/bin/csns.d.ts.map +1 -0
  58. package/dist/bin/csns.js +389 -0
  59. package/dist/bin/csns.js.map +1 -0
  60. package/dist/bin/pc.d.ts +13 -0
  61. package/dist/bin/pc.d.ts.map +1 -0
  62. package/dist/bin/pc.js +212 -0
  63. package/dist/bin/pc.js.map +1 -0
  64. package/dist/brief/brief-collector.d.ts +42 -0
  65. package/dist/brief/brief-collector.d.ts.map +1 -0
  66. package/dist/brief/brief-collector.js +228 -0
  67. package/dist/brief/brief-collector.js.map +1 -0
  68. package/dist/brief/index.d.ts +3 -0
  69. package/dist/brief/index.d.ts.map +1 -0
  70. package/dist/brief/index.js +3 -0
  71. package/dist/brief/index.js.map +1 -0
  72. package/dist/brief/smart-brief.d.ts +52 -0
  73. package/dist/brief/smart-brief.d.ts.map +1 -0
  74. package/dist/brief/smart-brief.js +440 -0
  75. package/dist/brief/smart-brief.js.map +1 -0
  76. package/dist/calculator/calculator.d.ts +7 -0
  77. package/dist/calculator/calculator.d.ts.map +1 -0
  78. package/dist/calculator/calculator.js +18 -0
  79. package/dist/calculator/calculator.js.map +1 -0
  80. package/dist/calculator/index.d.ts +2 -0
  81. package/dist/calculator/index.d.ts.map +1 -0
  82. package/dist/calculator/index.js +2 -0
  83. package/dist/calculator/index.js.map +1 -0
  84. package/dist/i18n/en.d.ts +6 -0
  85. package/dist/i18n/en.d.ts.map +1 -0
  86. package/dist/i18n/en.js +136 -0
  87. package/dist/i18n/en.js.map +1 -0
  88. package/dist/i18n/index.d.ts +31 -0
  89. package/dist/i18n/index.d.ts.map +1 -0
  90. package/dist/i18n/index.js +44 -0
  91. package/dist/i18n/index.js.map +1 -0
  92. package/dist/i18n/tr.d.ts +6 -0
  93. package/dist/i18n/tr.d.ts.map +1 -0
  94. package/dist/i18n/tr.js +136 -0
  95. package/dist/i18n/tr.js.map +1 -0
  96. package/dist/i18n/types.d.ts +86 -0
  97. package/dist/i18n/types.d.ts.map +1 -0
  98. package/dist/i18n/types.js +9 -0
  99. package/dist/i18n/types.js.map +1 -0
  100. package/dist/index.d.ts +7 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +72 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/llm/anthropic-provider.d.ts +18 -0
  105. package/dist/llm/anthropic-provider.d.ts.map +1 -0
  106. package/dist/llm/anthropic-provider.js +55 -0
  107. package/dist/llm/anthropic-provider.js.map +1 -0
  108. package/dist/llm/factory.d.ts +21 -0
  109. package/dist/llm/factory.d.ts.map +1 -0
  110. package/dist/llm/factory.js +59 -0
  111. package/dist/llm/factory.js.map +1 -0
  112. package/dist/llm/index.d.ts +7 -0
  113. package/dist/llm/index.d.ts.map +1 -0
  114. package/dist/llm/index.js +5 -0
  115. package/dist/llm/index.js.map +1 -0
  116. package/dist/llm/ollama-provider.d.ts +20 -0
  117. package/dist/llm/ollama-provider.d.ts.map +1 -0
  118. package/dist/llm/ollama-provider.js +62 -0
  119. package/dist/llm/ollama-provider.js.map +1 -0
  120. package/dist/llm/openai-provider.d.ts +20 -0
  121. package/dist/llm/openai-provider.d.ts.map +1 -0
  122. package/dist/llm/openai-provider.js +65 -0
  123. package/dist/llm/openai-provider.js.map +1 -0
  124. package/dist/llm/resolve.d.ts +10 -0
  125. package/dist/llm/resolve.d.ts.map +1 -0
  126. package/dist/llm/resolve.js +21 -0
  127. package/dist/llm/resolve.js.map +1 -0
  128. package/dist/llm/types.d.ts +45 -0
  129. package/dist/llm/types.d.ts.map +1 -0
  130. package/dist/llm/types.js +11 -0
  131. package/dist/llm/types.js.map +1 -0
  132. package/dist/memory/index.d.ts +2 -0
  133. package/dist/memory/index.d.ts.map +1 -0
  134. package/dist/memory/index.js +2 -0
  135. package/dist/memory/index.js.map +1 -0
  136. package/dist/memory/memory-layer.d.ts +54 -0
  137. package/dist/memory/memory-layer.d.ts.map +1 -0
  138. package/dist/memory/memory-layer.js +297 -0
  139. package/dist/memory/memory-layer.js.map +1 -0
  140. package/dist/orchestrator/dependency-graph.d.ts +39 -0
  141. package/dist/orchestrator/dependency-graph.d.ts.map +1 -0
  142. package/dist/orchestrator/dependency-graph.js +134 -0
  143. package/dist/orchestrator/dependency-graph.js.map +1 -0
  144. package/dist/orchestrator/escalator.d.ts +42 -0
  145. package/dist/orchestrator/escalator.d.ts.map +1 -0
  146. package/dist/orchestrator/escalator.js +163 -0
  147. package/dist/orchestrator/escalator.js.map +1 -0
  148. package/dist/orchestrator/evaluator.d.ts +34 -0
  149. package/dist/orchestrator/evaluator.d.ts.map +1 -0
  150. package/dist/orchestrator/evaluator.js +335 -0
  151. package/dist/orchestrator/evaluator.js.map +1 -0
  152. package/dist/orchestrator/index.d.ts +9 -0
  153. package/dist/orchestrator/index.d.ts.map +1 -0
  154. package/dist/orchestrator/index.js +9 -0
  155. package/dist/orchestrator/index.js.map +1 -0
  156. package/dist/orchestrator/integration-evaluator.d.ts +59 -0
  157. package/dist/orchestrator/integration-evaluator.d.ts.map +1 -0
  158. package/dist/orchestrator/integration-evaluator.js +405 -0
  159. package/dist/orchestrator/integration-evaluator.js.map +1 -0
  160. package/dist/orchestrator/milestone-manager.d.ts +28 -0
  161. package/dist/orchestrator/milestone-manager.d.ts.map +1 -0
  162. package/dist/orchestrator/milestone-manager.js +208 -0
  163. package/dist/orchestrator/milestone-manager.js.map +1 -0
  164. package/dist/orchestrator/orchestrator.d.ts +35 -0
  165. package/dist/orchestrator/orchestrator.d.ts.map +1 -0
  166. package/dist/orchestrator/orchestrator.js +338 -0
  167. package/dist/orchestrator/orchestrator.js.map +1 -0
  168. package/dist/orchestrator/planner.d.ts +15 -0
  169. package/dist/orchestrator/planner.d.ts.map +1 -0
  170. package/dist/orchestrator/planner.js +87 -0
  171. package/dist/orchestrator/planner.js.map +1 -0
  172. package/dist/orchestrator/recovery.d.ts +45 -0
  173. package/dist/orchestrator/recovery.d.ts.map +1 -0
  174. package/dist/orchestrator/recovery.js +98 -0
  175. package/dist/orchestrator/recovery.js.map +1 -0
  176. package/dist/run-calculator-test.d.ts +11 -0
  177. package/dist/run-calculator-test.d.ts.map +1 -0
  178. package/dist/run-calculator-test.js +212 -0
  179. package/dist/run-calculator-test.js.map +1 -0
  180. package/dist/run-real-task.d.ts +14 -0
  181. package/dist/run-real-task.d.ts.map +1 -0
  182. package/dist/run-real-task.js +185 -0
  183. package/dist/run-real-task.js.map +1 -0
  184. package/dist/run-todo-test.d.ts +6 -0
  185. package/dist/run-todo-test.d.ts.map +1 -0
  186. package/dist/run-todo-test.js +149 -0
  187. package/dist/run-todo-test.js.map +1 -0
  188. package/dist/todo/index.d.ts +2 -0
  189. package/dist/todo/index.d.ts.map +1 -0
  190. package/dist/todo/index.js +2 -0
  191. package/dist/todo/index.js.map +1 -0
  192. package/dist/todo/server.d.ts +2 -0
  193. package/dist/todo/server.d.ts.map +1 -0
  194. package/dist/todo/server.js +32 -0
  195. package/dist/todo/server.js.map +1 -0
  196. package/dist/types/index.d.ts +412 -0
  197. package/dist/types/index.d.ts.map +1 -0
  198. package/dist/types/index.js +5 -0
  199. package/dist/types/index.js.map +1 -0
  200. package/package.json +100 -0
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Semantic Analyzer — LLM ile Wiring Mantık Kontrolü
3
+ *
4
+ * LLMProvider abstraction ile herhangi bir model kullanabilir.
5
+ */
6
+ import type { LLMProvider } from '../../llm/types.js';
7
+ import type { DependencyEdge, ExportNode, WiringIssue, SemanticInsight } from '../../types/index.js';
8
+ export declare class SemanticAnalyzer {
9
+ private provider;
10
+ constructor(provider?: LLMProvider | null);
11
+ /**
12
+ * Import graph + dosya özetlerini LLM'e gönder, semantic sorunları tespit et
13
+ */
14
+ analyze(edges: DependencyEdge[], exports: ExportNode[], fileSummaries: Map<string, string>, architecture?: string): Promise<SemanticInsight[]>;
15
+ /**
16
+ * Semantic insight'ları WiringIssue'lara dönüştür
17
+ */
18
+ toWiringIssues(insights: SemanticInsight[]): WiringIssue[];
19
+ private buildPrompt;
20
+ private parseResponse;
21
+ private mapCategory;
22
+ private generateSuggestion;
23
+ }
24
+ //# sourceMappingURL=semantic-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-analyzer.d.ts","sourceRoot":"","sources":["../../../src/agent/tracer/semantic-analyzer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EACV,WAAW,EACX,eAAe,EAChB,MAAM,sBAAsB,CAAC;AA0B9B,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAqB;gBAEzB,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI;IAIzC;;OAEG;IACG,OAAO,CACX,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,UAAU,EAAE,EACrB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,eAAe,EAAE,CAAC;IAqB7B;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,WAAW,EAAE;IAc1D,OAAO,CAAC,WAAW;IAyCnB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,kBAAkB;CAU3B"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Semantic Analyzer — LLM ile Wiring Mantık Kontrolü
3
+ *
4
+ * LLMProvider abstraction ile herhangi bir model kullanabilir.
5
+ */
6
+ const SEMANTIC_SYSTEM_PROMPT = `You are an experienced software architect. Your task is to identify wiring issues in a TypeScript project.
7
+
8
+ You will receive:
9
+ 1. Import/export graph — which file imports what
10
+ 2. File summaries — what each file does
11
+ 3. Architecture decisions — how the project is structured
12
+
13
+ Detect:
14
+ - **injection-missing**: A service/handler needs another service but it's not injected
15
+ - **config-mismatch**: Env variable or config value used but undefined or type mismatch
16
+ - **interface-drift**: Contract mismatch between two modules (parameter types, return types)
17
+ - **handler-gap**: Route defined but handler not connected, or missing link in middleware chain
18
+ - **data-flow-break**: Data should flow A→B→C but B→C connection is broken
19
+
20
+ OUTPUT: JSON array only, each element:
21
+ {
22
+ "category": "injection-missing|config-mismatch|interface-drift|handler-gap|data-flow-break",
23
+ "description": "Human-readable description",
24
+ "files": ["file1.ts", "file2.ts"],
25
+ "confidence": 0.0-1.0
26
+ }
27
+
28
+ Mark uncertain findings with low confidence. Stay silent rather than produce false positives.`;
29
+ export class SemanticAnalyzer {
30
+ provider;
31
+ constructor(provider) {
32
+ this.provider = provider ?? null;
33
+ }
34
+ /**
35
+ * Import graph + dosya özetlerini LLM'e gönder, semantic sorunları tespit et
36
+ */
37
+ async analyze(edges, exports, fileSummaries, architecture) {
38
+ if (!this.provider) {
39
+ return []; // No LLM provider, skip
40
+ }
41
+ const prompt = this.buildPrompt(edges, exports, fileSummaries, architecture);
42
+ try {
43
+ const response = await this.provider.chat([{ role: 'user', content: prompt }], { system: SEMANTIC_SYSTEM_PROMPT, maxTokens: 4096 });
44
+ return this.parseResponse(response.text);
45
+ }
46
+ catch (error) {
47
+ const msg = error instanceof Error ? error.message : 'Unknown error';
48
+ console.warn(`⚠️ Semantic analysis failed: ${msg}`);
49
+ return [];
50
+ }
51
+ }
52
+ /**
53
+ * Semantic insight'ları WiringIssue'lara dönüştür
54
+ */
55
+ toWiringIssues(insights) {
56
+ return insights
57
+ .filter(i => i.confidence >= 0.5) // düşük güvenli olanları filtrele
58
+ .map(insight => ({
59
+ type: this.mapCategory(insight.category),
60
+ severity: insight.confidence >= 0.8 ? 'warning' : 'info',
61
+ file: insight.files[0] ?? 'unknown',
62
+ detail: `[LLM %.0f%%] ${insight.description}`.replace('%.0f', String(Math.round(insight.confidence * 100))),
63
+ suggestion: this.generateSuggestion(insight),
64
+ }));
65
+ }
66
+ // ── Private ────────────────────────────────────────────────
67
+ buildPrompt(edges, exports, fileSummaries, architecture) {
68
+ const parts = [];
69
+ // Graph özeti
70
+ parts.push('## Import/Export Grafiği\n');
71
+ for (const edge of edges.slice(0, 100)) { // max 100 edge
72
+ parts.push(`${edge.source} → ${edge.target} [${edge.symbols.join(', ')}]`);
73
+ }
74
+ // Export listesi
75
+ parts.push('\n## Dosya Export\'ları\n');
76
+ const byFile = new Map();
77
+ for (const exp of exports) {
78
+ if (!byFile.has(exp.file))
79
+ byFile.set(exp.file, []);
80
+ byFile.get(exp.file).push(exp);
81
+ }
82
+ for (const [file, exps] of byFile) {
83
+ parts.push(`**${file}**: ${exps.map(e => `${e.symbol}(${e.kind})`).join(', ')}`);
84
+ }
85
+ // Dosya özetleri
86
+ parts.push('\n## Dosya İçerik Özetleri\n');
87
+ for (const [file, summary] of fileSummaries) {
88
+ parts.push(`### ${file}\n${summary.slice(0, 500)}\n`);
89
+ }
90
+ // Mimari
91
+ if (architecture) {
92
+ parts.push(`\n## Mimari Kararlar\n${architecture.slice(0, 1500)}\n`);
93
+ }
94
+ parts.push('\n---\nBu projedeki wiring sorunlarını JSON array olarak raporla.');
95
+ return parts.join('\n');
96
+ }
97
+ parseResponse(text) {
98
+ // JSON array çıkar
99
+ const jsonMatch = text.match(/\[[\s\S]*\]/);
100
+ if (!jsonMatch)
101
+ return [];
102
+ try {
103
+ const parsed = JSON.parse(jsonMatch[0]);
104
+ return parsed.filter(item => item.category && item.description && Array.isArray(item.files) &&
105
+ typeof item.confidence === 'number');
106
+ }
107
+ catch {
108
+ return [];
109
+ }
110
+ }
111
+ mapCategory(category) {
112
+ const map = {
113
+ 'injection-missing': 'missing-import',
114
+ 'config-mismatch': 'type-mismatch',
115
+ 'interface-drift': 'type-mismatch',
116
+ 'handler-gap': 'missing-import',
117
+ 'data-flow-break': 'runtime-gap',
118
+ };
119
+ return map[category];
120
+ }
121
+ generateSuggestion(insight) {
122
+ const map = {
123
+ 'injection-missing': 'Inject the missing service via constructor or factory',
124
+ 'config-mismatch': 'Check config/env values, compare with .env.example',
125
+ 'interface-drift': 'Define a shared interface and ensure both sides implement it',
126
+ 'handler-gap': 'Check route definition and handler binding, verify middleware chain',
127
+ 'data-flow-break': 'Find the broken point in data flow, add missing intermediate layer',
128
+ };
129
+ return map[insight.category];
130
+ }
131
+ }
132
+ //# sourceMappingURL=semantic-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-analyzer.js","sourceRoot":"","sources":["../../../src/agent/tracer/semantic-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Static Analyzer — Import/Export Graph + Dead Code + Circular Dep Tespiti
3
+ *
4
+ * AST-free, regex tabanlı hızlı analiz.
5
+ * Tüm .ts/.tsx dosyalarını tarar, import/export grafiği çıkarır.
6
+ * Kullanılmayan export'ları, kırık import'ları, döngüsel bağımlılıkları tespit eder.
7
+ */
8
+ import type { ImportEdge, ExportNode, DependencyEdge, WiringIssue } from '../../types/index.js';
9
+ export declare class StaticAnalyzer {
10
+ private projectRoot;
11
+ constructor(projectRoot: string);
12
+ /**
13
+ * Tüm kaynak dosyaları tara, import/export grafiğini çıkar
14
+ */
15
+ buildGraph(): Promise<{
16
+ imports: ImportEdge[];
17
+ exports: ExportNode[];
18
+ edges: DependencyEdge[];
19
+ files: string[];
20
+ }>;
21
+ /**
22
+ * Static wiring sorunlarını tespit et
23
+ */
24
+ findIssues(): Promise<WiringIssue[]>;
25
+ private extractImports;
26
+ private extractExports;
27
+ private buildEdges;
28
+ private findDeadExports;
29
+ private findMissingImports;
30
+ private findCircularDeps;
31
+ private findPhantomDeps;
32
+ private collectSourceFiles;
33
+ private walk;
34
+ /**
35
+ * Relative import'u dosya yoluna çözümle.
36
+ * './foo.js' → 'src/foo.ts' (TypeScript .js → .ts mapping dahil)
37
+ */
38
+ private resolveImportPath;
39
+ private isEntryPoint;
40
+ private isNodeBuiltin;
41
+ private findLineNumber;
42
+ private inferExportKind;
43
+ }
44
+ //# sourceMappingURL=static-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-analyzer.d.ts","sourceRoot":"","sources":["../../../src/agent/tracer/static-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACZ,MAAM,sBAAsB,CAAC;AA+B9B,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,EAAE,MAAM;IAM/B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC;QAC1B,OAAO,EAAE,UAAU,EAAE,CAAC;QACtB,OAAO,EAAE,UAAU,EAAE,CAAC;QACtB,KAAK,EAAE,cAAc,EAAE,CAAC;QACxB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IAkBF;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAqB1C,OAAO,CAAC,cAAc;IAyDtB,OAAO,CAAC,cAAc;IAgDtB,OAAO,CAAC,UAAU;IA8BlB,OAAO,CAAC,eAAe;IA2DvB,OAAO,CAAC,kBAAkB;IAwB1B,OAAO,CAAC,gBAAgB;YAkDV,eAAe;YA+Df,kBAAkB;YAMlB,IAAI;IAmBlB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,eAAe;CAQxB"}
@@ -0,0 +1,453 @@
1
+ /**
2
+ * Static Analyzer — Import/Export Graph + Dead Code + Circular Dep Tespiti
3
+ *
4
+ * AST-free, regex tabanlı hızlı analiz.
5
+ * Tüm .ts/.tsx dosyalarını tarar, import/export grafiği çıkarır.
6
+ * Kullanılmayan export'ları, kırık import'ları, döngüsel bağımlılıkları tespit eder.
7
+ */
8
+ import { readFile, readdir } from 'node:fs/promises';
9
+ import { join, relative, dirname, extname } from 'node:path';
10
+ const SOURCE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs']);
11
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.next']);
12
+ // ── Regex Patterns ───────────────────────────────────────────
13
+ /** import { X, Y } from './path' */
14
+ const NAMED_IMPORT = /import\s+(?:type\s+)?{([^}]+)}\s+from\s+['"]([^'"]+)['"]/g;
15
+ /** import X from './path' */
16
+ const DEFAULT_IMPORT = /import\s+(?:type\s+)?(\w+)\s+from\s+['"]([^'"]+)['"]/g;
17
+ /** import * as X from './path' */
18
+ const STAR_IMPORT = /import\s+\*\s+as\s+(\w+)\s+from\s+['"]([^'"]+)['"]/g;
19
+ /** export { X, Y } from './path' (re-export) */
20
+ const RE_EXPORT = /export\s+(?:type\s+)?{([^}]+)}\s+from\s+['"]([^'"]+)['"]/g;
21
+ /** export default class/function/const X */
22
+ const EXPORT_DEFAULT = /export\s+default\s+(?:class|function|const|abstract\s+class)\s+(\w+)/g;
23
+ /** export class/function/const/type/interface/enum X */
24
+ const EXPORT_NAMED = /export\s+(?:declare\s+)?(?:abstract\s+)?(?:class|function|const|let|var|type|interface|enum)\s+(\w+)/g;
25
+ /** export default (anonymous) */
26
+ const EXPORT_DEFAULT_ANON = /export\s+default\s+(?!class|function|const|abstract)/g;
27
+ /** import type { X } from ... (TypeScript) */
28
+ const TYPE_IMPORT = /import\s+type\s+/;
29
+ export class StaticAnalyzer {
30
+ projectRoot;
31
+ constructor(projectRoot) {
32
+ this.projectRoot = projectRoot;
33
+ }
34
+ // ── Public API ─────────────────────────────────────────────
35
+ /**
36
+ * Tüm kaynak dosyaları tara, import/export grafiğini çıkar
37
+ */
38
+ async buildGraph() {
39
+ const files = await this.collectSourceFiles();
40
+ const allImports = [];
41
+ const allExports = [];
42
+ for (const file of files) {
43
+ const content = await readFile(join(this.projectRoot, file), 'utf-8');
44
+ const imports = this.extractImports(file, content);
45
+ const exports = this.extractExports(file, content);
46
+ allImports.push(...imports);
47
+ allExports.push(...exports);
48
+ }
49
+ const edges = this.buildEdges(allImports, files);
50
+ return { imports: allImports, exports: allExports, edges, files };
51
+ }
52
+ /**
53
+ * Static wiring sorunlarını tespit et
54
+ */
55
+ async findIssues() {
56
+ const { imports, exports, edges, files } = await this.buildGraph();
57
+ const issues = [];
58
+ // 1. Dead exports — hiçbir yerde import edilmeyen export'lar
59
+ issues.push(...this.findDeadExports(exports, imports, files));
60
+ // 2. Missing imports — resolve edilemeyen import'lar
61
+ issues.push(...this.findMissingImports(imports, files));
62
+ // 3. Circular dependencies
63
+ issues.push(...this.findCircularDeps(edges));
64
+ // 4. Phantom dependencies — package.json'da olmayan import'lar
65
+ issues.push(...await this.findPhantomDeps(imports));
66
+ return issues;
67
+ }
68
+ // ── Import Extraction ──────────────────────────────────────
69
+ extractImports(file, content) {
70
+ const imports = [];
71
+ const lines = content.split('\n');
72
+ // Named imports: import { X, Y } from './path'
73
+ for (const match of content.matchAll(NAMED_IMPORT)) {
74
+ const symbols = match[1].split(',').map(s => {
75
+ const parts = s.trim().split(/\s+as\s+/);
76
+ return parts[0].trim();
77
+ }).filter(s => s.length > 0);
78
+ const line = this.findLineNumber(lines, match.index);
79
+ const isTypeOnly = TYPE_IMPORT.test(match[0]);
80
+ imports.push({
81
+ from: file,
82
+ to: match[2],
83
+ symbols,
84
+ isTypeOnly,
85
+ line,
86
+ });
87
+ }
88
+ // Default imports: import X from './path'
89
+ for (const match of content.matchAll(DEFAULT_IMPORT)) {
90
+ // Named import regex ile overlap kontrolü
91
+ if (match[0].includes('{'))
92
+ continue;
93
+ const line = this.findLineNumber(lines, match.index);
94
+ const isTypeOnly = TYPE_IMPORT.test(match[0]);
95
+ imports.push({
96
+ from: file,
97
+ to: match[2],
98
+ symbols: ['default'],
99
+ isTypeOnly,
100
+ line,
101
+ });
102
+ }
103
+ // Star imports: import * as X from './path'
104
+ for (const match of content.matchAll(STAR_IMPORT)) {
105
+ const line = this.findLineNumber(lines, match.index);
106
+ imports.push({
107
+ from: file,
108
+ to: match[2],
109
+ symbols: ['*'],
110
+ isTypeOnly: false,
111
+ line,
112
+ });
113
+ }
114
+ return imports;
115
+ }
116
+ // ── Export Extraction ──────────────────────────────────────
117
+ extractExports(file, content) {
118
+ const exports = [];
119
+ const lines = content.split('\n');
120
+ const seen = new Set();
121
+ // Re-exports: export { X } from './path'
122
+ for (const match of content.matchAll(RE_EXPORT)) {
123
+ const symbols = match[1].split(',').map(s => s.trim().split(/\s+as\s+/).pop().trim());
124
+ for (const sym of symbols) {
125
+ if (sym && !seen.has(sym)) {
126
+ seen.add(sym);
127
+ exports.push({ file, symbol: sym, kind: 're-export', line: this.findLineNumber(lines, match.index) });
128
+ }
129
+ }
130
+ }
131
+ // Named exports: export class/function/const/type/interface/enum X
132
+ for (const match of content.matchAll(EXPORT_NAMED)) {
133
+ const sym = match[1];
134
+ if (!seen.has(sym)) {
135
+ seen.add(sym);
136
+ const kind = this.inferExportKind(match[0]);
137
+ exports.push({ file, symbol: sym, kind, line: this.findLineNumber(lines, match.index) });
138
+ }
139
+ }
140
+ // Default exports: export default class X
141
+ for (const match of content.matchAll(EXPORT_DEFAULT)) {
142
+ const sym = match[1];
143
+ if (!seen.has(sym)) {
144
+ seen.add(sym);
145
+ exports.push({ file, symbol: sym, kind: 'default', line: this.findLineNumber(lines, match.index) });
146
+ }
147
+ }
148
+ // Anonymous default exports
149
+ for (const match of content.matchAll(EXPORT_DEFAULT_ANON)) {
150
+ if (!seen.has('default')) {
151
+ seen.add('default');
152
+ exports.push({ file, symbol: 'default', kind: 'default', line: this.findLineNumber(lines, match.index) });
153
+ }
154
+ }
155
+ return exports;
156
+ }
157
+ // ── Edge Building ──────────────────────────────────────────
158
+ buildEdges(imports, files) {
159
+ const edgeMap = new Map();
160
+ const fileSet = new Set(files);
161
+ for (const imp of imports) {
162
+ const resolved = this.resolveImportPath(imp.from, imp.to, fileSet);
163
+ if (!resolved)
164
+ continue; // external package
165
+ const key = `${imp.from}→${resolved}`;
166
+ const existing = edgeMap.get(key);
167
+ if (existing) {
168
+ existing.weight++;
169
+ for (const s of imp.symbols) {
170
+ if (!existing.symbols.includes(s))
171
+ existing.symbols.push(s);
172
+ }
173
+ }
174
+ else {
175
+ edgeMap.set(key, {
176
+ source: imp.from,
177
+ target: resolved,
178
+ symbols: [...imp.symbols],
179
+ weight: 1,
180
+ });
181
+ }
182
+ }
183
+ return [...edgeMap.values()];
184
+ }
185
+ // ── Issue Detection ────────────────────────────────────────
186
+ findDeadExports(exports, imports, files) {
187
+ const issues = [];
188
+ const fileSet = new Set(files);
189
+ // Tüm import edilen symbol'leri topla (dosya bazlı)
190
+ const importedSymbols = new Map(); // file → symbols
191
+ for (const imp of imports) {
192
+ const resolved = this.resolveImportPath(imp.from, imp.to, fileSet);
193
+ if (!resolved)
194
+ continue;
195
+ if (!importedSymbols.has(resolved)) {
196
+ importedSymbols.set(resolved, new Set());
197
+ }
198
+ for (const sym of imp.symbols) {
199
+ importedSymbols.get(resolved).add(sym);
200
+ // Star import → tüm export'ları kullanılmış say
201
+ if (sym === '*') {
202
+ importedSymbols.get(resolved).add('*');
203
+ }
204
+ }
205
+ }
206
+ for (const exp of exports) {
207
+ // Entry point dosyalarını atla (index.ts, bin/*, main)
208
+ if (this.isEntryPoint(exp.file))
209
+ continue;
210
+ // Type-only export'ları atla (type/interface)
211
+ if (exp.kind === 'type' || exp.kind === 'interface')
212
+ continue;
213
+ const usedSymbols = importedSymbols.get(exp.file);
214
+ if (!usedSymbols) {
215
+ // Hiçbir dosya bu dosyayı import etmiyor
216
+ issues.push({
217
+ type: 'dead-export',
218
+ severity: 'warning',
219
+ file: exp.file,
220
+ symbol: exp.symbol,
221
+ detail: `Export '${exp.symbol}' hiçbir yerde kullanılmıyor (${exp.file}:${exp.line})`,
222
+ suggestion: `Kullanılmıyorsa kaldır veya export'u internal yap`,
223
+ });
224
+ }
225
+ else if (!usedSymbols.has(exp.symbol) && !usedSymbols.has('default') && !usedSymbols.has('*')) {
226
+ issues.push({
227
+ type: 'dead-export',
228
+ severity: 'info',
229
+ file: exp.file,
230
+ symbol: exp.symbol,
231
+ detail: `Export '${exp.symbol}' import ediliyor ama bu symbol kullanılmıyor (${exp.file}:${exp.line})`,
232
+ suggestion: `Import listesinden ve export'tan kaldırılabilir`,
233
+ });
234
+ }
235
+ }
236
+ return issues;
237
+ }
238
+ findMissingImports(imports, files) {
239
+ const issues = [];
240
+ const fileSet = new Set(files);
241
+ for (const imp of imports) {
242
+ // Sadece relative import'ları kontrol et
243
+ if (!imp.to.startsWith('.'))
244
+ continue;
245
+ const resolved = this.resolveImportPath(imp.from, imp.to, fileSet);
246
+ if (!resolved) {
247
+ issues.push({
248
+ type: 'missing-import',
249
+ severity: 'critical',
250
+ file: imp.from,
251
+ symbol: imp.symbols.join(', '),
252
+ detail: `Import çözümlenemedi: '${imp.to}' (${imp.from}:${imp.line})`,
253
+ suggestion: `Dosya mevcut mu? Yol doğru mu? Extension .js ekli mi?`,
254
+ });
255
+ }
256
+ }
257
+ return issues;
258
+ }
259
+ findCircularDeps(edges) {
260
+ const issues = [];
261
+ const adjList = new Map();
262
+ for (const edge of edges) {
263
+ if (!adjList.has(edge.source))
264
+ adjList.set(edge.source, []);
265
+ adjList.get(edge.source).push(edge.target);
266
+ }
267
+ const visited = new Set();
268
+ const inStack = new Set();
269
+ const path = [];
270
+ const dfs = (node) => {
271
+ if (inStack.has(node)) {
272
+ // Döngü bulundu — path'ten cycle'ı çıkar
273
+ const cycleStart = path.indexOf(node);
274
+ const cycle = path.slice(cycleStart);
275
+ cycle.push(node);
276
+ issues.push({
277
+ type: 'circular-dep',
278
+ severity: 'warning',
279
+ file: node,
280
+ detail: `Döngüsel bağımlılık: ${cycle.join(' → ')}`,
281
+ suggestion: `Bağımlılık yönünü değiştir veya ortak bir interface modülüne çıkar`,
282
+ });
283
+ return;
284
+ }
285
+ if (visited.has(node))
286
+ return;
287
+ visited.add(node);
288
+ inStack.add(node);
289
+ path.push(node);
290
+ for (const neighbor of adjList.get(node) ?? []) {
291
+ dfs(neighbor);
292
+ }
293
+ path.pop();
294
+ inStack.delete(node);
295
+ };
296
+ for (const node of adjList.keys()) {
297
+ dfs(node);
298
+ }
299
+ return issues;
300
+ }
301
+ async findPhantomDeps(imports) {
302
+ const issues = [];
303
+ // package.json oku
304
+ let pkgDeps;
305
+ try {
306
+ const pkg = JSON.parse(await readFile(join(this.projectRoot, 'package.json'), 'utf-8'));
307
+ pkgDeps = new Set([
308
+ ...Object.keys(pkg.dependencies ?? {}),
309
+ ...Object.keys(pkg.devDependencies ?? {}),
310
+ ...Object.keys(pkg.peerDependencies ?? {}),
311
+ ]);
312
+ }
313
+ catch {
314
+ return issues; // package.json yoksa kontrol etme
315
+ }
316
+ // External import'ları topla
317
+ const externalImports = new Set();
318
+ for (const imp of imports) {
319
+ if (imp.to.startsWith('.') || imp.to.startsWith('node:'))
320
+ continue;
321
+ // Scoped package: @scope/name → @scope/name
322
+ const pkgName = imp.to.startsWith('@')
323
+ ? imp.to.split('/').slice(0, 2).join('/')
324
+ : imp.to.split('/')[0];
325
+ externalImports.add(pkgName);
326
+ }
327
+ for (const pkg of externalImports) {
328
+ // Node built-in modüllerini atla
329
+ if (this.isNodeBuiltin(pkg))
330
+ continue;
331
+ if (!pkgDeps.has(pkg)) {
332
+ issues.push({
333
+ type: 'phantom-dep',
334
+ severity: 'critical',
335
+ file: 'package.json',
336
+ symbol: pkg,
337
+ detail: `'${pkg}' import ediliyor ama package.json'da dependency olarak tanımlı değil`,
338
+ suggestion: `npm install ${pkg} veya import'u kaldır`,
339
+ });
340
+ }
341
+ }
342
+ // Kullanılmayan dependency'ler (ters yön)
343
+ for (const dep of pkgDeps) {
344
+ if (dep.startsWith('@types/'))
345
+ continue; // type packages
346
+ if (!externalImports.has(dep)) {
347
+ issues.push({
348
+ type: 'unused-dep',
349
+ severity: 'info',
350
+ file: 'package.json',
351
+ symbol: dep,
352
+ detail: `'${dep}' package.json'da var ama hiçbir dosyada import edilmiyor`,
353
+ suggestion: `npm uninstall ${dep} (veya dolaylı kullanılıyorsa ignore et)`,
354
+ });
355
+ }
356
+ }
357
+ return issues;
358
+ }
359
+ // ── Helpers ────────────────────────────────────────────────
360
+ async collectSourceFiles() {
361
+ const files = [];
362
+ await this.walk(this.projectRoot, files);
363
+ return files;
364
+ }
365
+ async walk(dir, files) {
366
+ let entries;
367
+ try {
368
+ entries = await readdir(dir, { withFileTypes: true });
369
+ }
370
+ catch {
371
+ return;
372
+ }
373
+ for (const entry of entries) {
374
+ if (entry.isDirectory()) {
375
+ if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.'))
376
+ continue;
377
+ await this.walk(join(dir, entry.name), files);
378
+ }
379
+ else if (entry.isFile()) {
380
+ const ext = extname(entry.name).toLowerCase();
381
+ if (SOURCE_EXTS.has(ext)) {
382
+ files.push(relative(this.projectRoot, join(dir, entry.name)).replace(/\\/g, '/'));
383
+ }
384
+ }
385
+ }
386
+ }
387
+ /**
388
+ * Relative import'u dosya yoluna çözümle.
389
+ * './foo.js' → 'src/foo.ts' (TypeScript .js → .ts mapping dahil)
390
+ */
391
+ resolveImportPath(fromFile, importPath, fileSet) {
392
+ if (!importPath.startsWith('.'))
393
+ return null; // external
394
+ const fromDir = dirname(fromFile);
395
+ const rawResolved = join(fromDir, importPath).replace(/\\/g, '/');
396
+ // Aday uzantılar: olduğu gibi, .ts, .tsx, .js→.ts, /index.ts
397
+ const candidates = [
398
+ rawResolved,
399
+ rawResolved.replace(/\.js$/, '.ts'),
400
+ rawResolved.replace(/\.js$/, '.tsx'),
401
+ rawResolved.replace(/\.jsx$/, '.tsx'),
402
+ `${rawResolved}.ts`,
403
+ `${rawResolved}.tsx`,
404
+ `${rawResolved}/index.ts`,
405
+ `${rawResolved}/index.tsx`,
406
+ `${rawResolved}/index.js`,
407
+ ];
408
+ for (const candidate of candidates) {
409
+ if (fileSet.has(candidate))
410
+ return candidate;
411
+ }
412
+ return null;
413
+ }
414
+ isEntryPoint(file) {
415
+ return /^(src\/)?index\.ts$/.test(file) ||
416
+ file.includes('bin/') ||
417
+ file.endsWith('.test.ts') ||
418
+ file.endsWith('.spec.ts');
419
+ }
420
+ isNodeBuiltin(name) {
421
+ const builtins = new Set([
422
+ 'assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',
423
+ 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https',
424
+ 'module', 'net', 'os', 'path', 'perf_hooks', 'process', 'punycode',
425
+ 'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'sys',
426
+ 'timers', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'worker_threads', 'zlib',
427
+ ]);
428
+ return builtins.has(name);
429
+ }
430
+ findLineNumber(lines, charIndex) {
431
+ let count = 0;
432
+ for (let i = 0; i < lines.length; i++) {
433
+ count += lines[i].length + 1; // +1 for \n
434
+ if (count > charIndex)
435
+ return i + 1;
436
+ }
437
+ return lines.length;
438
+ }
439
+ inferExportKind(match) {
440
+ if (match.includes('function'))
441
+ return 'function';
442
+ if (match.includes('class'))
443
+ return 'class';
444
+ if (match.includes('type '))
445
+ return 'type';
446
+ if (match.includes('interface'))
447
+ return 'interface';
448
+ if (match.includes('enum'))
449
+ return 'enum';
450
+ return 'const';
451
+ }
452
+ }
453
+ //# sourceMappingURL=static-analyzer.js.map