spec-gen-cli 1.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 (303) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1078 -0
  3. package/dist/api/analyze.d.ts +17 -0
  4. package/dist/api/analyze.d.ts.map +1 -0
  5. package/dist/api/analyze.js +109 -0
  6. package/dist/api/analyze.js.map +1 -0
  7. package/dist/api/drift.d.ts +21 -0
  8. package/dist/api/drift.d.ts.map +1 -0
  9. package/dist/api/drift.js +145 -0
  10. package/dist/api/drift.js.map +1 -0
  11. package/dist/api/generate.d.ts +18 -0
  12. package/dist/api/generate.d.ts.map +1 -0
  13. package/dist/api/generate.js +251 -0
  14. package/dist/api/generate.js.map +1 -0
  15. package/dist/api/index.d.ts +39 -0
  16. package/dist/api/index.d.ts.map +1 -0
  17. package/dist/api/index.js +32 -0
  18. package/dist/api/index.js.map +1 -0
  19. package/dist/api/init.d.ts +18 -0
  20. package/dist/api/init.d.ts.map +1 -0
  21. package/dist/api/init.js +82 -0
  22. package/dist/api/init.js.map +1 -0
  23. package/dist/api/run.d.ts +19 -0
  24. package/dist/api/run.d.ts.map +1 -0
  25. package/dist/api/run.js +291 -0
  26. package/dist/api/run.js.map +1 -0
  27. package/dist/api/specs.d.ts +49 -0
  28. package/dist/api/specs.d.ts.map +1 -0
  29. package/dist/api/specs.js +136 -0
  30. package/dist/api/specs.js.map +1 -0
  31. package/dist/api/types.d.ts +176 -0
  32. package/dist/api/types.d.ts.map +1 -0
  33. package/dist/api/types.js +9 -0
  34. package/dist/api/types.js.map +1 -0
  35. package/dist/api/verify.d.ts +20 -0
  36. package/dist/api/verify.d.ts.map +1 -0
  37. package/dist/api/verify.js +117 -0
  38. package/dist/api/verify.js.map +1 -0
  39. package/dist/cli/commands/analyze.d.ts +27 -0
  40. package/dist/cli/commands/analyze.d.ts.map +1 -0
  41. package/dist/cli/commands/analyze.js +485 -0
  42. package/dist/cli/commands/analyze.js.map +1 -0
  43. package/dist/cli/commands/drift.d.ts +9 -0
  44. package/dist/cli/commands/drift.d.ts.map +1 -0
  45. package/dist/cli/commands/drift.js +540 -0
  46. package/dist/cli/commands/drift.js.map +1 -0
  47. package/dist/cli/commands/generate.d.ts +9 -0
  48. package/dist/cli/commands/generate.d.ts.map +1 -0
  49. package/dist/cli/commands/generate.js +633 -0
  50. package/dist/cli/commands/generate.js.map +1 -0
  51. package/dist/cli/commands/init.d.ts +9 -0
  52. package/dist/cli/commands/init.d.ts.map +1 -0
  53. package/dist/cli/commands/init.js +171 -0
  54. package/dist/cli/commands/init.js.map +1 -0
  55. package/dist/cli/commands/mcp.d.ts +638 -0
  56. package/dist/cli/commands/mcp.d.ts.map +1 -0
  57. package/dist/cli/commands/mcp.js +574 -0
  58. package/dist/cli/commands/mcp.js.map +1 -0
  59. package/dist/cli/commands/run.d.ts +24 -0
  60. package/dist/cli/commands/run.d.ts.map +1 -0
  61. package/dist/cli/commands/run.js +546 -0
  62. package/dist/cli/commands/run.js.map +1 -0
  63. package/dist/cli/commands/verify.d.ts +9 -0
  64. package/dist/cli/commands/verify.d.ts.map +1 -0
  65. package/dist/cli/commands/verify.js +417 -0
  66. package/dist/cli/commands/verify.js.map +1 -0
  67. package/dist/cli/commands/view.d.ts +9 -0
  68. package/dist/cli/commands/view.d.ts.map +1 -0
  69. package/dist/cli/commands/view.js +511 -0
  70. package/dist/cli/commands/view.js.map +1 -0
  71. package/dist/cli/index.d.ts +9 -0
  72. package/dist/cli/index.d.ts.map +1 -0
  73. package/dist/cli/index.js +83 -0
  74. package/dist/cli/index.js.map +1 -0
  75. package/dist/core/analyzer/architecture-writer.d.ts +67 -0
  76. package/dist/core/analyzer/architecture-writer.d.ts.map +1 -0
  77. package/dist/core/analyzer/architecture-writer.js +209 -0
  78. package/dist/core/analyzer/architecture-writer.js.map +1 -0
  79. package/dist/core/analyzer/artifact-generator.d.ts +222 -0
  80. package/dist/core/analyzer/artifact-generator.d.ts.map +1 -0
  81. package/dist/core/analyzer/artifact-generator.js +726 -0
  82. package/dist/core/analyzer/artifact-generator.js.map +1 -0
  83. package/dist/core/analyzer/call-graph.d.ts +83 -0
  84. package/dist/core/analyzer/call-graph.d.ts.map +1 -0
  85. package/dist/core/analyzer/call-graph.js +827 -0
  86. package/dist/core/analyzer/call-graph.js.map +1 -0
  87. package/dist/core/analyzer/code-shaper.d.ts +33 -0
  88. package/dist/core/analyzer/code-shaper.d.ts.map +1 -0
  89. package/dist/core/analyzer/code-shaper.js +149 -0
  90. package/dist/core/analyzer/code-shaper.js.map +1 -0
  91. package/dist/core/analyzer/dependency-graph.d.ts +179 -0
  92. package/dist/core/analyzer/dependency-graph.d.ts.map +1 -0
  93. package/dist/core/analyzer/dependency-graph.js +574 -0
  94. package/dist/core/analyzer/dependency-graph.js.map +1 -0
  95. package/dist/core/analyzer/duplicate-detector.d.ts +52 -0
  96. package/dist/core/analyzer/duplicate-detector.d.ts.map +1 -0
  97. package/dist/core/analyzer/duplicate-detector.js +279 -0
  98. package/dist/core/analyzer/duplicate-detector.js.map +1 -0
  99. package/dist/core/analyzer/embedding-service.d.ts +50 -0
  100. package/dist/core/analyzer/embedding-service.d.ts.map +1 -0
  101. package/dist/core/analyzer/embedding-service.js +104 -0
  102. package/dist/core/analyzer/embedding-service.js.map +1 -0
  103. package/dist/core/analyzer/file-walker.d.ts +78 -0
  104. package/dist/core/analyzer/file-walker.d.ts.map +1 -0
  105. package/dist/core/analyzer/file-walker.js +531 -0
  106. package/dist/core/analyzer/file-walker.js.map +1 -0
  107. package/dist/core/analyzer/import-parser.d.ts +91 -0
  108. package/dist/core/analyzer/import-parser.d.ts.map +1 -0
  109. package/dist/core/analyzer/import-parser.js +720 -0
  110. package/dist/core/analyzer/import-parser.js.map +1 -0
  111. package/dist/core/analyzer/index.d.ts +10 -0
  112. package/dist/core/analyzer/index.d.ts.map +1 -0
  113. package/dist/core/analyzer/index.js +10 -0
  114. package/dist/core/analyzer/index.js.map +1 -0
  115. package/dist/core/analyzer/refactor-analyzer.d.ts +80 -0
  116. package/dist/core/analyzer/refactor-analyzer.d.ts.map +1 -0
  117. package/dist/core/analyzer/refactor-analyzer.js +339 -0
  118. package/dist/core/analyzer/refactor-analyzer.js.map +1 -0
  119. package/dist/core/analyzer/repository-mapper.d.ts +150 -0
  120. package/dist/core/analyzer/repository-mapper.d.ts.map +1 -0
  121. package/dist/core/analyzer/repository-mapper.js +731 -0
  122. package/dist/core/analyzer/repository-mapper.js.map +1 -0
  123. package/dist/core/analyzer/signature-extractor.d.ts +31 -0
  124. package/dist/core/analyzer/signature-extractor.d.ts.map +1 -0
  125. package/dist/core/analyzer/signature-extractor.js +387 -0
  126. package/dist/core/analyzer/signature-extractor.js.map +1 -0
  127. package/dist/core/analyzer/significance-scorer.d.ts +79 -0
  128. package/dist/core/analyzer/significance-scorer.d.ts.map +1 -0
  129. package/dist/core/analyzer/significance-scorer.js +407 -0
  130. package/dist/core/analyzer/significance-scorer.js.map +1 -0
  131. package/dist/core/analyzer/subgraph-extractor.d.ts +43 -0
  132. package/dist/core/analyzer/subgraph-extractor.d.ts.map +1 -0
  133. package/dist/core/analyzer/subgraph-extractor.js +129 -0
  134. package/dist/core/analyzer/subgraph-extractor.js.map +1 -0
  135. package/dist/core/analyzer/vector-index.d.ts +63 -0
  136. package/dist/core/analyzer/vector-index.d.ts.map +1 -0
  137. package/dist/core/analyzer/vector-index.js +169 -0
  138. package/dist/core/analyzer/vector-index.js.map +1 -0
  139. package/dist/core/drift/drift-detector.d.ts +102 -0
  140. package/dist/core/drift/drift-detector.d.ts.map +1 -0
  141. package/dist/core/drift/drift-detector.js +597 -0
  142. package/dist/core/drift/drift-detector.js.map +1 -0
  143. package/dist/core/drift/git-diff.d.ts +55 -0
  144. package/dist/core/drift/git-diff.d.ts.map +1 -0
  145. package/dist/core/drift/git-diff.js +356 -0
  146. package/dist/core/drift/git-diff.js.map +1 -0
  147. package/dist/core/drift/index.d.ts +12 -0
  148. package/dist/core/drift/index.d.ts.map +1 -0
  149. package/dist/core/drift/index.js +9 -0
  150. package/dist/core/drift/index.js.map +1 -0
  151. package/dist/core/drift/spec-mapper.d.ts +73 -0
  152. package/dist/core/drift/spec-mapper.d.ts.map +1 -0
  153. package/dist/core/drift/spec-mapper.js +353 -0
  154. package/dist/core/drift/spec-mapper.js.map +1 -0
  155. package/dist/core/generator/adr-generator.d.ts +32 -0
  156. package/dist/core/generator/adr-generator.d.ts.map +1 -0
  157. package/dist/core/generator/adr-generator.js +192 -0
  158. package/dist/core/generator/adr-generator.js.map +1 -0
  159. package/dist/core/generator/index.d.ts +9 -0
  160. package/dist/core/generator/index.d.ts.map +1 -0
  161. package/dist/core/generator/index.js +12 -0
  162. package/dist/core/generator/index.js.map +1 -0
  163. package/dist/core/generator/mapping-generator.d.ts +54 -0
  164. package/dist/core/generator/mapping-generator.d.ts.map +1 -0
  165. package/dist/core/generator/mapping-generator.js +239 -0
  166. package/dist/core/generator/mapping-generator.js.map +1 -0
  167. package/dist/core/generator/openspec-compat.d.ts +160 -0
  168. package/dist/core/generator/openspec-compat.d.ts.map +1 -0
  169. package/dist/core/generator/openspec-compat.js +523 -0
  170. package/dist/core/generator/openspec-compat.js.map +1 -0
  171. package/dist/core/generator/openspec-format-generator.d.ts +111 -0
  172. package/dist/core/generator/openspec-format-generator.d.ts.map +1 -0
  173. package/dist/core/generator/openspec-format-generator.js +817 -0
  174. package/dist/core/generator/openspec-format-generator.js.map +1 -0
  175. package/dist/core/generator/openspec-writer.d.ts +131 -0
  176. package/dist/core/generator/openspec-writer.d.ts.map +1 -0
  177. package/dist/core/generator/openspec-writer.js +379 -0
  178. package/dist/core/generator/openspec-writer.js.map +1 -0
  179. package/dist/core/generator/prompts.d.ts +35 -0
  180. package/dist/core/generator/prompts.d.ts.map +1 -0
  181. package/dist/core/generator/prompts.js +212 -0
  182. package/dist/core/generator/prompts.js.map +1 -0
  183. package/dist/core/generator/spec-pipeline.d.ts +94 -0
  184. package/dist/core/generator/spec-pipeline.d.ts.map +1 -0
  185. package/dist/core/generator/spec-pipeline.js +474 -0
  186. package/dist/core/generator/spec-pipeline.js.map +1 -0
  187. package/dist/core/generator/stages/stage1-survey.d.ts +19 -0
  188. package/dist/core/generator/stages/stage1-survey.d.ts.map +1 -0
  189. package/dist/core/generator/stages/stage1-survey.js +105 -0
  190. package/dist/core/generator/stages/stage1-survey.js.map +1 -0
  191. package/dist/core/generator/stages/stage2-entities.d.ts +11 -0
  192. package/dist/core/generator/stages/stage2-entities.d.ts.map +1 -0
  193. package/dist/core/generator/stages/stage2-entities.js +67 -0
  194. package/dist/core/generator/stages/stage2-entities.js.map +1 -0
  195. package/dist/core/generator/stages/stage3-services.d.ts +11 -0
  196. package/dist/core/generator/stages/stage3-services.d.ts.map +1 -0
  197. package/dist/core/generator/stages/stage3-services.js +75 -0
  198. package/dist/core/generator/stages/stage3-services.js.map +1 -0
  199. package/dist/core/generator/stages/stage4-api.d.ts +11 -0
  200. package/dist/core/generator/stages/stage4-api.d.ts.map +1 -0
  201. package/dist/core/generator/stages/stage4-api.js +65 -0
  202. package/dist/core/generator/stages/stage4-api.js.map +1 -0
  203. package/dist/core/generator/stages/stage5-architecture.d.ts +10 -0
  204. package/dist/core/generator/stages/stage5-architecture.d.ts.map +1 -0
  205. package/dist/core/generator/stages/stage5-architecture.js +62 -0
  206. package/dist/core/generator/stages/stage5-architecture.js.map +1 -0
  207. package/dist/core/generator/stages/stage6-adr.d.ts +8 -0
  208. package/dist/core/generator/stages/stage6-adr.d.ts.map +1 -0
  209. package/dist/core/generator/stages/stage6-adr.js +41 -0
  210. package/dist/core/generator/stages/stage6-adr.js.map +1 -0
  211. package/dist/core/services/chat-agent.d.ts +45 -0
  212. package/dist/core/services/chat-agent.d.ts.map +1 -0
  213. package/dist/core/services/chat-agent.js +310 -0
  214. package/dist/core/services/chat-agent.js.map +1 -0
  215. package/dist/core/services/chat-tools.d.ts +32 -0
  216. package/dist/core/services/chat-tools.d.ts.map +1 -0
  217. package/dist/core/services/chat-tools.js +270 -0
  218. package/dist/core/services/chat-tools.js.map +1 -0
  219. package/dist/core/services/config-manager.d.ts +61 -0
  220. package/dist/core/services/config-manager.d.ts.map +1 -0
  221. package/dist/core/services/config-manager.js +143 -0
  222. package/dist/core/services/config-manager.js.map +1 -0
  223. package/dist/core/services/gitignore-manager.d.ts +29 -0
  224. package/dist/core/services/gitignore-manager.d.ts.map +1 -0
  225. package/dist/core/services/gitignore-manager.js +106 -0
  226. package/dist/core/services/gitignore-manager.js.map +1 -0
  227. package/dist/core/services/index.d.ts +8 -0
  228. package/dist/core/services/index.d.ts.map +1 -0
  229. package/dist/core/services/index.js +8 -0
  230. package/dist/core/services/index.js.map +1 -0
  231. package/dist/core/services/llm-service.d.ts +336 -0
  232. package/dist/core/services/llm-service.d.ts.map +1 -0
  233. package/dist/core/services/llm-service.js +1155 -0
  234. package/dist/core/services/llm-service.js.map +1 -0
  235. package/dist/core/services/mcp-handlers/analysis.d.ts +42 -0
  236. package/dist/core/services/mcp-handlers/analysis.d.ts.map +1 -0
  237. package/dist/core/services/mcp-handlers/analysis.js +300 -0
  238. package/dist/core/services/mcp-handlers/analysis.js.map +1 -0
  239. package/dist/core/services/mcp-handlers/graph.d.ts +65 -0
  240. package/dist/core/services/mcp-handlers/graph.d.ts.map +1 -0
  241. package/dist/core/services/mcp-handlers/graph.js +509 -0
  242. package/dist/core/services/mcp-handlers/graph.js.map +1 -0
  243. package/dist/core/services/mcp-handlers/semantic.d.ts +38 -0
  244. package/dist/core/services/mcp-handlers/semantic.d.ts.map +1 -0
  245. package/dist/core/services/mcp-handlers/semantic.js +172 -0
  246. package/dist/core/services/mcp-handlers/semantic.js.map +1 -0
  247. package/dist/core/services/mcp-handlers/utils.d.ts +21 -0
  248. package/dist/core/services/mcp-handlers/utils.d.ts.map +1 -0
  249. package/dist/core/services/mcp-handlers/utils.js +62 -0
  250. package/dist/core/services/mcp-handlers/utils.js.map +1 -0
  251. package/dist/core/services/project-detector.d.ts +32 -0
  252. package/dist/core/services/project-detector.d.ts.map +1 -0
  253. package/dist/core/services/project-detector.js +111 -0
  254. package/dist/core/services/project-detector.js.map +1 -0
  255. package/dist/core/verifier/index.d.ts +5 -0
  256. package/dist/core/verifier/index.d.ts.map +1 -0
  257. package/dist/core/verifier/index.js +5 -0
  258. package/dist/core/verifier/index.js.map +1 -0
  259. package/dist/core/verifier/verification-engine.d.ts +226 -0
  260. package/dist/core/verifier/verification-engine.d.ts.map +1 -0
  261. package/dist/core/verifier/verification-engine.js +681 -0
  262. package/dist/core/verifier/verification-engine.js.map +1 -0
  263. package/dist/types/index.d.ts +252 -0
  264. package/dist/types/index.d.ts.map +1 -0
  265. package/dist/types/index.js +5 -0
  266. package/dist/types/index.js.map +1 -0
  267. package/dist/types/pipeline.d.ts +148 -0
  268. package/dist/types/pipeline.d.ts.map +1 -0
  269. package/dist/types/pipeline.js +5 -0
  270. package/dist/types/pipeline.js.map +1 -0
  271. package/dist/utils/errors.d.ts +51 -0
  272. package/dist/utils/errors.d.ts.map +1 -0
  273. package/dist/utils/errors.js +128 -0
  274. package/dist/utils/errors.js.map +1 -0
  275. package/dist/utils/logger.d.ts +149 -0
  276. package/dist/utils/logger.d.ts.map +1 -0
  277. package/dist/utils/logger.js +331 -0
  278. package/dist/utils/logger.js.map +1 -0
  279. package/dist/utils/progress.d.ts +142 -0
  280. package/dist/utils/progress.d.ts.map +1 -0
  281. package/dist/utils/progress.js +280 -0
  282. package/dist/utils/progress.js.map +1 -0
  283. package/dist/utils/prompts.d.ts +53 -0
  284. package/dist/utils/prompts.d.ts.map +1 -0
  285. package/dist/utils/prompts.js +199 -0
  286. package/dist/utils/prompts.js.map +1 -0
  287. package/dist/utils/shutdown.d.ts +89 -0
  288. package/dist/utils/shutdown.d.ts.map +1 -0
  289. package/dist/utils/shutdown.js +237 -0
  290. package/dist/utils/shutdown.js.map +1 -0
  291. package/package.json +114 -0
  292. package/src/viewer/InteractiveGraphViewer.jsx +1486 -0
  293. package/src/viewer/app/index.html +17 -0
  294. package/src/viewer/app/main.jsx +13 -0
  295. package/src/viewer/components/ArchitectureView.jsx +177 -0
  296. package/src/viewer/components/ChatPanel.jsx +448 -0
  297. package/src/viewer/components/ClusterGraph.jsx +441 -0
  298. package/src/viewer/components/FilterBar.jsx +179 -0
  299. package/src/viewer/components/FlatGraph.jsx +275 -0
  300. package/src/viewer/components/MicroComponents.jsx +83 -0
  301. package/src/viewer/hooks/usePanZoom.js +79 -0
  302. package/src/viewer/utils/constants.js +47 -0
  303. package/src/viewer/utils/graph-helpers.js +291 -0
