@mohantn/gate-keeper 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 (272) hide show
  1. package/.github/instructions/dotnet-api-integration.instructions.md +416 -0
  2. package/.github/instructions/dotnet-development.instructions.md +353 -0
  3. package/.github/instructions/dotnet-testing.instructions.md +406 -0
  4. package/.github/instructions/gate-keeper.instructions.md +91 -0
  5. package/.github/instructions/react-development.instructions.md +315 -0
  6. package/.github/instructions/react-testing-optimization.instructions.md +373 -0
  7. package/.github/instructions/uiux.instructions.md +261 -0
  8. package/LICENSE +21 -0
  9. package/README.md +181 -0
  10. package/dist/analyzer/coverage-analyzer.d.ts +126 -0
  11. package/dist/analyzer/coverage-analyzer.d.ts.map +1 -0
  12. package/dist/analyzer/coverage-analyzer.js +633 -0
  13. package/dist/analyzer/coverage-analyzer.js.map +1 -0
  14. package/dist/analyzer/csharp-analyzer.d.ts +28 -0
  15. package/dist/analyzer/csharp-analyzer.d.ts.map +1 -0
  16. package/dist/analyzer/csharp-analyzer.js +437 -0
  17. package/dist/analyzer/csharp-analyzer.js.map +1 -0
  18. package/dist/analyzer/pattern-detector.d.ts +5 -0
  19. package/dist/analyzer/pattern-detector.d.ts.map +1 -0
  20. package/dist/analyzer/pattern-detector.js +74 -0
  21. package/dist/analyzer/pattern-detector.js.map +1 -0
  22. package/dist/analyzer/refactoring-advisor.d.ts +7 -0
  23. package/dist/analyzer/refactoring-advisor.d.ts.map +1 -0
  24. package/dist/analyzer/refactoring-advisor.js +280 -0
  25. package/dist/analyzer/refactoring-advisor.js.map +1 -0
  26. package/dist/analyzer/sonar-eslint-runner.d.ts +3 -0
  27. package/dist/analyzer/sonar-eslint-runner.d.ts.map +1 -0
  28. package/dist/analyzer/sonar-eslint-runner.js +136 -0
  29. package/dist/analyzer/sonar-eslint-runner.js.map +1 -0
  30. package/dist/analyzer/sonar-rule-map.d.ts +19 -0
  31. package/dist/analyzer/sonar-rule-map.d.ts.map +1 -0
  32. package/dist/analyzer/sonar-rule-map.js +67 -0
  33. package/dist/analyzer/sonar-rule-map.js.map +1 -0
  34. package/dist/analyzer/string-analyzer.d.ts +27 -0
  35. package/dist/analyzer/string-analyzer.d.ts.map +1 -0
  36. package/dist/analyzer/string-analyzer.js +274 -0
  37. package/dist/analyzer/string-analyzer.js.map +1 -0
  38. package/dist/analyzer/typescript-analyzer.d.ts +27 -0
  39. package/dist/analyzer/typescript-analyzer.d.ts.map +1 -0
  40. package/dist/analyzer/typescript-analyzer.js +437 -0
  41. package/dist/analyzer/typescript-analyzer.js.map +1 -0
  42. package/dist/analyzer/universal-analyzer.d.ts +10 -0
  43. package/dist/analyzer/universal-analyzer.d.ts.map +1 -0
  44. package/dist/analyzer/universal-analyzer.js +155 -0
  45. package/dist/analyzer/universal-analyzer.js.map +1 -0
  46. package/dist/cache/quality-cache.d.ts +119 -0
  47. package/dist/cache/quality-cache.d.ts.map +1 -0
  48. package/dist/cache/quality-cache.js +130 -0
  49. package/dist/cache/quality-cache.js.map +1 -0
  50. package/dist/cache/sqlite-cache.d.ts +43 -0
  51. package/dist/cache/sqlite-cache.d.ts.map +1 -0
  52. package/dist/cache/sqlite-cache.js +346 -0
  53. package/dist/cache/sqlite-cache.js.map +1 -0
  54. package/dist/cli/query-repl.d.ts +37 -0
  55. package/dist/cli/query-repl.d.ts.map +1 -0
  56. package/dist/cli/query-repl.js +298 -0
  57. package/dist/cli/query-repl.js.map +1 -0
  58. package/dist/cli/repl-algorithms.d.ts +49 -0
  59. package/dist/cli/repl-algorithms.d.ts.map +1 -0
  60. package/dist/cli/repl-algorithms.js +147 -0
  61. package/dist/cli/repl-algorithms.js.map +1 -0
  62. package/dist/cli/setup-core.d.ts +38 -0
  63. package/dist/cli/setup-core.d.ts.map +1 -0
  64. package/dist/cli/setup-core.js +427 -0
  65. package/dist/cli/setup-core.js.map +1 -0
  66. package/dist/cli/setup.d.ts +25 -0
  67. package/dist/cli/setup.d.ts.map +1 -0
  68. package/dist/cli/setup.js +159 -0
  69. package/dist/cli/setup.js.map +1 -0
  70. package/dist/cli-entry.d.ts +19 -0
  71. package/dist/cli-entry.d.ts.map +1 -0
  72. package/dist/cli-entry.js +178 -0
  73. package/dist/cli-entry.js.map +1 -0
  74. package/dist/daemon/watch-mode.d.ts +41 -0
  75. package/dist/daemon/watch-mode.d.ts.map +1 -0
  76. package/dist/daemon/watch-mode.js +163 -0
  77. package/dist/daemon/watch-mode.js.map +1 -0
  78. package/dist/daemon.d.ts +24 -0
  79. package/dist/daemon.d.ts.map +1 -0
  80. package/dist/daemon.js +357 -0
  81. package/dist/daemon.js.map +1 -0
  82. package/dist/github/app.d.ts +34 -0
  83. package/dist/github/app.d.ts.map +1 -0
  84. package/dist/github/app.js +261 -0
  85. package/dist/github/app.js.map +1 -0
  86. package/dist/github/commenter.d.ts +67 -0
  87. package/dist/github/commenter.d.ts.map +1 -0
  88. package/dist/github/commenter.js +155 -0
  89. package/dist/github/commenter.js.map +1 -0
  90. package/dist/graph/dependency-graph.d.ts +28 -0
  91. package/dist/graph/dependency-graph.d.ts.map +1 -0
  92. package/dist/graph/dependency-graph.js +198 -0
  93. package/dist/graph/dependency-graph.js.map +1 -0
  94. package/dist/graph/global-graph.d.ts +65 -0
  95. package/dist/graph/global-graph.d.ts.map +1 -0
  96. package/dist/graph/global-graph.js +153 -0
  97. package/dist/graph/global-graph.js.map +1 -0
  98. package/dist/graph/graph-algorithms.d.ts +90 -0
  99. package/dist/graph/graph-algorithms.d.ts.map +1 -0
  100. package/dist/graph/graph-algorithms.js +180 -0
  101. package/dist/graph/graph-algorithms.js.map +1 -0
  102. package/dist/graph/graph-export.d.ts +68 -0
  103. package/dist/graph/graph-export.d.ts.map +1 -0
  104. package/dist/graph/graph-export.js +264 -0
  105. package/dist/graph/graph-export.js.map +1 -0
  106. package/dist/graph/graph-report.d.ts +34 -0
  107. package/dist/graph/graph-report.d.ts.map +1 -0
  108. package/dist/graph/graph-report.js +136 -0
  109. package/dist/graph/graph-report.js.map +1 -0
  110. package/dist/graph/graph-summary.d.ts +68 -0
  111. package/dist/graph/graph-summary.d.ts.map +1 -0
  112. package/dist/graph/graph-summary.js +213 -0
  113. package/dist/graph/graph-summary.js.map +1 -0
  114. package/dist/graph/graphify-ignore.d.ts +32 -0
  115. package/dist/graph/graphify-ignore.d.ts.map +1 -0
  116. package/dist/graph/graphify-ignore.js +124 -0
  117. package/dist/graph/graphify-ignore.js.map +1 -0
  118. package/dist/graph/question-suggester.d.ts +30 -0
  119. package/dist/graph/question-suggester.d.ts.map +1 -0
  120. package/dist/graph/question-suggester.js +113 -0
  121. package/dist/graph/question-suggester.js.map +1 -0
  122. package/dist/graph/relationship-extractor.d.ts +40 -0
  123. package/dist/graph/relationship-extractor.d.ts.map +1 -0
  124. package/dist/graph/relationship-extractor.js +254 -0
  125. package/dist/graph/relationship-extractor.js.map +1 -0
  126. package/dist/graph/relationship-types.d.ts +24 -0
  127. package/dist/graph/relationship-types.d.ts.map +1 -0
  128. package/dist/graph/relationship-types.js +21 -0
  129. package/dist/graph/relationship-types.js.map +1 -0
  130. package/dist/graph/surprising-connections.d.ts +39 -0
  131. package/dist/graph/surprising-connections.d.ts.map +1 -0
  132. package/dist/graph/surprising-connections.js +127 -0
  133. package/dist/graph/surprising-connections.js.map +1 -0
  134. package/dist/hook-pre-tool-use.d.ts +14 -0
  135. package/dist/hook-pre-tool-use.d.ts.map +1 -0
  136. package/dist/hook-pre-tool-use.js +167 -0
  137. package/dist/hook-pre-tool-use.js.map +1 -0
  138. package/dist/hook-receiver.d.ts +29 -0
  139. package/dist/hook-receiver.d.ts.map +1 -0
  140. package/dist/hook-receiver.js +327 -0
  141. package/dist/hook-receiver.js.map +1 -0
  142. package/dist/hooks/git-hooks.d.ts +30 -0
  143. package/dist/hooks/git-hooks.d.ts.map +1 -0
  144. package/dist/hooks/git-hooks.js +179 -0
  145. package/dist/hooks/git-hooks.js.map +1 -0
  146. package/dist/mcp/cache-preload.d.ts +29 -0
  147. package/dist/mcp/cache-preload.d.ts.map +1 -0
  148. package/dist/mcp/cache-preload.js +103 -0
  149. package/dist/mcp/cache-preload.js.map +1 -0
  150. package/dist/mcp/handlers/analysis.d.ts +4 -0
  151. package/dist/mcp/handlers/analysis.d.ts.map +1 -0
  152. package/dist/mcp/handlers/analysis.js +196 -0
  153. package/dist/mcp/handlers/analysis.js.map +1 -0
  154. package/dist/mcp/handlers/context.d.ts +25 -0
  155. package/dist/mcp/handlers/context.d.ts.map +1 -0
  156. package/dist/mcp/handlers/context.js +382 -0
  157. package/dist/mcp/handlers/context.js.map +1 -0
  158. package/dist/mcp/handlers/graph-intelligence.d.ts +26 -0
  159. package/dist/mcp/handlers/graph-intelligence.d.ts.map +1 -0
  160. package/dist/mcp/handlers/graph-intelligence.js +371 -0
  161. package/dist/mcp/handlers/graph-intelligence.js.map +1 -0
  162. package/dist/mcp/handlers/graph-query.d.ts +25 -0
  163. package/dist/mcp/handlers/graph-query.d.ts.map +1 -0
  164. package/dist/mcp/handlers/graph-query.js +410 -0
  165. package/dist/mcp/handlers/graph-query.js.map +1 -0
  166. package/dist/mcp/handlers/graph.d.ts +5 -0
  167. package/dist/mcp/handlers/graph.d.ts.map +1 -0
  168. package/dist/mcp/handlers/graph.js +283 -0
  169. package/dist/mcp/handlers/graph.js.map +1 -0
  170. package/dist/mcp/handlers/impact-format.d.ts +9 -0
  171. package/dist/mcp/handlers/impact-format.d.ts.map +1 -0
  172. package/dist/mcp/handlers/impact-format.js +189 -0
  173. package/dist/mcp/handlers/impact-format.js.map +1 -0
  174. package/dist/mcp/handlers/impact.d.ts +4 -0
  175. package/dist/mcp/handlers/impact.d.ts.map +1 -0
  176. package/dist/mcp/handlers/impact.js +139 -0
  177. package/dist/mcp/handlers/impact.js.map +1 -0
  178. package/dist/mcp/handlers/improvement.d.ts +4 -0
  179. package/dist/mcp/handlers/improvement.d.ts.map +1 -0
  180. package/dist/mcp/handlers/improvement.js +136 -0
  181. package/dist/mcp/handlers/improvement.js.map +1 -0
  182. package/dist/mcp/handlers/index.d.ts +14 -0
  183. package/dist/mcp/handlers/index.d.ts.map +1 -0
  184. package/dist/mcp/handlers/index.js +36 -0
  185. package/dist/mcp/handlers/index.js.map +1 -0
  186. package/dist/mcp/handlers/platform-installer.d.ts +10 -0
  187. package/dist/mcp/handlers/platform-installer.d.ts.map +1 -0
  188. package/dist/mcp/handlers/platform-installer.js +168 -0
  189. package/dist/mcp/handlers/platform-installer.js.map +1 -0
  190. package/dist/mcp/handlers/pr-review.d.ts +33 -0
  191. package/dist/mcp/handlers/pr-review.d.ts.map +1 -0
  192. package/dist/mcp/handlers/pr-review.js +170 -0
  193. package/dist/mcp/handlers/pr-review.js.map +1 -0
  194. package/dist/mcp/handlers/shared.d.ts +20 -0
  195. package/dist/mcp/handlers/shared.d.ts.map +1 -0
  196. package/dist/mcp/handlers/shared.js +27 -0
  197. package/dist/mcp/handlers/shared.js.map +1 -0
  198. package/dist/mcp/handlers/types.d.ts +46 -0
  199. package/dist/mcp/handlers/types.d.ts.map +1 -0
  200. package/dist/mcp/handlers/types.js +3 -0
  201. package/dist/mcp/handlers/types.js.map +1 -0
  202. package/dist/mcp/helpers.d.ts +36 -0
  203. package/dist/mcp/helpers.d.ts.map +1 -0
  204. package/dist/mcp/helpers.js +199 -0
  205. package/dist/mcp/helpers.js.map +1 -0
  206. package/dist/mcp/installer.d.ts +22 -0
  207. package/dist/mcp/installer.d.ts.map +1 -0
  208. package/dist/mcp/installer.js +341 -0
  209. package/dist/mcp/installer.js.map +1 -0
  210. package/dist/mcp/server.d.ts +111 -0
  211. package/dist/mcp/server.d.ts.map +1 -0
  212. package/dist/mcp/server.js +216 -0
  213. package/dist/mcp/server.js.map +1 -0
  214. package/dist/mcp/token-tracker.d.ts +47 -0
  215. package/dist/mcp/token-tracker.d.ts.map +1 -0
  216. package/dist/mcp/token-tracker.js +93 -0
  217. package/dist/mcp/token-tracker.js.map +1 -0
  218. package/dist/quality-loop/file-lock.d.ts +12 -0
  219. package/dist/quality-loop/file-lock.d.ts.map +1 -0
  220. package/dist/quality-loop/file-lock.js +38 -0
  221. package/dist/quality-loop/file-lock.js.map +1 -0
  222. package/dist/quality-loop/fix-worker.d.ts +44 -0
  223. package/dist/quality-loop/fix-worker.d.ts.map +1 -0
  224. package/dist/quality-loop/fix-worker.js +414 -0
  225. package/dist/quality-loop/fix-worker.js.map +1 -0
  226. package/dist/quality-loop/orchestrator.d.ts +137 -0
  227. package/dist/quality-loop/orchestrator.d.ts.map +1 -0
  228. package/dist/quality-loop/orchestrator.js +894 -0
  229. package/dist/quality-loop/orchestrator.js.map +1 -0
  230. package/dist/quality-loop/queue-manager.d.ts +45 -0
  231. package/dist/quality-loop/queue-manager.d.ts.map +1 -0
  232. package/dist/quality-loop/queue-manager.js +173 -0
  233. package/dist/quality-loop/queue-manager.js.map +1 -0
  234. package/dist/rating/rating-calculator.d.ts +15 -0
  235. package/dist/rating/rating-calculator.d.ts.map +1 -0
  236. package/dist/rating/rating-calculator.js +136 -0
  237. package/dist/rating/rating-calculator.js.map +1 -0
  238. package/dist/types/agent.d.ts +49 -0
  239. package/dist/types/agent.d.ts.map +1 -0
  240. package/dist/types/agent.js +7 -0
  241. package/dist/types/agent.js.map +1 -0
  242. package/dist/types.d.ts +156 -0
  243. package/dist/types.d.ts.map +1 -0
  244. package/dist/types.js +3 -0
  245. package/dist/types.js.map +1 -0
  246. package/dist/util/fix-text.d.ts +7 -0
  247. package/dist/util/fix-text.d.ts.map +1 -0
  248. package/dist/util/fix-text.js +13 -0
  249. package/dist/util/fix-text.js.map +1 -0
  250. package/dist/viz/graph-viz.d.ts +40 -0
  251. package/dist/viz/graph-viz.d.ts.map +1 -0
  252. package/dist/viz/graph-viz.js +332 -0
  253. package/dist/viz/graph-viz.js.map +1 -0
  254. package/dist/viz/viz-helpers.d.ts +13 -0
  255. package/dist/viz/viz-helpers.d.ts.map +1 -0
  256. package/dist/viz/viz-helpers.js +134 -0
  257. package/dist/viz/viz-helpers.js.map +1 -0
  258. package/dist/viz/viz-routes.d.ts +28 -0
  259. package/dist/viz/viz-routes.d.ts.map +1 -0
  260. package/dist/viz/viz-routes.js +333 -0
  261. package/dist/viz/viz-routes.js.map +1 -0
  262. package/dist/viz/viz-scanner.d.ts +20 -0
  263. package/dist/viz/viz-scanner.d.ts.map +1 -0
  264. package/dist/viz/viz-scanner.js +241 -0
  265. package/dist/viz/viz-scanner.js.map +1 -0
  266. package/dist/viz/viz-server.d.ts +38 -0
  267. package/dist/viz/viz-server.d.ts.map +1 -0
  268. package/dist/viz/viz-server.js +240 -0
  269. package/dist/viz/viz-server.js.map +1 -0
  270. package/package.json +89 -0
  271. package/scripts/postinstall.js +28 -0
  272. package/scripts/setup.sh +113 -0
@@ -0,0 +1,156 @@
1
+ export type Language = 'csharp' | 'typescript' | 'tsx' | 'jsx';
2
+ export interface Dependency {
3
+ source: string;
4
+ target: string;
5
+ type: 'import' | 'inheritance' | 'composition' | 'usage';
6
+ weight: number;
7
+ }
8
+ export interface Metrics {
9
+ linesOfCode: number;
10
+ cyclomaticComplexity: number;
11
+ numberOfMethods: number;
12
+ numberOfClasses: number;
13
+ importCount: number;
14
+ /** Test coverage percentage (0–100). Undefined when no coverage data is available. */
15
+ coveragePercent?: number;
16
+ }
17
+ export { Span, Fix, RatingBreakdownItem, AgentResponseEnvelope, RemediationStep, RemediationPlan, } from './types/agent';
18
+ import { Span, Fix, RatingBreakdownItem } from './types/agent';
19
+ export type ViolationCategory = 'bug' | 'vulnerability' | 'code_smell' | 'hotspot';
20
+ export interface Violation {
21
+ type: string;
22
+ severity: 'error' | 'warning' | 'info';
23
+ message: string;
24
+ line?: number;
25
+ fix?: Fix | string;
26
+ ruleId?: string;
27
+ span?: Span;
28
+ codeSnippet?: string;
29
+ priorityScore?: number;
30
+ category?: ViolationCategory;
31
+ }
32
+ export interface FileAnalysis {
33
+ path: string;
34
+ language: Language;
35
+ dependencies: Dependency[];
36
+ metrics: Metrics;
37
+ violations: Violation[];
38
+ rating: number;
39
+ analyzedAt: number;
40
+ repoRoot?: string;
41
+ definedTypes?: string[];
42
+ ratingBreakdown?: RatingBreakdownItem[];
43
+ fileHash?: string;
44
+ analyzerVersion?: string;
45
+ }
46
+ export interface GraphNode {
47
+ id: string;
48
+ label: string;
49
+ type: Language;
50
+ rating: number;
51
+ size: number;
52
+ violations: Violation[];
53
+ metrics: Metrics;
54
+ }
55
+ export interface GraphEdge {
56
+ source: string;
57
+ target: string;
58
+ type: string;
59
+ strength: number;
60
+ }
61
+ export interface GraphData {
62
+ nodes: GraphNode[];
63
+ edges: GraphEdge[];
64
+ }
65
+ export interface WSMessage {
66
+ type: 'init' | 'update' | 'analysis_complete' | 'error' | 'scan_start' | 'scan_progress' | 'scan_complete' | 'scan_log' | 'repo_list' | 'repo_created';
67
+ data?: GraphData;
68
+ delta?: {
69
+ nodes: GraphNode[];
70
+ edges: GraphEdge[];
71
+ };
72
+ analysis?: FileAnalysis;
73
+ error?: string;
74
+ scanTotal?: number;
75
+ scanAnalyzed?: number;
76
+ repos?: RepoMetadata[];
77
+ repo?: RepoMetadata;
78
+ currentRepo?: string;
79
+ logMessage?: string;
80
+ logLevel?: 'info' | 'warn' | 'error';
81
+ logTimestamp?: number;
82
+ }
83
+ export interface HookPayload {
84
+ session_id?: string;
85
+ hook_event_name?: 'PostToolUse' | 'PreToolUse' | 'UserPromptSubmit' | 'SessionStart' | 'Stop' | 'session_create' | string;
86
+ tool_name: string;
87
+ cwd?: string;
88
+ tool_input: {
89
+ file_path?: string;
90
+ path?: string;
91
+ old_string?: string;
92
+ new_string?: string;
93
+ content?: string;
94
+ };
95
+ }
96
+ export interface DaemonRequest {
97
+ filePath: string;
98
+ repoRoot: string;
99
+ }
100
+ export interface DaemonStatus {
101
+ running: boolean;
102
+ port: number;
103
+ analyzedFiles: number;
104
+ overallRating: number;
105
+ }
106
+ export interface Config {
107
+ minRating: number;
108
+ scanExcludePatterns?: {
109
+ /** Glob patterns applied to all languages */
110
+ global?: string[];
111
+ /** Glob patterns for C# files (.cs) */
112
+ csharp?: string[];
113
+ /** Glob patterns for TypeScript/JavaScript/React files */
114
+ typescript?: string[];
115
+ };
116
+ }
117
+ export interface RepoMetadata {
118
+ id: string;
119
+ path: string;
120
+ name: string;
121
+ sessionId?: string;
122
+ sessionType: 'github-copilot' | 'claude' | 'unknown';
123
+ createdAt: number;
124
+ lastAnalyzedAt?: number;
125
+ fileCount?: number;
126
+ overallRating?: number;
127
+ isActive?: boolean;
128
+ }
129
+ export interface SessionCreatePayload {
130
+ session_id: string;
131
+ hook_event_name: 'session_create';
132
+ tool_name: string;
133
+ session_info: {
134
+ workspace_path: string;
135
+ git_root?: string;
136
+ session_type: 'github-copilot' | 'claude';
137
+ };
138
+ }
139
+ export interface RefactoringHint {
140
+ patternName: string;
141
+ violationType: string;
142
+ rationale: string;
143
+ steps: string[];
144
+ estimatedRatingGain: number;
145
+ priority: 'high' | 'medium' | 'low';
146
+ }
147
+ export interface PatternReport {
148
+ violationType: string;
149
+ severity: 'error' | 'warning' | 'info';
150
+ fileCount: number;
151
+ totalOccurrences: number;
152
+ affectedFiles: string[];
153
+ estimatedRatingGain: number;
154
+ moduleSuggestion: string;
155
+ }
156
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ import { Fix } from '../types';
2
+ /**
3
+ * Render either a string Fix or a Fix object to a single line of text suitable
4
+ * for markdown reports. Returns undefined when no fix is present.
5
+ */
6
+ export declare function fixText(fix: Fix | string | undefined): string | undefined;
7
+ //# sourceMappingURL=fix-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-text.d.ts","sourceRoot":"","sources":["../../src/util/fix-text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B;;;GAGG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGzE"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fixText = fixText;
4
+ /**
5
+ * Render either a string Fix or a Fix object to a single line of text suitable
6
+ * for markdown reports. Returns undefined when no fix is present.
7
+ */
8
+ function fixText(fix) {
9
+ if (fix == null)
10
+ return undefined;
11
+ return typeof fix === 'string' ? fix : fix.description;
12
+ }
13
+ //# sourceMappingURL=fix-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-text.js","sourceRoot":"","sources":["../../src/util/fix-text.ts"],"names":[],"mappings":";;AAMA,0BAGC;AAPD;;;GAGG;AACH,SAAgB,OAAO,CAAC,GAA6B;IACnD,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC;IAClC,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;AACzD,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Standalone interactive HTML graph visualizer.
3
+ *
4
+ * Generates a self-contained HTML file with:
5
+ * - Force-directed layout (Verlet integration, spring + repulsion + gravity)
6
+ * - SVG rendering with pan/zoom via pointer events
7
+ * - Hover tooltip and click detail panel
8
+ * - Search/filter nodes by name
9
+ * - Rating-coloured nodes, size proportional to in-degree
10
+ * - Full offline operation — zero external dependencies
11
+ *
12
+ * Pure function: generateGraphViz(nodes, edges) → HTML string
13
+ */
14
+ interface VizNode {
15
+ id: string;
16
+ label: string;
17
+ rating: number;
18
+ metrics?: {
19
+ linesOfCode?: number;
20
+ cyclomaticComplexity?: number;
21
+ importCount?: number;
22
+ };
23
+ violations?: Array<{
24
+ type: string;
25
+ severity: string;
26
+ }>;
27
+ }
28
+ interface VizEdge {
29
+ source: string;
30
+ target: string;
31
+ type?: string;
32
+ }
33
+ export interface GraphVizOptions {
34
+ title?: string;
35
+ width?: number;
36
+ height?: number;
37
+ }
38
+ export declare function generateGraphViz(nodes: ReadonlyArray<VizNode>, edges: ReadonlyArray<VizEdge>, opts?: GraphVizOptions): string;
39
+ export {};
40
+ //# sourceMappingURL=graph-viz.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-viz.d.ts","sourceRoot":"","sources":["../../src/viz/graph-viz.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxF,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAED,UAAU,OAAO;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE;AAEnE,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAC7B,IAAI,GAAE,eAAoB,GACzB,MAAM,CAyTR"}
@@ -0,0 +1,332 @@
1
+ "use strict";
2
+ /**
3
+ * Standalone interactive HTML graph visualizer.
4
+ *
5
+ * Generates a self-contained HTML file with:
6
+ * - Force-directed layout (Verlet integration, spring + repulsion + gravity)
7
+ * - SVG rendering with pan/zoom via pointer events
8
+ * - Hover tooltip and click detail panel
9
+ * - Search/filter nodes by name
10
+ * - Rating-coloured nodes, size proportional to in-degree
11
+ * - Full offline operation — zero external dependencies
12
+ *
13
+ * Pure function: generateGraphViz(nodes, edges) → HTML string
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.generateGraphViz = generateGraphViz;
17
+ function generateGraphViz(nodes, edges, opts = {}) {
18
+ const title = opts.title ?? 'Gate Keeper — Dependency Graph';
19
+ const W = opts.width ?? 1200;
20
+ const H = opts.height ?? 800;
21
+ // Serialise graph data as JSON for embedding
22
+ const graphData = JSON.stringify({
23
+ nodes: nodes.map(n => ({
24
+ id: n.id,
25
+ label: n.label,
26
+ rating: n.rating,
27
+ loc: n.metrics?.linesOfCode ?? 0,
28
+ complexity: n.metrics?.cyclomaticComplexity ?? 0,
29
+ imports: n.metrics?.importCount ?? 0,
30
+ errors: n.violations?.filter(v => v.severity === 'error').length ?? 0,
31
+ warnings: n.violations?.filter(v => v.severity === 'warning').length ?? 0,
32
+ })),
33
+ edges: edges.map(e => ({ s: e.source, t: e.target, tp: e.type ?? 'import' })),
34
+ });
35
+ return `<!DOCTYPE html>
36
+ <html lang="en">
37
+ <head>
38
+ <meta charset="UTF-8">
39
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
40
+ <title>${htmlEsc(title)}</title>
41
+ <style>
42
+ *{box-sizing:border-box;margin:0;padding:0}
43
+ body{font-family:system-ui,sans-serif;background:#1e1e2e;color:#cdd6f4;height:100vh;display:flex;flex-direction:column}
44
+ #toolbar{display:flex;align-items:center;gap:10px;padding:8px 14px;background:#181825;border-bottom:1px solid #313244;flex-shrink:0}
45
+ #toolbar h1{font-size:14px;font-weight:600;color:#cba6f7;white-space:nowrap}
46
+ #search{background:#313244;border:1px solid #45475a;border-radius:6px;color:#cdd6f4;padding:4px 10px;font-size:13px;width:200px}
47
+ #search:focus{outline:none;border-color:#89b4fa}
48
+ #stats{font-size:12px;color:#6c7086;margin-left:auto}
49
+ .legend{display:flex;gap:12px;font-size:11px;align-items:center}
50
+ .litem{display:flex;align-items:center;gap:4px}
51
+ .ldot{width:10px;height:10px;border-radius:50%;flex-shrink:0}
52
+ #main{display:flex;flex:1;overflow:hidden}
53
+ #canvas-wrap{flex:1;overflow:hidden;position:relative;cursor:grab}
54
+ #canvas-wrap.grabbing{cursor:grabbing}
55
+ svg{width:100%;height:100%;display:block}
56
+ .edge{stroke:#45475a;stroke-width:1;fill:none;opacity:0.6}
57
+ .edge.call{stroke:#89b4fa;opacity:0.8}
58
+ .edge.extends{stroke:#cba6f7;stroke-width:2;opacity:0.9}
59
+ .node circle{stroke:#1e1e2e;stroke-width:1.5;transition:stroke-width .15s}
60
+ .node circle:hover,.node.selected circle{stroke:#f38ba8;stroke-width:3}
61
+ .node text{font-size:9px;fill:#cdd6f4;pointer-events:none;user-select:none}
62
+ #panel{width:300px;background:#181825;border-left:1px solid #313244;overflow-y:auto;flex-shrink:0;transform:translateX(100%);transition:transform .2s}
63
+ #panel.open{transform:translateX(0)}
64
+ #panel-inner{padding:16px}
65
+ #panel h2{font-size:14px;color:#cba6f7;margin-bottom:12px}
66
+ .metric{display:flex;justify-content:space-between;font-size:12px;padding:4px 0;border-bottom:1px solid #313244}
67
+ .metric .val{color:#a6e3a1;font-weight:600}
68
+ .metric .val.bad{color:#f38ba8}
69
+ .metric .val.warn{color:#fab387}
70
+ #close-panel{position:absolute;top:8px;right:8px;background:none;border:none;color:#6c7086;font-size:18px;cursor:pointer}
71
+ #close-panel:hover{color:#cdd6f4}
72
+ #tooltip{position:absolute;background:#313244;border:1px solid #45475a;border-radius:6px;padding:8px 12px;font-size:12px;pointer-events:none;opacity:0;transition:opacity .1s;max-width:240px;z-index:10}
73
+ #tooltip.show{opacity:1}
74
+ </style>
75
+ </head>
76
+ <body>
77
+ <div id="toolbar">
78
+ <h1>⬡ ${htmlEsc(title)}</h1>
79
+ <input id="search" placeholder="Search files…" autocomplete="off">
80
+ <div class="legend">
81
+ <div class="litem"><div class="ldot" style="background:#a6e3a1"></div>≥8</div>
82
+ <div class="litem"><div class="ldot" style="background:#f9e2af"></div>6–8</div>
83
+ <div class="litem"><div class="ldot" style="background:#fab387"></div>4–6</div>
84
+ <div class="litem"><div class="ldot" style="background:#f38ba8"></div>&lt;4</div>
85
+ </div>
86
+ <div id="stats"></div>
87
+ </div>
88
+ <div id="main">
89
+ <div id="canvas-wrap">
90
+ <svg id="svg"><g id="g-edges"></g><g id="g-nodes"></g></svg>
91
+ <div id="tooltip"></div>
92
+ </div>
93
+ <div id="panel">
94
+ <button id="close-panel">×</button>
95
+ <div id="panel-inner"></div>
96
+ </div>
97
+ </div>
98
+ <script>
99
+ (function(){
100
+ 'use strict';
101
+ const DATA = ${graphData};
102
+
103
+ // ── State ──────────────────────────────────────────────────
104
+ const nodeMap = new Map(DATA.nodes.map(n => [n.id, n]));
105
+ const adjOut = new Map(); // id → [target ids]
106
+ const adjIn = new Map(); // id → [source ids]
107
+ DATA.nodes.forEach(n => { adjOut.set(n.id,[]); adjIn.set(n.id,[]); });
108
+ DATA.edges.forEach(e => {
109
+ (adjOut.get(e.s)||[]).push(e.t);
110
+ (adjIn.get(e.t)||[]).push(e.s);
111
+ });
112
+
113
+ let pan={x:0,y:0}, zoom=1;
114
+ let dragging=null, lastPointer=null;
115
+ let simRunning=true, tick=0;
116
+
117
+ // Physics state
118
+ const sim = DATA.nodes.map((n,i) => {
119
+ const angle = (2*Math.PI*i)/DATA.nodes.length;
120
+ const r = 200 + Math.random()*80;
121
+ return { id:n.id, x:r*Math.cos(angle), y:r*Math.sin(angle), vx:0, vy:0 };
122
+ });
123
+ const simMap = new Map(sim.map(s => [s.id, s]));
124
+
125
+ // ── Colors ────────────────────────────────────────────────
126
+ function ratingColor(r) {
127
+ if(r>=8) return '#a6e3a1';
128
+ if(r>=6) return '#f9e2af';
129
+ if(r>=4) return '#fab387';
130
+ return '#f38ba8';
131
+ }
132
+ function nodeR(id) {
133
+ const d = (adjIn.get(id)||[]).length;
134
+ return Math.max(6, Math.min(18, 6 + d*1.5));
135
+ }
136
+
137
+ // ── SVG helpers ────────────────────────────────────────────
138
+ const SVG_NS = 'http://www.w3.org/2000/svg';
139
+ function el(tag, attrs={}) {
140
+ const e = document.createElementNS(SVG_NS, tag);
141
+ for(const [k,v] of Object.entries(attrs)) e.setAttribute(k,v);
142
+ return e;
143
+ }
144
+
145
+ // ── Build SVG elements ─────────────────────────────────────
146
+ const svg = document.getElementById('svg');
147
+ const gEdges = document.getElementById('g-edges');
148
+ const gNodes = document.getElementById('g-nodes');
149
+
150
+ const edgeEls = DATA.edges.map(e => {
151
+ const cls = e.tp==='FUNCTION_CALL'?'edge call':e.tp==='CLASS_EXTENDS'?'edge extends':'edge';
152
+ const line = el('line',{class:cls,'data-s':e.s,'data-t':e.t});
153
+ gEdges.appendChild(line);
154
+ return {el:line, s:e.s, t:e.t};
155
+ });
156
+
157
+ const nodeEls = new Map();
158
+ DATA.nodes.forEach(n => {
159
+ const g = el('g',{class:'node','data-id':n.id});
160
+ const c = el('circle',{r:nodeR(n.id), fill:ratingColor(n.rating), cx:'0', cy:'0'});
161
+ const txt = el('text',{x:(nodeR(n.id)+3).toString(), y:'3'});
162
+ txt.textContent = n.label;
163
+ g.appendChild(c); g.appendChild(txt);
164
+ gNodes.appendChild(g);
165
+ nodeEls.set(n.id, {g, c});
166
+ });
167
+
168
+ // ── Force simulation ───────────────────────────────────────
169
+ function step() {
170
+ const K=80, REPEL=3000, GRAVITY=0.04, DAMP=0.85;
171
+ const idx = Array.from(simMap.values());
172
+ // Repulsion
173
+ for(let i=0;i<idx.length;i++) {
174
+ for(let j=i+1;j<idx.length;j++) {
175
+ const a=idx[i], b=idx[j];
176
+ const dx=b.x-a.x, dy=b.y-a.y;
177
+ const d2=dx*dx+dy*dy+0.1;
178
+ const f=REPEL/d2;
179
+ const fx=f*dx/Math.sqrt(d2), fy=f*dy/Math.sqrt(d2);
180
+ a.vx-=fx; a.vy-=fy; b.vx+=fx; b.vy+=fy;
181
+ }
182
+ }
183
+ // Spring attraction
184
+ DATA.edges.forEach(e => {
185
+ const a=simMap.get(e.s), b=simMap.get(e.t);
186
+ if(!a||!b) return;
187
+ const dx=b.x-a.x, dy=b.y-a.y;
188
+ const d=Math.sqrt(dx*dx+dy*dy)+0.1;
189
+ const f=(d-K)/d*0.3;
190
+ a.vx+=f*dx; a.vy+=f*dy; b.vx-=f*dx; b.vy-=f*dy;
191
+ });
192
+ // Gravity toward origin
193
+ for(const s of idx) {
194
+ s.vx-=s.x*GRAVITY; s.vy-=s.y*GRAVITY;
195
+ s.vx*=DAMP; s.vy*=DAMP;
196
+ s.x+=s.vx; s.y+=s.vy;
197
+ }
198
+ }
199
+
200
+ // ── Render ─────────────────────────────────────────────────
201
+ function applyTransform() {
202
+ svg.querySelector('#g-edges').setAttribute('transform',
203
+ \`translate(\${pan.x+window.innerWidth/2},\${pan.y+window.innerHeight/2}) scale(\${zoom})\`);
204
+ svg.querySelector('#g-nodes').setAttribute('transform',
205
+ \`translate(\${pan.x+window.innerWidth/2},\${pan.y+window.innerHeight/2}) scale(\${zoom})\`);
206
+ }
207
+
208
+ let hidden = new Set();
209
+ function render() {
210
+ for(const {el:line,s,t} of edgeEls) {
211
+ const a=simMap.get(s), b=simMap.get(t);
212
+ if(!a||!b) continue;
213
+ if(hidden.has(s)||hidden.has(t)) { line.style.display='none'; continue; }
214
+ line.style.display='';
215
+ line.setAttribute('x1',a.x); line.setAttribute('y1',a.y);
216
+ line.setAttribute('x2',b.x); line.setAttribute('y2',b.y);
217
+ }
218
+ for(const [id,{g}] of nodeEls) {
219
+ const s=simMap.get(id);
220
+ if(!s) continue;
221
+ if(hidden.has(id)) { g.style.display='none'; continue; }
222
+ g.style.display='';
223
+ g.setAttribute('transform',\`translate(\${s.x},\${s.y})\`);
224
+ }
225
+ applyTransform();
226
+ }
227
+
228
+ const WARMUP=200;
229
+ function loop() {
230
+ if(simRunning) { step(); tick++; if(tick>=WARMUP) simRunning=false; }
231
+ render();
232
+ requestAnimationFrame(loop);
233
+ }
234
+ applyTransform();
235
+ loop();
236
+
237
+ document.getElementById('stats').textContent =
238
+ \`\${DATA.nodes.length} files · \${DATA.edges.length} edges\`;
239
+
240
+ // ── Search ────────────────────────────────────────────────
241
+ document.getElementById('search').addEventListener('input', function(){
242
+ const q = this.value.toLowerCase().trim();
243
+ if(!q) { hidden=new Set(); return; }
244
+ hidden = new Set(DATA.nodes.filter(n => !n.label.toLowerCase().includes(q)).map(n=>n.id));
245
+ });
246
+
247
+ // ── Pan/Zoom ───────────────────────────────────────────────
248
+ const wrap = document.getElementById('canvas-wrap');
249
+ wrap.addEventListener('wheel', e => {
250
+ e.preventDefault();
251
+ zoom = Math.max(0.2, Math.min(5, zoom * (e.deltaY < 0 ? 1.1 : 0.9)));
252
+ }, {passive:false});
253
+ wrap.addEventListener('pointerdown', e => {
254
+ if(e.target.closest('.node')) return;
255
+ dragging='pan'; lastPointer={x:e.clientX,y:e.clientY};
256
+ wrap.classList.add('grabbing');
257
+ });
258
+ window.addEventListener('pointermove', e => {
259
+ if(dragging==='pan') {
260
+ pan.x += e.clientX - lastPointer.x;
261
+ pan.y += e.clientY - lastPointer.y;
262
+ lastPointer={x:e.clientX,y:e.clientY};
263
+ }
264
+ });
265
+ window.addEventListener('pointerup', () => {
266
+ dragging=null; wrap.classList.remove('grabbing');
267
+ });
268
+
269
+ // ── Tooltip ───────────────────────────────────────────────
270
+ const tooltip = document.getElementById('tooltip');
271
+ gNodes.addEventListener('mouseover', e => {
272
+ const g = e.target.closest('.node');
273
+ if(!g) return;
274
+ const n = nodeMap.get(g.dataset.id);
275
+ if(!n) return;
276
+ tooltip.innerHTML = \`<strong>\${n.label}</strong><br>
277
+ Rating: \${n.rating}/10 · LOC: \${n.loc||'?'}<br>
278
+ In-degree: \${(adjIn.get(n.id)||[]).length} · Out: \${(adjOut.get(n.id)||[]).length}\`;
279
+ tooltip.classList.add('show');
280
+ });
281
+ gNodes.addEventListener('mousemove', e => {
282
+ tooltip.style.left = (e.clientX+14)+'px';
283
+ tooltip.style.top = (e.clientY-10)+'px';
284
+ });
285
+ gNodes.addEventListener('mouseleave', () => tooltip.classList.remove('show'));
286
+
287
+ // ── Detail panel ──────────────────────────────────────────
288
+ let selected = null;
289
+ gNodes.addEventListener('click', e => {
290
+ const g = e.target.closest('.node');
291
+ if(!g) return;
292
+ const id = g.dataset.id;
293
+ if(selected) nodeEls.get(selected)?.g.classList.remove('selected');
294
+ selected = id;
295
+ g.classList.add('selected');
296
+ openPanel(id);
297
+ });
298
+ document.getElementById('close-panel').addEventListener('click', () => {
299
+ document.getElementById('panel').classList.remove('open');
300
+ if(selected) { nodeEls.get(selected)?.g.classList.remove('selected'); selected=null; }
301
+ });
302
+
303
+ function openPanel(id) {
304
+ const n = nodeMap.get(id);
305
+ if(!n) return;
306
+ const ins = (adjIn.get(id)||[]).map(x=>nodeMap.get(x)?.label||x);
307
+ const outs = (adjOut.get(id)||[]).map(x=>nodeMap.get(x)?.label||x);
308
+ const rc = r => r>=8?'':r>=6?'warn':'bad';
309
+ document.getElementById('panel-inner').innerHTML = \`
310
+ <h2>\${n.label}</h2>
311
+ <div class="metric"><span>Rating</span><span class="val \${rc(n.rating)}">\${n.rating}/10</span></div>
312
+ <div class="metric"><span>Lines of code</span><span class="val">\${n.loc||'?'}</span></div>
313
+ <div class="metric"><span>Complexity</span><span class="val \${n.complexity>10?'bad':n.complexity>5?'warn':''}">\${n.complexity||'?'}</span></div>
314
+ <div class="metric"><span>Imports</span><span class="val">\${n.imports||0}</span></div>
315
+ <div class="metric"><span>Errors / Warnings</span><span class="val \${n.errors?'bad':''}">\${n.errors} / \${n.warnings}</span></div>
316
+ <div class="metric"><span>In-degree</span><span class="val">\${ins.length}</span></div>
317
+ <div class="metric"><span>Out-degree</span><span class="val">\${outs.length}</span></div>
318
+ \${ins.length?'<p style="font-size:11px;margin-top:10px;color:#6c7086">Imported by:</p><p style="font-size:11px">'+ins.slice(0,8).join(', ')+(ins.length>8?'…':'')+'</p>':''}
319
+ \${outs.length?'<p style="font-size:11px;margin-top:8px;color:#6c7086">Imports:</p><p style="font-size:11px">'+outs.slice(0,8).join(', ')+(outs.length>8?'…':'')+'</p>':''}
320
+ \`;
321
+ document.getElementById('panel').classList.add('open');
322
+ }
323
+
324
+ })();
325
+ </script>
326
+ </body>
327
+ </html>`;
328
+ }
329
+ function htmlEsc(s) {
330
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
331
+ }
332
+ //# sourceMappingURL=graph-viz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-viz.js","sourceRoot":"","sources":["../../src/viz/graph-viz.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AAkBH,4CA6TC;AA7TD,SAAgB,gBAAgB,CAC9B,KAA6B,EAC7B,KAA6B,EAC7B,OAAwB,EAAE;IAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,gCAAgC,CAAC;IAC7D,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC;IAC7B,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC;IAE7B,6CAA6C;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAC/B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACrB,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,WAAW,IAAI,CAAC;YAChC,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,oBAAoB,IAAI,CAAC;YAChD,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,WAAW,IAAI,CAAC;YACpC,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC;YACrE,QAAQ,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,IAAI,CAAC;SAC1E,CAAC,CAAC;QACH,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC,CAAC;KAC9E,CAAC,CAAC;IAEH,OAAO;;;;;SAKA,OAAO,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAsCb,OAAO,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;eAuBT,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAkOhB,CAAC;AACT,CAAC;AAED,SAAS,OAAO,CAAC,CAAS;IACxB,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACtG,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { Config } from '../types';
2
+ /** Convert a simple glob pattern to a RegExp. Supports * and ** wildcards. */
3
+ export declare function globToRegex(pattern: string): RegExp;
4
+ /** Map file extension to config language key */
5
+ export declare function extToConfigLang(ext: string): 'csharp' | 'typescript' | null;
6
+ /** Check if a file path should be excluded by scan patterns */
7
+ export declare function shouldExcludeFile(filePath: string, ext: string, patterns: Config['scanExcludePatterns']): boolean;
8
+ export declare function walkFiles(dir: string, filter?: (filePath: string) => boolean): Generator<string>;
9
+ export declare function getGitDiffStats(filePath: string): {
10
+ added: number;
11
+ removed: number;
12
+ } | null;
13
+ //# sourceMappingURL=viz-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viz-helpers.d.ts","sourceRoot":"","sources":["../../src/viz/viz-helpers.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAOlC,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED,gDAAgD;AAChD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,IAAI,CAI3E;AAED,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,qBAAqB,CAAC,GAAG,OAAO,CAqBjH;AAED,wBAAiB,SAAS,CACxB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,GACrC,SAAS,CAAC,MAAM,CAAC,CAgBnB;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAyB3F"}