@@ -0,0 +1,291 @@
1
+ import { CLUSTER_PALETTE } from './constants.js';
2
+
3
+ export function parseSpecRequirements(mdText) {
4
+ const reqs = {};
5
+ if (!mdText) return reqs;
6
+ const sections = mdText.split(/^#{3,4}\s+Requirement:\s*/m);
7
+ for (let i = 1; i < sections.length; i++) {
8
+ const lines = sections[i].split('\n');
9
+ const rawTitle = lines[0].trim();
10
+ if (!rawTitle) continue;
11
+ const body = lines.slice(1).join('\n').trim();
12
+ reqs[rawTitle] = { title: rawTitle, body };
13
+ }
14
+ return reqs;
15
+ }
16
+
17
+ export function buildMappingIndex(mappingJson) {
18
+ const index = {};
19
+ if (!mappingJson?.mappings) return index;
20
+ for (const m of mappingJson.mappings) {
21
+ for (const fn of m.functions || []) {
22
+ const key = fn.file.replace(/\\/g, '/');
23
+ if (!index[key]) index[key] = [];
24
+ index[key].push({
25
+ requirement: m.requirement,
26
+ service: m.service,
27
+ domain: m.domain,
28
+ specFile: m.specFile,
29
+ fnName: fn.name,
30
+ fnLine: fn.line,
31
+ confidence: fn.confidence,
32
+ });
33
+ }
34
+ }
35
+ return index;
36
+ }
37
+
38
+ export function normalizePath(p) {
39
+ return (p || '').replace(/\\/g, '/').replace(/^\/+/, '');
40
+ }
41
+
42
+ export function parseGraph(raw) {
43
+ const clusterByNode = {};
44
+ (raw.clusters || []).forEach((cl, ci) => {
45
+ cl.files.forEach((fid) => {
46
+ clusterByNode[fid] = {
47
+ name: cl.name,
48
+ index: ci,
49
+ id: cl.id,
50
+ color: CLUSTER_PALETTE[ci % CLUSTER_PALETTE.length],
51
+ };
52
+ });
53
+ });
54
+
55
+ const nodes = (raw.nodes || []).map((n) => ({
56
+ id: n.id,
57
+ label: n.file.name,
58
+ path: n.file.path,
59
+ ext: n.file.extension,
60
+ dir: n.file.directory,
61
+ lines: n.file.lines,
62
+ size: n.file.size,
63
+ isEntry: n.isEntryPoint,
64
+ isConfig: n.isConfig,
65
+ isTest: n.isTest,
66
+ score: n.importanceScore ?? 0,
67
+ cluster: clusterByNode[n.id] || { name: '?', index: 0, id: 'unknown', color: '#555' },
68
+ exports: n.exports || [],
69
+ tags: n.tags || [],
70
+ metrics: n.metrics || {},
71
+ refactor: null,
72
+ }));
73
+
74
+ const edges = (raw.edges || []).map((e) => ({
75
+ id: `${e.source}->${e.target}`,
76
+ source: e.source,
77
+ target: e.target,
78
+ isType: e.isTypeOnly || false,
79
+ importedNames: e.importedNames || [],
80
+ }));
81
+
82
+ const clusters = (raw.clusters || []).map((cl, ci) => ({
83
+ id: cl.id,
84
+ name: cl.name,
85
+ files: cl.files,
86
+ color: CLUSTER_PALETTE[ci % CLUSTER_PALETTE.length],
87
+ }));
88
+
89
+ return {
90
+ nodes,
91
+ edges,
92
+ clusters,
93
+ statistics: raw.statistics || {},
94
+ rankings: raw.rankings || {},
95
+ };
96
+ }
97
+
98
+ export function enrichGraphWithRefactors(graph, refReport) {
99
+ if (!graph || !refReport || !refReport.priorities) return graph;
100
+
101
+ const byFile = new Map();
102
+ refReport.priorities.forEach((entry) => {
103
+ const list = byFile.get(entry.file) || [];
104
+ list.push(entry);
105
+ byFile.set(entry.file, list);
106
+ });
107
+
108
+ const nodes = graph.nodes.map((n) => {
109
+ const entries = byFile.get(n.path) || [];
110
+ if (!entries.length) return { ...n, refactor: null };
111
+
112
+ let maxPriority = 0;
113
+ const issuesSet = new Set();
114
+ entries.forEach((e) => {
115
+ if (typeof e.priorityScore === 'number') {
116
+ maxPriority = Math.max(maxPriority, e.priorityScore);
117
+ }
118
+ (e.issues || []).forEach((iss) => issuesSet.add(iss));
119
+ });
120
+
121
+ return {
122
+ ...n,
123
+ refactor: {
124
+ functions: entries.length,
125
+ maxPriority,
126
+ issues: Array.from(issuesSet),
127
+ },
128
+ };
129
+ });
130
+
131
+ return {
132
+ ...graph,
133
+ nodes,
134
+ refactorStats: refReport.stats || null,
135
+ };
136
+ }
137
+
138
+ export function computeBlast(edges, nodeId) {
139
+ const affected = new Set();
140
+ const q = [nodeId];
141
+ while (q.length) {
142
+ const cur = q.shift();
143
+ edges.forEach((e) => {
144
+ if (e.source === cur && !affected.has(e.target)) {
145
+ affected.add(e.target);
146
+ q.push(e.target);
147
+ }
148
+ });
149
+ }
150
+ return [...affected];
151
+ }
152
+
153
+ export function computeLayout(nodes, edges, W = 900, H = 540) {
154
+ if (!nodes.length) return {};
155
+ const pos = {};
156
+
157
+ const byCluster = {};
158
+ nodes.forEach((n) => {
159
+ if (!byCluster[n.cluster.id]) byCluster[n.cluster.id] = [];
160
+ byCluster[n.cluster.id].push(n.id);
161
+ });
162
+ const clIds = Object.keys(byCluster);
163
+ clIds.forEach((cid, ci) => {
164
+ const angle = (ci / clIds.length) * Math.PI * 2 - Math.PI / 2;
165
+ const cx = W / 2 + Math.cos(angle) * W * 0.33;
166
+ const cy = H / 2 + Math.sin(angle) * H * 0.3;
167
+ byCluster[cid].forEach((nid, mi) => {
168
+ const a2 = (mi / Math.max(byCluster[cid].length, 1)) * Math.PI * 2;
169
+ const r = Math.min(60, 13 * Math.sqrt(byCluster[cid].length));
170
+ pos[nid] = { x: cx + Math.cos(a2) * r, y: cy + Math.sin(a2) * r };
171
+ });
172
+ });
173
+
174
+ const k = 55;
175
+ for (let iter = 0; iter < 80; iter++) {
176
+ const disp = {};
177
+ nodes.forEach((n) => {
178
+ disp[n.id] = { x: 0, y: 0 };
179
+ });
180
+
181
+ for (let i = 0; i < nodes.length; i++) {
182
+ for (let j = i + 1; j < nodes.length; j++) {
183
+ const a = nodes[i],
184
+ b = nodes[j];
185
+ const dx = pos[a.id].x - pos[b.id].x;
186
+ const dy = pos[a.id].y - pos[b.id].y;
187
+ const d = Math.max(Math.sqrt(dx * dx + dy * dy), 0.01);
188
+ const f = (k * k) / d;
189
+ disp[a.id].x += (dx / d) * f;
190
+ disp[a.id].y += (dy / d) * f;
191
+ disp[b.id].x -= (dx / d) * f;
192
+ disp[b.id].y -= (dy / d) * f;
193
+ }
194
+ }
195
+
196
+ edges.forEach((e) => {
197
+ if (!pos[e.source] || !pos[e.target]) return;
198
+ const dx = pos[e.source].x - pos[e.target].x;
199
+ const dy = pos[e.source].y - pos[e.target].y;
200
+ const d = Math.max(Math.sqrt(dx * dx + dy * dy), 0.01);
201
+ const f = (d * d) / (k * (e.isType ? 2 : 1));
202
+ disp[e.source].x -= (dx / d) * f;
203
+ disp[e.source].y -= (dy / d) * f;
204
+ disp[e.target].x += (dx / d) * f;
205
+ disp[e.target].y += (dy / d) * f;
206
+ });
207
+
208
+ const temp = k * Math.max(0.05, 1 - iter / 80) * 0.5;
209
+ nodes.forEach((n) => {
210
+ const d = Math.sqrt(disp[n.id].x ** 2 + disp[n.id].y ** 2);
211
+ if (d > 0) {
212
+ pos[n.id].x += (disp[n.id].x / d) * Math.min(d, temp);
213
+ pos[n.id].y += (disp[n.id].y / d) * Math.min(d, temp);
214
+ }
215
+ pos[n.id].x = Math.max(36, Math.min(W - 36, pos[n.id].x));
216
+ pos[n.id].y = Math.max(36, Math.min(H - 36, pos[n.id].y));
217
+ });
218
+ }
219
+ return pos;
220
+ }
221
+
222
+ export function computeClusterLayout(clusters, W = 900, H = 540) {
223
+ const pos = {};
224
+ clusters.forEach((cl, i) => {
225
+ const angle = (i / clusters.length) * Math.PI * 2 - Math.PI / 2;
226
+ pos[cl.id] = {
227
+ x: W / 2 + Math.cos(angle) * W * 0.34,
228
+ y: H / 2 + Math.sin(angle) * H * 0.32,
229
+ };
230
+ });
231
+ return pos;
232
+ }
233
+
234
+ export function inferClusterRole(entryCount, hubCount, fileCount) {
235
+ if (entryCount > fileCount * 0.5) return 'entry_layer';
236
+ if (hubCount > 0 && entryCount > 0) return 'orchestrator';
237
+ if (hubCount > 0) return 'core_utilities';
238
+ if (entryCount > 0) return 'api_layer';
239
+ return 'internal';
240
+ }
241
+
242
+ export function computeArchOverview(graph, llmCtx) {
243
+ if (!graph) return null;
244
+
245
+ const hubFiles = new Set((llmCtx?.callGraph?.hubFunctions ?? []).map(h => h.filePath));
246
+ const entryFiles = new Set((llmCtx?.callGraph?.entryPoints ?? []).map(e => e.filePath));
247
+
248
+ const clusterOfNode = {};
249
+ (graph.nodes ?? []).forEach(n => {
250
+ if (n.cluster?.id) clusterOfNode[n.id] = n.cluster.id;
251
+ const rel = n.path?.replace(/^\/+/, '') ?? '';
252
+ if (rel && n.cluster?.id) clusterOfNode[rel] = n.cluster.id;
253
+ });
254
+
255
+ const clusterEdges = {};
256
+ (graph.edges ?? []).forEach(e => {
257
+ const from = clusterOfNode[e.source];
258
+ const to = clusterOfNode[e.target];
259
+ if (from && to && from !== to) {
260
+ if (!clusterEdges[from]) clusterEdges[from] = new Set();
261
+ clusterEdges[from].add(to);
262
+ }
263
+ });
264
+
265
+ const clusters = (graph.clusters ?? []).map(cl => {
266
+ const clNodes = (graph.nodes ?? []).filter(n => n.cluster?.id === cl.id);
267
+ const relPaths = clNodes.map(n => n.path?.replace(/^\/+/, '') ?? '');
268
+ const hubCount = relPaths.filter(p => hubFiles.has(p)).length;
269
+ const entryCount = relPaths.filter(p => entryFiles.has(p)).length;
270
+ const role = inferClusterRole(entryCount, hubCount, clNodes.length || cl.files?.length || 1);
271
+ const dependsOn = [...(clusterEdges[cl.id] ?? [])];
272
+ const keyFiles = relPaths.filter(p => hubFiles.has(p) || entryFiles.has(p)).slice(0, 5);
273
+ return { id: cl.id, name: cl.name ?? cl.id, fileCount: clNodes.length || cl.files?.length || 0, role, entryPointCount: entryCount, hubCount, dependsOn, keyFiles, color: cl.color };
274
+ }).sort((a, b) => b.fileCount - a.fileCount);
275
+
276
+ const globalEntryPoints = (llmCtx?.callGraph?.entryPoints ?? []).slice(0, 20).map(n => ({ name: n.name, file: n.filePath, language: n.language }));
277
+ const criticalHubs = (llmCtx?.callGraph?.hubFunctions ?? []).slice(0, 10).map(n => ({ name: n.name, file: n.filePath, fanIn: n.fanIn, fanOut: n.fanOut }));
278
+
279
+ return {
280
+ summary: {
281
+ totalFiles: graph.statistics?.nodeCount ?? (graph.nodes?.length ?? 0),
282
+ totalClusters: clusters.length,
283
+ totalEdges: graph.statistics?.edgeCount ?? (graph.edges?.length ?? 0),
284
+ cycles: graph.statistics?.cycleCount ?? 0,
285
+ layerViolations: llmCtx?.callGraph?.layerViolations?.length ?? 0,
286
+ },
287
+ clusters,
288
+ globalEntryPoints,
289
+ criticalHubs,
290
+ };
291
+ }